Thursday, February 12, 2009

Get "unique device ID" of a mobile device

I searched Internet a lot to find how to get "unique device id" for mobile devices, which is not dependent on any application data.

I am developing on Windows Mobile 6 with HTC phone.

There are severay ways to do it.

1) Use GetDeviceUniqueID(): GetDeviceUniqueID() requires at least 8 bytes of data to generate a hash. Furthermore, you should not expect GetDeviceUniqueID() to return the UUID string as HAL_GET_DEVICEID does. It will return application-specific hash that is unique for this particular device. You should treat it as a sequence of bytes.

2) Use HAL_GET_DEVICEID: This does not work on Smartphone unless your code is signed with a privleged certificate.

3) Get IMEI(International Mobile Equipment Identity) number: The IMEI number is a unique 15-digit code used to identify an individual GSM mobile phone in a GSM network. The IMEI number can be displayed on most phones by dialing the code *#06#. Every phone has a unique IMEI number, which is usually printed under the battery on the phone. The IMEI number is used in many mobile applications since the unique number makes it possible to lock software to a particular phone. This effectively prevents unauthorized copying of an application.
--> Use Tapi dll
--> Make your code (See, References (2))
: References
1) Getting the IMEI number: a UIQ 3 code example

2) IMEI in C#





using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

