How do I get the "right" Device ID?

I've been asked more than once how to go about getting the “right” Device ID from managed code.  There's a myth floating around (to which, for a short time, I myself subscribed) that a device has multiple Device IDs, or that there's some trick to getting the one “true” Device ID.

Getting the device ID isn't particularly difficult.  There are a number of samples floating around for retrieving the ID from native and managed code (my own modest offering can be found here).  And, believe it or not, there is only one ID, and really only one way to get at it.  Why then all the confusion? 

Windows CE specifies that a Device ID is a 2 part critter, where one part is the Platform ID, and the other part is the Preset ID.  The Platform ID is suppose to be an identifier that uniquely identifies the type of hardware the device is running on.  So, two identical devices should have the same Platform ID.

The Preset ID is suppose to be a number that uniquely identifies a specific unit of a given platform.  So, 2 identical ACME PDAs should have the same Platform ID, but different Preset IDs.  Two unrelated CE Devices might have (unlikely though it may be) the same Preset IDs, but certainly should not have the same Platform IDs.

On Windows CE, the Platform ID and Preset ID can be any length.  The Pocket PC standards say that the 2 IDs together will have a length of 16 bytes, so that the DeviceID can be treated as a Guid.  So, let's talk about the Gotchas.

Gotcha #1
Often times, when someone attempts to retrieve the DeviceID, they only pay attention to either the Platform ID or the Preset ID.  However, neither ID is, by itself, unique.  It's only the combination of IDs that is guaranteed to be unique.

Gotcha #2
Alright, the DeviceID has a length of 16 bytes on PPC, so it can be treated as a GUID.  However, there are a number of differing definitions that describe exactly what is inside a GUID.  Three common definitions are:

    1. byte[16];
    2. int a;
      short b;
      short c;
      byte[8] d;
    3. DWORD a;
      DWORD b;
      DWORD c;
      DWORD d;

All of these pseudo-code definitions are 16 bytes.  However, the same data will not necessary be represented the same way in all 3 cases.  It just so happens that most platforms are Little-Endian, storing the lowest order byte before the higher order bytes.  What does that mean?  Well, a DWORD with the value of 1000 (0x00000E38) will actually be stored in memory as 0x38, 0x0E, 0x00, 0x00.  Therefore, someone who treats the 4-byte DWORD as a DWORD may get one sequence of bytes whereas someone treating it as a byte[] may get a different sequence of bytes.

As a real world example, I used 2 different utilities to get the Device ID from my iPaq 3760, and got the following results:

Utility 1: FE0CEA0D-000C-0116-0800-57454D325750
Utility 2: FE0CEA0D-0116-000C-4557-00085057324D

You may notice, if you're the kind of person that likes to rearrange things (and, gee, who isn't?) that Utility 2 gives a DeviceID that is simply a jumble of the ID given by Utility 1.

Gotcha #3
Some older PPC devices have a slightly different behavior when it comes to retrieving the ID.  The method we all know and love for retrieving the ID (KernelIoControl, IOCTL_HAL_GET_DEVICEID, DEVICE_ID Structure, mutter magic incantation) doesn't work the same on some older devices.

Typically you create a DEVICE_ID structure, which is actually just a large buffer which we pretend is a structure, set its first field to its size, and pass it and its size in to KernelIoControl.  Most of the time “viola”, you get a DeviceID (or the Kernel says it needs a bigger buffer).

Unfortunately, the mechanism is broken on some older devices.  In fact, on these older devices, if you claim the size of the buffer is anything other than 16 bytes (the size of a GUID), the method fails and gives you nothing.  Do not despair!  Passing in 16 as the size of the buffer will return you the entire 16 byte Device ID in the buffer, which you can then use as returned.

Gotcha #4
Finally, there is the matter of emulators.  Device IDs are one of those things that Windows CE specifies how it should work, and then it's up to the manufacturer of the device to actually implement.  So, of course, it's not always available as you would like.  In particular, a number of device emulators don't support any form of Device ID retrieval. 

--- jeh
This post is provided “As Is”, with no warranties, and confers no rights.