Getting unique device ID in Win8 app - windows

I need to get an unique device identifier in Windows 8 application. I have few applications and I need to determine device ID that have one or more apps installed (e.g. a bonus for a gamer installing other game in the series). Using following methods provides me with per-app IDs which won't tell me that device have some other apps installed.
I've tried three different approaches but they all return different UDIDs on the same PC.
1) This was used before, since I needed unique id per app, now I need UDID, so it's predictably doesn't work for me:
GUID g;
std::string ret;
CoCreateGuid(&g);
Platform::Guid pg(g);
std::string udid = WStringToUTF8(pg.ToString()->Data());
2) I've tried EasClienDeviceInformation, which was suggested as a sure thing, but got different results for 2 apps on the same PC:
EasClientDeviceInformation^ info = ref new EasClientDeviceInformation;
ret = WStringToUTF8(info->Id.ToString()->Data());
3) And I've tried the commonly used way to get ASHWID, without any hope and it obviously shown different UDIDs:
auto token = Windows::System::Profile::HardwareIdentification::GetPackageSpecificToken(nullptr);
ret = WStringToUTF8(Windows::Security::Cryptography::CryptographicBuffer::EncodeToBase64String(token->Id)->Data());
_RPT1(_CRT_WARN, "TOKEN UDID IS %s \n", ret.c_str());
I know only about one option and it's to use MAC-address, but I'm not sure if it's a valid option. Users can have a PC where MAC-address could be changed or duplicated (I've heard of batches of chinese network adapters having the same address), or have a device without a network whatsoever (e.g. use a PC without a network adapter and connect to the internet using USB dongles).
So the questions are:
Did I do everything right, or I made a mistake that caused my examples to return wrong UDIDs?
Am I right to assume that MAC-address is the only viable way to get a trutfully unique per-device identifier? I could've been inattentive and missed some obvious way.
Am I wrong in my assumptions of MAC-address identification insecurities like those I've described above?
UPD: I also would like to know the right way for WP8, while we're on it.

Related

A driver has enumerated two child PDO's that returned identical Device ID's

I have a kmdf bus driver PCI\VEN_XXXX&DEV_XXXX that creates two statically enumerated PDOs with serial numbers: 217 and 218; one for each Ethernet port. The PDO hardware id is ROOT\MY_NIC_PORT so I can install a NDIS Miniport driver on them.
The bus driver passes SDV and Verifier; but, on reboot two more PDOs get enumerated. On the next reboot I get a duplicate pdo crash.
The toaster example used the device class guid as part of the hardware id. When I tried that my NIC ports no longer showed up in device manager.
Any debug suggestion or work around idea would be appreciated?
pnpCaps.LockSupported = WdfFalse;
pnpCaps.EjectSupported = WdfTrue;
pnpCaps.Removable = WdfTrue;
pnpCaps.DockDevice = WdfFalse;
pnpCaps.UniqueID = WdfTrue;
pnpCaps.SilentInstall = WdfTrue;
pnpCaps.SurpriseRemovalOK = WdfTrue;
pnpCaps.HardwareDisabled = WdfFalse;
pnpCaps.NoDisplayInUI = WdfFalse;
pnpCaps.Address = SerialNo;
pnpCaps.UINumber = SerialNo;
************************************************************
Driver Verifier detected violation:
A driver has enumerated two child PDO's that returned identical Device
ID's.
CulpritAddress = FFFFF8025ED309C4, DeviceObject1 = FFFFE3882FB2F300,
DeviceObject2 = FFFFE3882EBF88D0.
************************************************************
There are a few versions of the toaster bus sample -- assuming you started with this one, then note that it saves its list of child PDOs in the registry. My guess is that your driver is both loading PDOs from the registry, and trying to dynamically create some too.
Set a breakpoint on your driver's version of Bus_PlugInDevice, and see how often it's getting called. Make sure it's never getting called 2x with the same Instance ID.
To clear up a bit of the naming thing: a device setup class is a GUID that is totally unrelated to its hardware ID. For NICs that want to interoperate with the OS's networking stack, you must use the NET setup class, {4d36e972-e325-11ce-bfc1-08002be10318}. You can put anything you want into your hardware ID. I don't really encourage you to put "ROOT\" in there, since that could be confused with a root-enumerated device (which your devices are not). Instead, you can use "yourcompany_yourdevice\port1" as a hardware ID.
While you're thinking about naming things, there are a few things to note about hardware IDs:
Once you assign a HWID, it's rather difficult to change it in a future driver update, without breaking customers who had already installed your device. So get it right the first time.
Once you assign an Instance ID, don't change or reuse it for the lifetime of the device. Otherwise you'll cause this bugcheck, or cause IP addresses to bounce around / get reset. The OS ultimately uses the Instance ID to figure out which NIC port to bind an IP address to.
Think about what happens if someone plugs 2 of your device into a system. Make sure your Instance ID is unique across all ports. You can do this by encoding into the Instance ID the PCI device serial number (if it has one) or by falling back to the PCI bus:device:function.
Don't lump together different types of hardware under the same hardware ID. For example, if the deluxe version of your device supports checksum offload, but the regular version does not -- you should use 2 different hardware IDs for these two different devices. Otherwise it gets difficult to write a single INF that has keywords for both.