// Reference: http://groups.google.com/group/microsoft.public.dotnet.framework.compactframework/browse_thread/thread/280299812d7b171c
public class clsDeviceInfo
{
private string _manufacture;
private string _model;
private string _revision;
private string _serialNumber; // IMEI
private string _subscriberID; // IMSI

public string Manufacture
{
get { return _manufacture; }
}

public string Model
{
get { return _model; }
}

public string Revision
{
get { return _revision; }
}

public string SerialNumber
{
get { return _serialNumber; }
}

public string SubscriberID
{
get { return _subscriberID; }
}

public clsDeviceInfo()
{
GetDeviceInfo();
}

private void GetDeviceInfo()
{
IntPtr hLine;
int dwNumDev;
int num1 = 0x20000;

LINEINITIALIZEEXPARAMS lineInitializeParams = new LINEINITIALIZEEXPARAMS();
lineInitializeParams.dwTotalSize = (uint)Marshal.SizeOf(lineInitializeParams);
lineInitializeParams.dwNeededSize = lineInitializeParams.dwTotalSize;
lineInitializeParams.dwUsedSize = lineInitializeParams.dwUsedSize;
lineInitializeParams.dwOptions = 2;
lineInitializeParams.hEvent = IntPtr.Zero;
lineInitializeParams.hCompletionPort = IntPtr.Zero;

// lineInitializeEx
int result = NativeTapi.lineInitializeEx(out hLine, IntPtr.Zero, IntPtr.Zero, null, out dwNumDev, ref num1, ref lineInitializeParams);
if (result != 0)
{
return;
}

// lineNegotiateAPIVerison
int version;
int dwAPIVersionLow = 0x10004;
int dwAPIVersionHigh = 0x20000;
LINEEXTENSIONID lineExtensionID;
result = NativeTapi.lineNegotiateAPIVersion(hLine, 0, dwAPIVersionLow, dwAPIVersionHigh, out version, out lineExtensionID);
if (result != 0)
{
return;
}

// lineOpen
IntPtr hLine2 = IntPtr.Zero;
result = NativeTapi.lineOpen(hLine, 0, out hLine2, version, 0, IntPtr.Zero, 0x00000002, 0x00000004, IntPtr.Zero);
if (result != 0)
{
return;
}

// lineGetGeneralInfo
int structSize = Marshal.SizeOf(new LINEGENERALINFO());
byte[] bytes = new byte[structSize];
byte[] tmpBytes = BitConverter.GetBytes(structSize);

for (int index = 0; index < tmpBytes.Length; index++)
{
bytes[index] = tmpBytes[index];
}

// make initial query to retrieve necessary size
result = NativeTapi.lineGetGeneralInfo(hLine2, bytes);

// get the needed size
int neededSize = BitConverter.ToInt32(bytes, 4);

// resize the array
bytes = new byte[neededSize];

// write out the new allocated size to the byte stream
tmpBytes = BitConverter.GetBytes(neededSize);
for (int index = 0; index < tmpBytes.Length; index++)
{
bytes[index] = tmpBytes[index];
}

// fetch the information with properly size buffer
result = NativeTapi.lineGetGeneralInfo(hLine2, bytes);
if (result != 0)
{
//LogManager.GetLogger("DeviceInfo").Error(Marshal.GetLastWin32Error().ToString());
return;
}

int size;
int offset;

size = BitConverter.ToInt32(bytes, 12);
offset = BitConverter.ToInt32(bytes, 16);

// manufacture
if (size > 0 && offset > 0)
{
_manufacture = Encoding.Unicode.GetString(bytes, offset, size);
_manufacture = _manufacture.Substring(0, _manufacture.IndexOf('\0'));
}

size = BitConverter.ToInt32(bytes, 20);
offset = BitConverter.ToInt32(bytes, 24);

// model
if (size > 0 && offset > 0)
{
_model = Encoding.Unicode.GetString(bytes, offset, size);
_model = _model.Substring(0, _model.IndexOf('\0'));
}

size = BitConverter.ToInt32(bytes, 28);
offset = BitConverter.ToInt32(bytes, 32);

// revision
if (size > 0 && offset > 0)
{
_revision = Encoding.Unicode.GetString(bytes, offset, size);
_revision = _revision.Substring(0, _revision.IndexOf('\0'));
}

size = BitConverter.ToInt32(bytes, 36);
offset = BitConverter.ToInt32(bytes, 40);

// serial number (IMEI)
if (size > 0 && offset > 0)
{
_serialNumber = Encoding.Unicode.GetString(bytes, offset, size);
_serialNumber = _serialNumber.Substring(0, _serialNumber.IndexOf('\0'));
}

size = BitConverter.ToInt32(bytes, 44);
offset = BitConverter.ToInt32(bytes, 48);

// subscriber id (IMSI)
if (size > 0 && offset > 0)
{
_subscriberID = Encoding.Unicode.GetString(bytes, offset, size);
_subscriberID = _subscriberID.Substring(0, _subscriberID.IndexOf('\0'));
}

// lineClose for hLine2
NativeTapi.lineClose(hLine2);

// lineShutdown for hLine
NativeTapi.lineShutdown(hLine);
}

[StructLayout(LayoutKind.Sequential)]
private struct LINEEXTENSIONID
{
public IntPtr dwExtensionID0;
public IntPtr dwExtensionID1;
public IntPtr dwExtensionID2;
public IntPtr dwExtensionID3;
}

[StructLayout(LayoutKind.Sequential)]
private struct LINEINITIALIZEEXPARAMS
{
public uint dwTotalSize;
public uint dwNeededSize;
public uint dwUsedSize;
public uint dwOptions;
public System.IntPtr hEvent;
public System.IntPtr hCompletionPort;
public uint dwCompletionKey;
}

[StructLayout(LayoutKind.Sequential)]
private struct LINEGENERALINFO
{
public int dwTotalSize;
public int dwNeededSize;
public int dwUsedSize;
public int dwManufacturerSize;
public int dwManufacturerOffset;
public int dwModelSize;
public int dwModelOffset;
public int dwRevisionSize;
public int dwRevisionOffset;
public int dwSerialNumberSize;
public int dwSerialNumberOffset;
public int dwSubscriberNumberSize;
public int dwSubscriberNumberOffset;
}

private class NativeTapi
{
[DllImport("coredll")]
public static extern int lineClose(IntPtr hLine);

[DllImport("cellcore")]
public static extern int lineGetGeneralInfo(IntPtr hLine, byte[] bytes);

[DllImport("coredll")]
public static extern int lineGetAddressCaps(IntPtr hLineApp, int dwDeviceID, int dwAddressID, int dwAPIVersion, int dwExtVersion, byte[] lpAddressCaps);

[DllImport("coredll")]
public static extern int lineInitializeEx(out IntPtr lpm_hLineApp, IntPtr hInstance, IntPtr lpfnCallback, string lpszFriendlyAppName, out int lpdwNumDevs, ref int lpdwAPIVersion, ref LINEINITIALIZEEXPARAMS lpLineInitializeExParams);

[DllImport("coredll")]
public static extern int lineNegotiateAPIVersion(IntPtr m_hLineApp, int dwDeviceID, int dwAPILowVersion, int dwAPIHighVersion, out int lpdwAPIVersion, out LINEEXTENSIONID lpExtensionID);

[DllImport("coredll")]
public static extern int lineOpen(IntPtr m_hLineApp, int dwDeviceID, out IntPtr lphLine, int dwAPIVersion, int dwExtVersion, IntPtr dwCallbackInstance, int dwPrivileges, int dwMediaModes, IntPtr lpCallParams);

[DllImport("coredll")]
public static extern int lineShutdown(IntPtr m_hLineApp);
}
}

No comments: