Device information in Windows 8 store apps

Our Sticker Tales game tracks var­i­ous activ­i­ties via Google Ana­lyt­ics using code that grew into our CSharp­An­a­lyt­ics open source project.

But we also want to add some sys­tem met­rics that could help us answer other questions:

When is it time to exploit fea­tures of an OS update?
Do peo­ple on tablets play longer than peo­ple on laptops?
How long do var­i­ous timed activ­i­ties take by CPU?
Does not hav­ing a phys­i­cal key­board affect pur­chase flow completion?
To do this we want to record:

Proces­sor architecture
Device man­u­fac­turer, model and form fac­tor (category)
Win­dows ver­sion number
On Win­dows Phone and .NET this infor­ma­tion is eas­ily avail­able but in Win­dows Store apps it is not. Microsoft have made this dif­fi­cult because your appli­ca­tion should not change it’s behav­ior based on this infor­ma­tion.

The fol­low­ing code uses the PnPOb­ject API to best-guess these things. It is not bullet-proof and could eas­ily fail on machines with cus­tom HAL dri­vers (I haven’t seen one of those in years) or on other lan­guage edi­tions of Win­dows (not yet tried).

It is good enough in my opin­ion for ana­lyt­ics, log­ging or trou­bleshoot­ing and for noth­ing more.

To use it simply:

var windowsVersion = await SystemInfoEstimate.GetWindowsVersionAsync();
var processor = await SystemInfoEstimate.GetProcessorArchitectureAsync();
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Devices.Enumeration.Pnp;
using Windows.System;
 
public class SystemInfoEstimate
{
  const string ItemNameKey = "System.ItemNameDisplay";
  const string ModelNameKey = "System.Devices.ModelName";
  const string ManufacturerKey = "System.Devices.Manufacturer";
  const string DeviceClassKey = "{A45C254E-DF1C-4EFD-8020-67D146A850E0},10";
  const string PrimaryCategoryKey = "{78C34FC8-104A-4ACA-9EA4-524D52996E57},97";
  const string DeviceDriverVersionKey = "{A8B865DD-2E3D-4094-AD97-E593A70C75D6},3";
  const string RootContainer = "{00000000-0000-0000-FFFF-FFFFFFFFFFFF}";
  const string RootQuery = "System.Devices.ContainerId:=\"" + RootContainer + "\"";
  const string HalDeviceClass = "4d36e966-e325-11ce-bfc1-08002be10318";
 
  public static async Task<ProcessorArchitecture> GetProcessorArchitectureAsync()
  {
    var halDevice = await GetHalDevice(ItemNameKey);
    if (halDevice != null && halDevice.Properties[ItemNameKey] != null) {
      var halName = halDevice.Properties[ItemNameKey].ToString();
      if (halName.Contains("x64")) return ProcessorArchitecture.X64;
      if (halName.Contains("ARM")) return ProcessorArchitecture.Arm;
      return ProcessorArchitecture.X86;
    }
    return ProcessorArchitecture.Unknown;
  }
 
  public static Task<string> GetDeviceManufacturerAsync()
  {
    return GetRootDeviceInfoAsync(ManufacturerKey);
  }
 
  public static Task<string> GetDeviceModelAsync()
  {
    return GetRootDeviceInfoAsync(ModelNameKey);
  }
 
  public static Task<string> GetDeviceCategoryAsync()
  {
    return GetRootDeviceInfoAsync(PrimaryCategoryKey);
  }
 
  public static async Task<string> GetWindowsVersionAsync()
  {
    // There is no good place to get this.
    // The HAL driver version number should work unless you're using a custom HAL... 
    var hal = await GetHalDevice(DeviceDriverVersionKey);
    if (hal == null || !hal.Properties.ContainsKey(DeviceDriverVersionKey))
      return null;
 
    var versionParts = hal.Properties[DeviceDriverVersionKey].ToString().Split('.');
    return string.Join(".", versionParts.Take(2).ToArray());
  }
 
  private static async Task<string> GetRootDeviceInfoAsync(string propertyKey)
  {
    var pnp = await PnpObject.CreateFromIdAsync(PnpObjectType.DeviceContainer,
              RootContainer, new[] { propertyKey });
    return (string)pnp.Properties[propertyKey];
  }
 
  private static async Task<PnpObject> GetHalDevice(params string[] properties)
  {
    var actualProperties = properties.Concat(new[] { DeviceClassKey });
    var rootDevices = await PnpObject.FindAllAsync(PnpObjectType.Device, 
        actualProperties, RootQuery);
 
    foreach (var rootDevice in rootDevices.Where(d => d.Properties != null && d.Properties.Any())) {
        var lastProperty = rootDevice.Properties.Last();
        if (lastProperty.Value != null)
           if (lastProperty.Value.ToString().Equals(HalDeviceClass))
              return rootDevice;
    }
    return null;
  }
}

猜你喜欢

转载自baron-unsafe.iteye.com/blog/1864621