How to scan Bluetooth Low energy (BLE) devices which are available/present?

I am working on a windows phone app that can scan BLE devices. I have implemented the logic which is showing the desired devices.
But the problem is that if I remove those devices or switch them off, even then my application returns their names in scan result. I think it is returning cached result. How I can make sure it will show only those devices which are available/present.
I have tried using the additional properties i.e. System.Devices.Aep.IsPresent etc in scan but they are coming as null in result no matter ble devices available or not.
Here is code snippet I am using -
string[] requestedProperties = new string[] { "System.Devices.Aep.IsPresent"
, "System.Devices.Present"
, "System.Devices.Connected"
, "System.Devices.Paired"
, "System.Devices.Aep.IsConnected"
, "System.Devices.AepContainer.IsPresent"
};
diCollection = await DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(serviceUuid)
, requestedProperties
);
foreach (var diItem in diCollection)
{
Debug.WriteLine("Discovered Device name - " + diItem.Name);
Debug.WriteLine("Discovered Device Additional Properties Below");
foreach (var item in diItem.Properties)
{
Debug.WriteLine("Key-{0} Value-{1}", item.Key, item.Value);
}
}
Here is the Package.appxmanifest capabilities used -
<Capabilities>
<Capability Name="internetClientServer" />
<DeviceCapability Name="bluetooth" />
</Capabilities>
Please help me resolve this small issue. Am I missing something trivial here?
Thanks in advance.
-Jitender
I tried every single one of the properties below with 2 PCs, where both were paired to the Handheld and only one was turned on and a Windows Handheld 8.1.
https://learn.microsoft.com/en-us/windows/uwp/devices-sensors/device-information-properties
The ones needed were AssociationEndpoint related properties, none of which are supported in windows phone 8.1 (even the enumeration is not available) - so basically the api does not provide any way for us to be able to query the connections from cache for whether they are presently available or not.
I tested with every combinations and they do not provide sufficient information (the PC that is turned on is indistinguishable from the one that was not).
The only workaround was to connect to every paired computer on the cache and see if each connection was successful to add this to the list displayed if succeeeded. Every failed connection takes ~4-5 seconds. So this can take some significant amount of delay in showing the list if there are multiple paired computers via in the past. Yet I could not find any other feasible way of checking this, at least this resolves the issue.

How is the guidProduct field of DIDEVICEINSTANCE generated

How does DirectInput generate the GUID for the guidProduct field in DIDEVICEINSTANCE? The documentation reads:
guidProduct
Unique identifier for the product. This identifier is established by the manufacturer of the device.
I am searching for a way to retrieve or synthesize the product GUID for a joystick without using DirectInput. I have successfully used RawInput to retrieve the device path and class GUID, but I have not yet found a way to retrieve the product GUID using RawInput and/or SetupDi* functions.
While searching, I noticed that MAKELONG(VID, PID) == guidProduct.Data1, which makes me hopeful that there is way to do what I want (DirectInput somehow does it, after all.)
Questions:
Is there an API to retrieve the product GUID for an HID (esp. joystick) device?
If not, does anyone know how DirectInput synthesizes this field? (The first fields combines VID and PID. What about the rest?)
Edit:
By hacking around the guidProduct field, I came across an interesting discovery. The product GUID for the P880 USB gamepad has the following format:
010906a3-0000-0000-0000-504944564944
The first 4 bytes are quite evidently the PID and VID for the controller. The last part of the GUID is common for all HID controllers in my possession. After a while it dawned on me - they are ASCII characters! The translation is:
010906a3-0000-0000-0000-504944564944
010906a3-0000-0000-0000- P I D V I D
PID_VID_-0000-0000-0000-'P I D"V I D'
I have verified this using the SDL2 game controller database, and it appears to hold! Of course, this does not cover bluetooth devices (such as the OUYA controller), which is only a minor issue for now.
Does anyone know how guidProduct is composed for bluetooth devices?

Windows HID Device Name Format

