How do I get a unique identifier for a machine run

2019-02-09 14:26发布

问题:

I'm working on a Metro app written in C# and need a way to uniquely identify a device. I found the ASHWID in the documentation which looks great. The code suggested is as follows:

HardwareToken token = HardwareIdentification.GetPackageSpecificToken(null);
IBuffer hardwareId = token.Id;
IBuffer signature = token.Signature;
IBuffer certificate = token.Certificate;

The problem is, how do I turn that IBuffer into a string which I can use?

回答1:

After a lot of hunting through suggestions which were actually in JS or C++ I finally found an answer!

private string GetHardwareId()  
{  
    var token = HardwareIdentification.GetPackageSpecificToken(null);  
    var hardwareId = token.Id;  
    var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);  

    byte[] bytes = new byte[hardwareId.Length];  
    dataReader.ReadBytes(bytes);  

    return BitConverter.ToString(bytes);  
}  

Thanks go to this blog - http://bartwullems.blogspot.co.uk/2012/09/windows-8-uniquely-identifying-device.html



回答2:

This should work as well, but I don't have Windows 8 to test with...

private string GetHardwareId()   
{ 
  return BitConverter.ToString(Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray());
}

And if you call it more than once, you might want to stick it in a Lazy<T>

private static Lazy<string> _hardwareId = new Lazy<string>(() => BitConverter.ToString(Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray()), true);

public string HardwareId()   
{ 
     return _hardwareId.Value;
}

Or just make it static if you know it will always be called:

public static readonly string HardwareId = BitConverter.ToString(Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray()));


回答3:

You can use HardwareIdentification.GetPackageSpecificToken(null), see http://msdn.microsoft.com/en-us/library/windows/apps/jj553431.aspx

That function gives you a lot of information, that you can filter as you like. For example:

public static string GetMachineId()
{
    var hardwareToken = 
        HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray();
    var count = hardwareToken.Length / 4;
    ulong id = 0ul;
    for (int i = 0; i < count; i++)
    {
        switch (BitConverter.ToUInt16(hardwareToken, i * 4))
        {
            case 1:
                // processor
            case 2:
                // memory
            case 9:
                // system BIOS
                id = (id << 12) ^ BitConverter.ToUInt16(hardwareToken, i * 4 + 2);
                break;
        }
    }
    return Convert.ToBase64String(BitConverter.GetBytes(id));
}

However, bear in mind that this function, and the underlying API, cannot guarantee absolute uniqueness across all the machines connected to the internet. You would typically combine this with information about the user.

Another option is to generate and store a GUID in local (non-roaming) storage, and use that as your machine id. Depending in you exact needs, this may be a better solution.



回答4:

For a guid id you can do the following as an extension to the above answer

    private Guid GetHardwareId()
    {
        var token = HardwareIdentification.GetPackageSpecificToken(null);  
        var hardwareId = token.Id;  
        var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);  

        byte[] bytes = new byte[hardwareId.Length];  
        dataReader.ReadBytes(bytes);  

        byte[] deviceId = new byte[16];
        Array.Copy((byte[])bytes, deviceId, deviceId.Length);

        return new Guid(deviceId);
    }