A Simple Device ID Class
I've received a number of questions regarding how best to retrieve the Device ID. As a result, I've decided to provide the following class for your coding pleasure:
--- jeh
This posting is provided “AS IS“, without warranties, and confers no rights.
using System;
using System.Runtime.InteropServices;
namespace DeviceID
{
public sealed class DeviceIDException : Exception
{
public DeviceIDException() : base() {}
public DeviceIDException(string message) : base(message) {}
public DeviceIDException(string message, Exception innerException) : base(message, innerException) {}
}
/// <summary>
/// Summary description for DeviceID.
/// </summary>
public sealed class DeviceID
{
private const int GuidLength = 16;
private const Int32 ERROR_NOT_SUPPORTED = 0x32;
private const Int32 ERROR_INSUFFICIENT_BUFFER = 0x7A;
private const Int32 IOCTL_HAL_GET_DEVICEID = 0x01010054;
private byte[] idBytes = null;
private Guid idGuid = Guid.Empty;
private string idString = String.Empty;
public DeviceID()
{
byte[] buffer = new byte[20];
bool idLoaded = false;
uint bytesReturned;
while(!idLoaded)
{
Array.Copy(BitConverter.GetBytes(buffer.Length), 0, buffer, 0, 4);
try
{
idLoaded = KernelIoControl(IOCTL_HAL_GET_DEVICEID, 0, 0, buffer, (uint)buffer.Length, out bytesReturned);
}
catch (Exception e)
{
throw new DeviceIDException("This platform may not support DeviceIDs", e);
}
if(!idLoaded)
{
int error = Marshal.GetLastWin32Error();
if(error == ERROR_INSUFFICIENT_BUFFER)
{
buffer = new byte[BitConverter.ToUInt32(buffer, 0)];
}
else
{
// Some older PPC devices only return the ID if the buffer
// is exactly the size of a GUID, so attempt to retrieve
// the ID this way before throwing an exception
buffer = new byte[GuidLength];
idLoaded = KernelIoControl(IOCTL_HAL_GET_DEVICEID, 0, 0, buffer, GuidLength, out bytesReturned);
if(idLoaded)
{
InitializeFromBytes(buffer);
return;
}
else
{
if(error == ERROR_NOT_SUPPORTED)
{
throw new DeviceIDException("This platform does not support DeviceIDs");
}
else
{
throw new DeviceIDException(String.Format(
"Error Encountered Retrieving ID (0x{0})", error.ToString("X8")));
}
}
}
}
}
int dwPresetIDOffset = BitConverter.ToInt32(buffer, 4);
int dwPresetIDBytes = BitConverter.ToInt32(buffer, 8);
int dwPlatformIDOffset = BitConverter.ToInt32(buffer, 12);
int dwPlatformIDBytes = BitConverter.ToInt32(buffer, 16);
idBytes = new byte[dwPresetIDBytes + dwPlatformIDBytes];
Array.Copy(buffer, dwPresetIDOffset, idBytes, 0, dwPresetIDBytes);
Array.Copy(buffer, dwPlatformIDOffset, idBytes, dwPresetIDBytes, dwPlatformIDBytes);
}
public DeviceID(Guid g)
{
idBytes = g.ToByteArray();
idGuid = g;
}
public DeviceID(byte[] bytes)
{
InitializeFromBytes(bytes);
}
private void InitializeFromBytes(byte[] bytes)
{
idBytes = new byte[bytes.Length];
Array.Copy(bytes, 0, idBytes, 0, bytes.Length);
}
/// <summary>
/// DeviceIDs are only guaranteed to be Guids on PPC. On generic Windows CE, they can be
/// any unspecified length
/// </summary>
public bool IsGuid
{
get
{
return (idBytes.Length == GuidLength);
}
}
public Guid Guid
{
get
{
if(IsGuid)
{
if(idGuid == Guid.Empty)
{
idGuid = new Guid(idBytes);
}
return idGuid;
}
else
{
throw new DeviceIDException(String.Format("The DeviceID {0} is not a Guid", ToString()));
}
}
}
public override bool Equals(object obj)
{
if(obj is DeviceID)
{
DeviceID rhs = (DeviceID)obj;
if(idBytes.Length == rhs.idBytes.Length)
{
for(int i = 0; i < idBytes.Length; i++)
{
if(idBytes[i] != rhs.idBytes[i])
{
return false;
}
}
return true;
}
}
return false;
}
public override int GetHashCode()
{
if(IsGuid)
{
return this.Guid.GetHashCode();
}
else
{
// The default GetHashCode for object is guaranteed to
// always be the same for a given object, but not for
// multiple objects with the same value. We want a HashCode
// that will always be the same for a given ID
byte[] tempbytes = new byte[16];
if(idBytes.Length > 16)
{
Array.Copy(idBytes, 0, tempbytes, 0, 16);
}
else
{
Array.Clear(tempbytes, 0, 16); // Should be unneccessary
Array.Copy(idBytes, 0, tempbytes, 0, idBytes.Length);
}
return (new Guid(tempbytes)).GetHashCode();
}
}
public override string ToString()
{
if(idString == String.Empty)
{
if(IsGuid)
{
idString = this.Guid.ToString();
}
else
{
idString = "";
for(int i = 0; i < idBytes.Length; i++)
{
if(i == 4 || i == 6 || i == 8 || i == 10)
{
idString = String.Format("{0}-{1}", idString, idBytes[i].ToString("x2"));
}
else
{
idString = String.Format("{0}{1}", idString, idBytes[i].ToString("x2"));
}
}
}
}
return idString;
}
public byte[] ToByteArray()
{
byte[] cpyBytes = new byte[idBytes.Length];
Array.Copy(idBytes, 0, cpyBytes, 0, idBytes.Length);
return cpyBytes;
}
[DllImport("coredll.dll", SetLastError=true)]
private static extern bool KernelIoControl(
uint dwIoControlCode,
uint lpInBuf /* set to 0 */,
uint nInBufSize /* set to 0 */,
[In, Out] byte[] lpOutBuf,
uint nOutBufSize,
out uint lpBytesReturned);
}
}
Comments
- Anonymous
June 16, 2006
I needed to get a device ID for a recent project I worked on.&nbsp; Some googling found many discussions... - Anonymous
August 10, 2006
智能设备的唯一编号,可以用于实现更好的智能设备软件的授权机制,还可以利用它来限制智能设备客户端软件访问后台服务的权限,从而提高系统的安全性。本文介绍了获取智能设备唯一编号的各种方法。 - Anonymous
August 10, 2006
http://www.cnblogs.com/upto/archive/2006/08/11/GetDeviceUniqueID.html - Anonymous
June 21, 2007
获取 Windows Mobile 设备的唯一标识各种方法。