Programmatically getting the phone number of a device

One question that is often asked is "How do I get the phone number of my device?" Usually the person asking doesn't really need the phone number, they just need some number that uniquely identifies the device. While there does exist an IOCTL to get a unique ID (not the phone number), only apps that are privileged are allowed to call it. (On a closed Smartphone, that means only apps that have been signed with a certificate that is in the device's privileged certificate store.) As an alternative, the code below shows how to get the phone number (without needing to be privileged).

 

 

#include "stdafx.h"
#include "windows.h"
#include "tapi.h"
#include "tsp.h"

#define EXIT_ON_NULL(_p) \
if (_p == NULL) \
{ \
hr = E_OUTOFMEMORY; \
goto FuncExit; \
}

#define EXIT_ON_FALSE(_f) \
if (!(_f)) \
{ \
hr = E_FAIL; \
goto FuncExit; \
}

#define MAX(i, j) ((i) > (j) ? (i) : (j))

#define TAPI_API_LOW_VERSION 0x00020000
#define TAPI_API_HIGH_VERSION 0x00020000

#define CAPS_BUFFER_SIZE 512

HRESULT SHReadLineAddressCaps(LPTSTR szNumber, UINT cchNumber, PDWORD pdwCallFwdModes, UINT nLineNumber)
{
HRESULT hr = E_FAIL;
LRESULT lResult = 0;
HLINEAPP hLineApp;
DWORD dwNumDevs;
DWORD dwAPIVersion = TAPI_API_HIGH_VERSION;
LINEINITIALIZEEXPARAMS liep;

DWORD dwTAPILineDeviceID;
const DWORD dwAddressID = nLineNumber - 1;

liep.dwTotalSize = sizeof(liep);
liep.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT;

if (SUCCEEDED(lineInitializeEx(&hLineApp, 0, 0, TEXT("ExTapi_Lib"), &dwNumDevs, &dwAPIVersion, &liep)))
{

BYTE* pCapBuf = NULL;
DWORD dwCapBufSize = CAPS_BUFFER_SIZE;
LINEEXTENSIONID LineExtensionID;
LINEDEVCAPS* pLineDevCaps = NULL;
LINEADDRESSCAPS* placAddressCaps = NULL;

pCapBuf = new BYTE[dwCapBufSize];
EXIT_ON_NULL(pCapBuf);

pLineDevCaps = (LINEDEVCAPS*)pCapBuf;
pLineDevCaps->dwTotalSize = dwCapBufSize;

// Get TSP Line Device ID
dwTAPILineDeviceID = 0xffffffff;
for (DWORD dwCurrentDevID = 0 ; dwCurrentDevID < dwNumDevs ; dwCurrentDevID++)
{
if (0 == lineNegotiateAPIVersion(hLineApp, dwCurrentDevID, TAPI_API_LOW_VERSION, TAPI_API_HIGH_VERSION,
&dwAPIVersion, &LineExtensionID))
{
lResult = lineGetDevCaps(hLineApp, dwCurrentDevID, dwAPIVersion, 0, pLineDevCaps);

if (dwCapBufSize < pLineDevCaps->dwNeededSize)
{
delete[] pCapBuf;
dwCapBufSize = pLineDevCaps->dwNeededSize;
pCapBuf = new BYTE[dwCapBufSize];
EXIT_ON_NULL(pCapBuf);

pLineDevCaps = (LINEDEVCAPS*)pCapBuf;
pLineDevCaps->dwTotalSize = dwCapBufSize;

lResult = lineGetDevCaps(hLineApp, dwCurrentDevID, dwAPIVersion, 0, pLineDevCaps);
}

if ((0 == lResult) &&
(0 == _tcscmp((TCHAR*)((BYTE*)pLineDevCaps+pLineDevCaps->dwLineNameOffset), CELLTSP_LINENAME_STRING)))
{
dwTAPILineDeviceID = dwCurrentDevID;
break;
}
}
}

placAddressCaps = (LINEADDRESSCAPS*)pCapBuf;
placAddressCaps->dwTotalSize = dwCapBufSize;

lResult = lineGetAddressCaps(hLineApp, dwTAPILineDeviceID, dwAddressID, dwAPIVersion, 0, placAddressCaps);

if (dwCapBufSize < placAddressCaps->dwNeededSize)
{
delete[] pCapBuf;
dwCapBufSize = placAddressCaps->dwNeededSize;
pCapBuf = new BYTE[dwCapBufSize];
EXIT_ON_NULL(pCapBuf);

placAddressCaps = (LINEADDRESSCAPS*)pCapBuf;
placAddressCaps->dwTotalSize = dwCapBufSize;

lResult = lineGetAddressCaps(hLineApp, dwTAPILineDeviceID, dwAddressID, dwAPIVersion, 0, placAddressCaps);
}

if (0 == lResult)
{
if (szNumber)
{
szNumber[0] = _T('\0');

EXIT_ON_FALSE(0 != placAddressCaps->dwAddressSize);

// A non-zero dwAddressSize means a phone number was found
ASSERT(0 != placAddressCaps->dwAddressOffset);
PWCHAR tsAddress = (WCHAR*)(((BYTE*)placAddressCaps)+placAddressCaps->dwAddressOffset);

StringCchCopy(szNumber, cchNumber, tsAddress);
}

// Record the allowed forwarding modes
if (pdwCallFwdModes)
{
*pdwCallFwdModes = placAddressCaps->dwForwardModes;
}

hr = S_OK;
}

delete[] pCapBuf;
} // End if ()

FuncExit:
lineShutdown(hLineApp);

return hr;
}

// szNumber - Out Buffer for the phone number

//cchNumber - size of sznumber in characters

// nLineNumber - which phone line (1 or 2) to get the number for
HRESULT SHGetPhoneNumber(LPTSTR szNumber, UINT cchNumber, UINT nLineNumber)
{
return SHReadLineAddressCaps(szNumber, cchNumber, NULL, nLineNumber);
}