There are various ways to retrieve the Windows "Device Name" of a HID device, GetRawInputDeviceInfo with RIDI_DEVICENAME being one way to do it.
Given the example name:
\?\HID#VID_FEED&PID_DEAD#6&3559c8ea&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
I'm wondering if there is any documentation whatsoever on what is what in this string?
\?\HID#VID_AAAA&PID_BBBB#C&DDDDDD&E&FFFF#{GUID}
So the obvious ones are A(VID), B(PID) and the GUID on the end. What I'm wondering is what EXACTLY are C, D, E and F?
It seems that C and D are unique even if you plug in two of the exact same HID devices which is great for my problem, but I'd feel more comfortable if I could know exactly how this is determined on a per OS basis, or at least that it follows some known format.
I have been googling like a madman trying to figure this out, am I missing something obvious?
Thanks in advance
According to a similar MSDN post, the value represents a unique device instance ID:
the device instance ID is unique and constant for the physical
location the device is plugged into, but it is also opaque and should
not be parsed. that means it can be used for string comparison, but
not for interpretation.
It is actually device interface instance id (symbolic link name). And yes, its unique and persists across system restart. Some details also here.
You can use CM_Get_Device_Interface_Property or SetupDiGetDeviceInterfaceProperty on interface instance id with DEVPKEY_Device_InstanceId to get device instance id (one device can have multiple interfaces).
In your example - you have a HID device. Its device id format is described here.
Info on general USB devices id format is here.
After you have device instance id you can use CM_Get_DevNode_Property or SetupDiGetDeviceProperty with DEVPKEY_NAME to get localized friendly name of a device (which is shown in Device Manager).
To sum up:
\\?\HID#VID_203A&PID_FFFC&MI_01#7&2de99099&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd} - is device interface id (also referred as "device interface path" or "device name" in docs). This is path in virtual device file system.
{378de44c-56ef-11d1-bc8c-00a0c91405dd} - device interface class guid (GUID_DEVINTERFACE_MOUSE in this case. It determines which IOCTLs can be called on this device. IOCTL_MOUSE_QUERY_ATTRIBUTES in this case)
HID\VID_203A&PID_FFFC&MI_01\7&2de99099&0&0000 - is device instance id
NOTE: exact device interface id format is not documented, each device interface can generate file name it want. I don't recommend you to parse it - it could be changed in later Windows version, better aquire device instance id - it is documents at least.

How to identify PC (motherboard) in win32 api? [duplicate]

How to uniquely identify computer (mainboard) using C#(.Net/Mono, local application)?
Edition. We can identify mainboard in .Net using something like this (see Get Unique System Identifiers in C#):
using System.Management;
...
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_MotherboardDevice");
...
But unfortunately Mono does not support System.Management. How to do it under Mono for Linux? - I don't know :(
Write a function that takes a few unique hardware parameters as input and generates a hash out of them.
For example, Windows activation looks at the following hardware characteristics:
Display Adapter
SCSI Adapter
IDE Adapter (effectively the motherboard)
Network Adapter (NIC) and its MAC Address
RAM Amount Range (i.e., 0-64mb, 64-128mb, etc.)
Processor Type
Processor Serial Number
Hard Drive Device
Hard Drive Volume Serial Number (VSN)
CD-ROM / CD-RW / DVD-ROM
You can pick up a few of them to generate your unique computer identifier.
Please see: Get Unique System Identifiers in C#
You realistically have MotherboardID, CPUID, Disk Serial and MAC address, from experience none of them are 100%.
Our stats show
Disk serial Is missing 0.1 %
MAC Is missing 1.3 %
Motherboard ID Is missing 30 %
CPUID Is missing 99 %
0.04% of machines tested yielded no information, we couldn't even read the computer name. It maybe that these were some kind of virtual PC, HyperV or VMWare instance, or maybe just very locked down? In any case your design has to be able to cope with these cases.
Disk serial is the most reliable, but easy to change, mac can be changed and depending on the filtering applied when reading it can change if device drivers are added (hyperv, wireshark etc).
Motherboard and CPUID sometimes return values that are invalid "NONE", "AAAA..", "XXXX..." etc.
You should also note that these functions can be very slow to call (they may take a few seconds even on a fast PC), so it may be worth kicking them off on a background thread as early as possible, you ideally don't want to be blocking on them.
Try this:
http://carso-owen.blogspot.com/2007/02/how-to-get-my-motherboard-serial-number.html
Personally though, I'd go with hard drive serial number. If a mainboard dies and is replaced, that PC isn't valid any more. If the HDD drive is replaced, it doesn't matter too much because the software was on it.
Of course, on the other hand, if the HDD is just moved elsewhere, the information goes with it, so you might want to look at a combination of serial numbers, depending what you want it for.
How about the MAC address of the network card?

Resources