1299 lines
41 KiB
C++
1299 lines
41 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// File: serialid.cpp
|
|
//
|
|
// Microsoft Digital Rights Management
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999, All Rights Reserved
|
|
//
|
|
// Description:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#include <windows.h>
|
|
#include <stddef.h>
|
|
|
|
#include "drmerr.h"
|
|
#include "aspi32.h"
|
|
#include "serialid.h"
|
|
#include "spti.h"
|
|
//#include "KBDevice.h"
|
|
#include <crtdbg.h>
|
|
|
|
HRESULT __stdcall UtilStartStopService(bool fStartService);
|
|
|
|
|
|
// #define WRITE_TO_LOG_FILE
|
|
|
|
#if defined(DBG) || defined(WRITE_TO_LOG_FILE)
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
void DebugMsg(const char* pszFormat, ...)
|
|
{
|
|
#if defined(DBG) || defined(WRITE_TO_LOG_FILE)
|
|
char buf[1024];
|
|
sprintf(buf, "[Serial Number Library](%lu): ", GetCurrentThreadId());
|
|
va_list arglist;
|
|
va_start(arglist, pszFormat);
|
|
vsprintf(&buf[strlen(buf)], pszFormat, arglist);
|
|
va_end(arglist);
|
|
strcat(buf, "\n");
|
|
|
|
#if defined(DBG)
|
|
OutputDebugString(buf);
|
|
#endif
|
|
|
|
#if defined(WRITE_TO_LOG_FILE)
|
|
FILE* fp = fopen("c:\\WmdmService.txt", "a");
|
|
if (fp)
|
|
{
|
|
fprintf(fp, buf);
|
|
fclose(fp);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
#ifdef USE_IOREADY
|
|
#ifndef __Using_iomegaReady_Lib__
|
|
#define __Using_iomegaReady_Lib__
|
|
#endif
|
|
#include "ioReadyMin.h"
|
|
#endif
|
|
|
|
#define WCS_PMID_SOFT L"media.id"
|
|
|
|
|
|
BOOL IsWinNT()
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
BOOL bRet=FALSE;
|
|
|
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
if ( ! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
|
|
return FALSE;
|
|
|
|
switch ( osvi.dwPlatformId )
|
|
{
|
|
case VER_PLATFORM_WIN32_NT:
|
|
bRet=TRUE;
|
|
break;
|
|
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
bRet=FALSE;
|
|
break;
|
|
|
|
case VER_PLATFORM_WIN32s:
|
|
bRet=FALSE;
|
|
break;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL IsAdministrator(DWORD& dwLastError)
|
|
{
|
|
dwLastError = ERROR_SUCCESS;
|
|
if ( IsWinNT() )
|
|
{
|
|
/* typedef SC_HANDLE (*T_POSCM)(LPCTSTR,LPCTSTR,DWORD);
|
|
|
|
T_POSCM p_OpenSCM=NULL;
|
|
|
|
p_OpenSCM = (T_POSCM)GetProcAddress(GetModuleHandle("advapi32.dll"), "OpenSCManagerA");
|
|
|
|
if( !p_OpenSCM )
|
|
{
|
|
return FALSE;
|
|
}
|
|
*/
|
|
SC_HANDLE hSCM = OpenSCManagerA(NULL, // local machine
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_ALL_ACCESS); // full access
|
|
if ( !hSCM )
|
|
{
|
|
dwLastError = GetLastError();
|
|
if (dwLastError == ERROR_ACCESS_DENIED)
|
|
{
|
|
dwLastError = ERROR_SUCCESS;
|
|
}
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
CloseServiceHandle(hSCM);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else // On Win9x, everybody is admin
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
UINT __stdcall UtilGetDriveType(LPSTR szDL)
|
|
{
|
|
return GetDriveTypeA(szDL);
|
|
}
|
|
|
|
BOOL IsIomegaDrive(DWORD dwDriveNum)
|
|
{
|
|
BOOL bRet=FALSE;
|
|
|
|
#ifdef USE_IOREADY
|
|
if (dwDriveNum >= 26)
|
|
{
|
|
return bRet;
|
|
}
|
|
|
|
ioReady::Drive *pDrive = NULL;
|
|
pDrive = new ioReady::Drive((int) dwDriveNum);
|
|
if ( pDrive )
|
|
{
|
|
if ( pDrive->isIomegaDrive() )
|
|
bRet=TRUE;
|
|
delete pDrive;
|
|
}
|
|
#endif
|
|
DebugMsg("IsIomegaDrive returning %u", bRet);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL GetIomegaDiskSerialNumber(DWORD dwDriveNum, PWMDMID pSN)
|
|
{
|
|
BOOL bRet=FALSE;
|
|
|
|
#ifdef USE_IOREADY
|
|
if (dwDriveNum >= 26)
|
|
{
|
|
return bRet;
|
|
}
|
|
|
|
ioReady::Drive *pDrive = NULL;
|
|
char *pszSerial = NULL;
|
|
pDrive = new ioReady::Drive((int) dwDriveNum);
|
|
if ( pDrive )
|
|
{
|
|
if ( pDrive->isIomegaDrive() )
|
|
{
|
|
ioReady::Disk &refDisk = pDrive->getDisk();
|
|
pszSerial = (char *)refDisk.getMediaSerialNumber();
|
|
if ( pszSerial[0] )
|
|
{
|
|
ZeroMemory(pSN->pID, WMDMID_LENGTH);
|
|
if (ioReady::ct_nSerialNumberLength <= sizeof(pSN->pID))
|
|
{
|
|
CopyMemory(pSN->pID, pszSerial, ioReady::ct_nSerialNumberLength);
|
|
pSN->SerialNumberLength = ioReady::ct_nSerialNumberLength;
|
|
pSN->dwVendorID = MDSP_PMID_IOMEGA;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete pDrive;
|
|
#endif
|
|
return bRet;
|
|
}
|
|
|
|
HRESULT __stdcall UtilGetManufacturer(LPWSTR pDeviceName, LPWSTR *ppwszName, UINT nMaxChars)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
|
|
CARg(pDeviceName);
|
|
CARg(ppwszName);
|
|
|
|
CPRg(nMaxChars>16); // ensure enough buffer size
|
|
|
|
DWORD dwDriveNum;
|
|
|
|
// We use only the first char of pDeviceName and expect it to
|
|
// be a drive letter. The rest of pDeviceName is not validated.
|
|
// Perhaps it should, but we don't want to break our clients.
|
|
if (pDeviceName[0] >= L'A' && pDeviceName[0] <= L'Z')
|
|
{
|
|
dwDriveNum = pDeviceName[0] - L'A';
|
|
}
|
|
else if (pDeviceName[0] >= L'a' && pDeviceName[0] <= L'z')
|
|
{
|
|
dwDriveNum = pDeviceName[0] - L'a';
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
|
|
|
|
if ( IsIomegaDrive(dwDriveNum) )
|
|
wcscpy(*ppwszName, L"Iomega");
|
|
else
|
|
{
|
|
wcscpy(*ppwszName, L"Unknown");
|
|
WMDMID snData;
|
|
snData.cbSize = sizeof(WMDMID);
|
|
if ( S_OK==UtilGetSerialNumber(pDeviceName, &snData, FALSE) )
|
|
{
|
|
switch ( snData.dwVendorID )
|
|
{
|
|
case 1:
|
|
wcscpy(*ppwszName, L"SanDisk");
|
|
break;
|
|
case 2:
|
|
wcscpy(*ppwszName, L"Iomega");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Error:
|
|
return hr;
|
|
}
|
|
|
|
#include <winioctl.h>
|
|
|
|
// This is defined in the Whistler platform SDK.
|
|
#ifndef IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER
|
|
#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE( \
|
|
IOCTL_STORAGE_BASE, 0x304, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
|
#endif
|
|
|
|
HRESULT GetMSNWithNtIoctl(LPCWSTR wcsDevice, PWMDMID pSN)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
HANDLE hDevice = INVALID_HANDLE_VALUE;
|
|
BOOL bResult;
|
|
MEDIA_SERIAL_NUMBER_DATA MSNGetSize;
|
|
MEDIA_SERIAL_NUMBER_DATA* pMSN = NULL; // Buffer to hold the serial number
|
|
DWORD dwBufferSize; // Size of pMSNNt buffer
|
|
ULONG i;
|
|
DWORD dwRet = 0; // Bytes returned
|
|
|
|
CARg(pSN);
|
|
|
|
DebugMsg("Entering GetMSNWithNtIoctl");
|
|
|
|
hDevice = CreateFileW( wcsDevice,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL |
|
|
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
|
|
NULL);
|
|
CWRg(hDevice != INVALID_HANDLE_VALUE);
|
|
|
|
DebugMsg("GetMSNWithNtIoctl: CreateFile ok");
|
|
|
|
// Get size of buffer we need to allocate
|
|
bResult = DeviceIoControl( hDevice,
|
|
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
|
|
NULL,
|
|
0,
|
|
(LPVOID)&MSNGetSize,
|
|
sizeof(MEDIA_SERIAL_NUMBER_DATA),
|
|
&dwRet,
|
|
NULL);
|
|
|
|
// Handle expected buffer overrun error
|
|
if ( !bResult )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// Error 'more data is available' is an expected error code
|
|
if ( hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA) )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else goto Error;
|
|
}
|
|
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1 ok");
|
|
|
|
if (dwRet < RTL_SIZEOF_THROUGH_FIELD(MEDIA_SERIAL_NUMBER_DATA, SerialNumberLength))
|
|
{
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1 dwRet bad: %u, expected >= %u",
|
|
dwRet, RTL_SIZEOF_THROUGH_FIELD(MEDIA_SERIAL_NUMBER_DATA, SerialNumberLength));
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
|
|
// No serial number?
|
|
if ( MSNGetSize.SerialNumberLength == 0 )
|
|
{
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1: MSNGetSize.SerialNumberLength == 0");
|
|
hr = E_FAIL;
|
|
goto Error;
|
|
}
|
|
// The WMDMID structure we are using can only handle 128 bytes long serial numbers
|
|
if ( MSNGetSize.SerialNumberLength > WMDMID_LENGTH )
|
|
{
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1: MSNGetSize.SerialNumberLength > WMDMID_LENGTH");
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
goto Error;
|
|
}
|
|
|
|
// Allocate buffer and call to get the serial number
|
|
dwBufferSize = sizeof(MEDIA_SERIAL_NUMBER_DATA) + MSNGetSize.SerialNumberLength;
|
|
pMSN = (MEDIA_SERIAL_NUMBER_DATA*) new BYTE[dwBufferSize];
|
|
if ( pMSN == NULL )
|
|
{
|
|
DebugMsg("GetMSNWithNtIoctl: Out of memory allocating %u bytes", dwBufferSize);
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
}
|
|
bResult = DeviceIoControl( hDevice,
|
|
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
|
|
NULL,
|
|
0,
|
|
(LPVOID)pMSN,
|
|
dwBufferSize,
|
|
&dwRet,
|
|
NULL);
|
|
if ( !bResult )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl2 failed, hr = 0x%x", hr);
|
|
goto Error;
|
|
}
|
|
if (dwRet < FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData) + pMSN->SerialNumberLength)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl1: MSNGetSize.SerialNumberLength == 0");
|
|
goto Error;
|
|
}
|
|
if (pMSN->SerialNumberLength > sizeof(pSN->pID))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
DebugMsg("GetMSNWithNtIoctl: DeviceIoControl2: MSNGetSize.SerialNumberLength > WMDMID_LENGTH");
|
|
goto Error;
|
|
}
|
|
|
|
// Copy serial number to out structure
|
|
memcpy( pSN->pID, pMSN->SerialNumberData, pMSN->SerialNumberLength );
|
|
pSN->SerialNumberLength = pMSN->SerialNumberLength;
|
|
|
|
// Check result
|
|
pSN->dwVendorID = MDSP_PMID_SANDISK;
|
|
if ( pSN->SerialNumberLength > 24 )
|
|
{
|
|
char szVID[4];
|
|
for ( i=0; i<3; i++ )
|
|
{
|
|
szVID[i]=(pSN->pID[18+i]);
|
|
}
|
|
szVID[i]=0;
|
|
|
|
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
|
SORT_DEFAULT);
|
|
|
|
// if ( !lstrcmpiA(szVID, "ZIP") ||
|
|
// !lstrcmpiA(szVID, "JAZ") ||
|
|
// !lstrcmpiA(szVID, "CLI") )
|
|
if (CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "ZIP", -1) == CSTR_EQUAL ||
|
|
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "JAZ", -1) == CSTR_EQUAL ||
|
|
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "CLI", -1) == CSTR_EQUAL)
|
|
{
|
|
pSN->dwVendorID = MDSP_PMID_IOMEGA;
|
|
}
|
|
}
|
|
|
|
|
|
if ( (pSN->dwVendorID==MDSP_PMID_IOMEGA) && (pSN->SerialNumberLength>19) )
|
|
{
|
|
pSN->SerialNumberLength = 19;
|
|
pSN->pID[18] = 0;
|
|
}
|
|
DebugMsg("GetMSNWithNtIoctl ok, pSN->SerialNumberLength = %u", pSN->SerialNumberLength);
|
|
|
|
Error:
|
|
if ( hDevice != INVALID_HANDLE_VALUE ) CloseHandle(hDevice);
|
|
if ( pMSN ) delete [] pMSN;
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT GetMSNWith9xIoctl(char chDriveLetter, PWMDMID pSN, DWORD dwCode, DWORD dwIOCTL )
|
|
{
|
|
HRESULT hr=S_OK;
|
|
HANDLE hDevice=INVALID_HANDLE_VALUE;
|
|
BOOL bResult;
|
|
MEDIA_SERIAL_NUMBER_DATA MSNGetSize;
|
|
MEDIA_SERIAL_NUMBER_DATA* pMSN = NULL; // Buffer to hold the serial number
|
|
ULONG uBufferSize; // Size of pMSN
|
|
DWORD dwRet = 0; // Bytes returned
|
|
|
|
// _ASSERT( dwCode == 0x440D ||
|
|
// dwCode == 0x4404 );
|
|
// _ASSERT( (dwIOCTL == (0x0800 | 0x75)) ||
|
|
// (dwIOCTL == WIN9X_IOCTL_GET_MEDIA_SERIAL_NUMBER) );
|
|
CARg(pSN);
|
|
|
|
hDevice = CreateFile("\\\\.\\VWIN32",0,0,NULL,OPEN_EXISTING,FILE_FLAG_DELETE_ON_CLOSE,0);
|
|
|
|
CFRg(hDevice != INVALID_HANDLE_VALUE);
|
|
|
|
DIOC_REGISTERS reg;
|
|
DWORD cb;
|
|
WORD drv;
|
|
|
|
drv = (chDriveLetter >= 'a' ) ? (chDriveLetter-'a') : (chDriveLetter-'A');
|
|
|
|
// Call first to get serial number size
|
|
{
|
|
MSNGetSize.SerialNumberLength = 0;
|
|
reg.reg_EAX = dwCode; //create the ioctl
|
|
reg.reg_EBX = drv;
|
|
reg.reg_EBX++;
|
|
reg.reg_ECX = dwIOCTL; // BUGBUG, needs definition of 0x75
|
|
|
|
//
|
|
// ISSUE: The following code will not work on 64-bit systems.
|
|
// The conditional is only to get the code to compiler.
|
|
//
|
|
|
|
#if defined(_WIN64)
|
|
reg.reg_EDX = (DWORD)(DWORD_PTR)&MSNGetSize;
|
|
#else
|
|
reg.reg_EDX = (DWORD)&MSNGetSize;
|
|
#endif
|
|
reg.reg_Flags = 0x0001;
|
|
|
|
bResult = DeviceIoControl( hDevice,
|
|
VWIN32_DIOC_DOS_IOCTL,
|
|
®,
|
|
sizeof(DIOC_REGISTERS),
|
|
®,
|
|
sizeof(DIOC_REGISTERS),
|
|
&cb,
|
|
NULL );
|
|
|
|
// Check for errors
|
|
if ( bResult && !(reg.reg_Flags&0x0001) )
|
|
{
|
|
if ( (MSNGetSize.Result != ERROR_SUCCESS) &&
|
|
(MSNGetSize.Result != ERROR_MORE_DATA ) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(MSNGetSize.Result);
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
// No serial number?
|
|
if ( MSNGetSize.SerialNumberLength == 0 )
|
|
{
|
|
hr = E_FAIL;
|
|
goto Error;
|
|
}
|
|
|
|
// Max serial number size is 128 byte right now
|
|
if ( MSNGetSize.SerialNumberLength > WMDMID_LENGTH )
|
|
{
|
|
hr = E_FAIL;
|
|
goto Error;
|
|
}
|
|
|
|
// Allocate buffer to get serial number
|
|
uBufferSize = MSNGetSize.SerialNumberLength + sizeof(MEDIA_SERIAL_NUMBER_DATA);
|
|
pMSN = (MEDIA_SERIAL_NUMBER_DATA*) new BYTE[uBufferSize];
|
|
if ( pMSN == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
|
|
// Call again to accually get the serial number
|
|
{
|
|
pMSN->SerialNumberLength = uBufferSize;
|
|
reg.reg_EAX = dwCode; //create the ioctl
|
|
reg.reg_EBX = drv;
|
|
reg.reg_EBX++;
|
|
reg.reg_ECX = dwIOCTL; // BUGBUG, needs definition of 0x75
|
|
|
|
//
|
|
// ISSUE: The following code will not work on 64-bit systems.
|
|
// The conditional is only to get the code to compiler.
|
|
//
|
|
|
|
#if defined(_WIN64)
|
|
reg.reg_EDX = (DWORD)0;
|
|
#else
|
|
reg.reg_EDX = (DWORD)pMSN;
|
|
#endif
|
|
reg.reg_Flags = 0x0001;
|
|
|
|
bResult = DeviceIoControl( hDevice,
|
|
VWIN32_DIOC_DOS_IOCTL,
|
|
®,
|
|
sizeof(DIOC_REGISTERS),
|
|
®,
|
|
sizeof(DIOC_REGISTERS),
|
|
&cb,
|
|
NULL );
|
|
|
|
// Check for errors
|
|
if ( bResult && !(reg.reg_Flags&0x0001) )
|
|
{
|
|
if ( (pMSN->Result != ERROR_SUCCESS) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(pMSN->Result);
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy serial number to out structure
|
|
// and 'figure out' vendor
|
|
{
|
|
memcpy( pSN->pID, pMSN->SerialNumberData, pMSN->SerialNumberLength );
|
|
pSN->SerialNumberLength = pMSN->SerialNumberLength;
|
|
|
|
pSN->dwVendorID = MDSP_PMID_SANDISK;
|
|
if ( pSN->SerialNumberLength > 24 )
|
|
{
|
|
char szVID[4];
|
|
ULONG i;
|
|
|
|
for ( i=0; i<3; i++ )
|
|
{
|
|
szVID[i]=(pSN->pID[18+i]);
|
|
}
|
|
szVID[i]=0;
|
|
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
|
SORT_DEFAULT);
|
|
|
|
// if ( !lstrcmpiA(szVID, "ZIP") ||
|
|
// !lstrcmpiA(szVID, "JAZ") ||
|
|
// !lstrcmpiA(szVID, "CLI") )
|
|
if (CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "ZIP", -1) == CSTR_EQUAL ||
|
|
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "JAZ", -1) == CSTR_EQUAL ||
|
|
CompareStringA(lcid, NORM_IGNORECASE, szVID, -1, "CLI", -1) == CSTR_EQUAL)
|
|
{
|
|
pSN->dwVendorID = MDSP_PMID_IOMEGA;
|
|
}
|
|
}
|
|
|
|
if ( (pSN->dwVendorID==MDSP_PMID_IOMEGA) && (pSN->SerialNumberLength>19) )
|
|
{
|
|
pSN->SerialNumberLength = 19;
|
|
pSN->pID[18] = 0;
|
|
}
|
|
}
|
|
|
|
Error:
|
|
if ( hDevice != INVALID_HANDLE_VALUE ) CloseHandle(hDevice);
|
|
if ( pMSN ) delete [] pMSN;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetDeviceSNwithNTScsiPassThrough(LPCWSTR wszDevice, PWMDMID pSN)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
HANDLE fileHandle=INVALID_HANDLE_VALUE;
|
|
UCHAR buffer[2048];
|
|
BOOL status;
|
|
ULONG returned, length, i, bufOffset;
|
|
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
|
|
PSCSI_ADAPTER_BUS_INFO adapterInfo;
|
|
PSCSI_INQUIRY_DATA inquiryData;
|
|
|
|
DebugMsg("Entering GetDeviceSNwithNTScsiPassThrough");
|
|
|
|
ZeroMemory(pSN, sizeof(WMDMID));
|
|
fileHandle = CreateFileW(wszDevice,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
|
|
NULL);
|
|
|
|
CWRg(fileHandle != INVALID_HANDLE_VALUE);
|
|
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: CreateFile ok");
|
|
|
|
status = DeviceIoControl(fileHandle,
|
|
IOCTL_SCSI_GET_INQUIRY_DATA,
|
|
NULL,
|
|
0,
|
|
buffer,
|
|
sizeof(buffer),
|
|
&returned,
|
|
FALSE);
|
|
// CWRg(status);
|
|
// We use IOCTL_SCSI_GET_INQUIRY_DATA to get the disk's SCSI address, if
|
|
// this fails, it is not on a SCSI bus so the SCSI address will be all zeros
|
|
if ( status )
|
|
{
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl1 ok");
|
|
|
|
if (returned < sizeof(SCSI_ADAPTER_BUS_INFO))
|
|
{
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl1 returned = %u < sizeof(SCSI_ADAPTER_BUS_INFO) = %u",
|
|
returned, sizeof(SCSI_ADAPTER_BUS_INFO));
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
adapterInfo = (PSCSI_ADAPTER_BUS_INFO) buffer;
|
|
CFRg(adapterInfo->NumberOfBuses>0);
|
|
if (returned < adapterInfo->BusData[0].InquiryDataOffset + sizeof(SCSI_INQUIRY_DATA))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl1 returned = %u < adapterInfo->BusData[0].InquiryDataOffset (%u) + sizeof(SCSI_INQUIRY_DATA) (%u)",
|
|
returned, adapterInfo->BusData[0].InquiryDataOffset, sizeof(SCSI_INQUIRY_DATA));
|
|
goto Error;
|
|
}
|
|
inquiryData = (PSCSI_INQUIRY_DATA) (buffer +
|
|
adapterInfo->BusData[0].InquiryDataOffset); // we know card readers has only one bus
|
|
}
|
|
|
|
ZeroMemory(&sptwb,sizeof(sptwb));
|
|
|
|
sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
|
|
sptwb.spt.PathId = (status?inquiryData->PathId:0);
|
|
sptwb.spt.TargetId = (status?inquiryData->TargetId:0);
|
|
sptwb.spt.Lun = (status?inquiryData->Lun:0);
|
|
sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
|
|
sptwb.spt.SenseInfoLength = 24;
|
|
sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
|
|
sptwb.spt.DataTransferLength = 256 /*256*/;
|
|
sptwb.spt.TimeOutValue = 2;
|
|
sptwb.spt.DataBufferOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
|
|
sptwb.spt.SenseInfoOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
|
|
sptwb.spt.Cdb[0] = 0x12 /* Command - SCSIOP_INQUIRY */;
|
|
sptwb.spt.Cdb[1] = 0x01; /* Request - VitalProductData */
|
|
sptwb.spt.Cdb[2] = 0x80 /* VPD page 80 - serial number page */;
|
|
sptwb.spt.Cdb[3] = 0;
|
|
sptwb.spt.Cdb[4] = 0xff /*255*/;
|
|
sptwb.spt.Cdb[5] = 0;
|
|
|
|
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
|
|
sptwb.spt.DataTransferLength;
|
|
|
|
status = DeviceIoControl(fileHandle,
|
|
IOCTL_SCSI_PASS_THROUGH,
|
|
&sptwb,
|
|
sizeof(SCSI_PASS_THROUGH),
|
|
&sptwb,
|
|
length,
|
|
&returned,
|
|
FALSE);
|
|
CWRg(status);
|
|
|
|
// CFRg(sptwb.ucDataBuf[3]>0);
|
|
|
|
// Keep or remove this @@@@
|
|
if (returned < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 4)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 returned = %u < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 4 = %u",
|
|
returned, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 4);
|
|
goto Error;
|
|
}
|
|
|
|
// Here there is a difference between Parallel and USB Unit:
|
|
// Since the Parallel Unit is an emulation of SCSI disk, it doesn't follow SCSI spec.
|
|
pSN->SerialNumberLength=0;
|
|
pSN->dwVendorID=0;
|
|
if ( sptwb.ucDataBuf[3] == 0 ) // this is the SanDisk USB device
|
|
{
|
|
pSN->SerialNumberLength = 20;
|
|
// Keep or remove this @@@@
|
|
if (returned < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 5)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 returned = %u < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 5 = %u",
|
|
returned, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + 5);
|
|
goto Error;
|
|
}
|
|
if ( sptwb.ucDataBuf[4] > 0 )
|
|
{
|
|
if ((DWORD) (sptwb.ucDataBuf[4]) + 5 >= (DWORD) (pSN->SerialNumberLength))
|
|
{
|
|
bufOffset=(sptwb.ucDataBuf[4]+5)-(pSN->SerialNumberLength);
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
}
|
|
else
|
|
{ // There are 50K ImageMate III devices that read like this
|
|
bufOffset=36;
|
|
}
|
|
}
|
|
else if ( sptwb.ucDataBuf[3] > 0 )
|
|
{
|
|
pSN->SerialNumberLength = sptwb.ucDataBuf[3];
|
|
bufOffset=4;
|
|
}
|
|
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 pSN->SerialNumberLength = %u",
|
|
pSN->SerialNumberLength);
|
|
// The WMDMID structure we are using can only handle 128 bytes long serial numbers
|
|
if ( pSN->SerialNumberLength > WMDMID_LENGTH )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 pSN->SerialNumberLength > WMDMID_LENGTH = %u", WMDMID_LENGTH);
|
|
goto Error;
|
|
}
|
|
|
|
// Keep or remove this @@@@
|
|
if (returned < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + bufOffset + pSN->SerialNumberLength)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: DeviceIoControl2 returned = %u < offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) (=%u) + bufOffset (=%u) + pSN->SerialNumberLength) (=%u) = %u",
|
|
returned, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf), bufOffset, pSN->SerialNumberLength,
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + bufOffset + pSN->SerialNumberLength);
|
|
goto Error;
|
|
}
|
|
|
|
for ( i=0; i<pSN->SerialNumberLength; i++ )
|
|
{
|
|
pSN->pID[i] = sptwb.ucDataBuf[bufOffset+i];
|
|
if ( !(pSN->dwVendorID) && pSN->pID[i] && pSN->pID[i] != 0x20 )
|
|
pSN->dwVendorID = MDSP_PMID_SANDISK;
|
|
}
|
|
|
|
if ( !(pSN->dwVendorID) )
|
|
hr=S_FALSE;
|
|
else
|
|
hr=S_OK;
|
|
|
|
Error:
|
|
if ( fileHandle != INVALID_HANDLE_VALUE )
|
|
CloseHandle(fileHandle);
|
|
DebugMsg("GetDeviceSNwithNTScsiPassThrough: returning hr = 0x%x", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT GetMediaSerialNumberFromNTService(DWORD dwDN, PWMDMID pSN)
|
|
{
|
|
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
|
BYTE ubBuf[256];
|
|
BOOL fSuccess;
|
|
DWORD cbRead, cbWritten;
|
|
WCHAR wszPipename[64] = L"\\\\.\\pipe\\WMDMPMSPpipe";
|
|
DWORD dwErr;
|
|
PMEDIA_SERIAL_NUMBER_DATA pMSN;
|
|
HRESULT hr;
|
|
BOOL bStarted = 0;
|
|
|
|
if (dwDN >= 26)
|
|
{
|
|
_ASSERTE(dwDN < 26);
|
|
hr = E_INVALIDARG;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
// Try to open a named pipe; wait for it, if necessary.
|
|
for ( DWORD dwTriesLeft = 3; dwTriesLeft; dwTriesLeft -- )
|
|
{
|
|
// Set the impersonation level to the lowest one that works.
|
|
// The real server impersonates us to validate the drive type.
|
|
// SECURITY_ANONYMOUS is enough for this as long as the drive
|
|
// specified is of the form x: (i.e., is not an ms-dos device name
|
|
// in the DosDevices directory)
|
|
hPipe = CreateFileW(
|
|
wszPipename,
|
|
GENERIC_READ |GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
|
|
NULL
|
|
);
|
|
|
|
// Break if the pipe handle is valid.
|
|
if ( hPipe != INVALID_HANDLE_VALUE )
|
|
{
|
|
// Success
|
|
fSuccess=TRUE;
|
|
break;
|
|
}
|
|
|
|
// If all pipe instances are busy or if server has not yet created
|
|
// the first instance of the named pipe, wait for a while and retry.
|
|
// Else, exit.
|
|
dwErr=GetLastError();
|
|
DebugMsg("GetMediaSerialNumberFromNTService(): CreateFile on drive %u failed, last err = %u, Tries left = %u, bStarted = %d",
|
|
dwDN, dwErr, dwTriesLeft, bStarted);
|
|
if ( dwErr != ERROR_PIPE_BUSY && dwErr != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
fSuccess=FALSE;
|
|
break;
|
|
}
|
|
if (dwErr == ERROR_FILE_NOT_FOUND && !bStarted)
|
|
{
|
|
dwTriesLeft++; // Don't count this iteration
|
|
bStarted = 1;
|
|
|
|
// We start the service here because the service now
|
|
// times out sfter a period of inactivity.
|
|
// We ignore errors. If the start fails, we'll
|
|
// timeout anyway. (If we did respond to errors, note
|
|
// that the service may already be running and that
|
|
// shuld not be considered an error.)
|
|
UtilStartStopService(TRUE);
|
|
|
|
// Wait for service to start
|
|
for (DWORD i = 2; i > 0; i--)
|
|
{
|
|
Sleep(1000);
|
|
if (WaitNamedPipeW(wszPipename, 0))
|
|
{
|
|
// Service is up and running and a pipe instance
|
|
// is available
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Either the service has not yet started or no
|
|
// pipe instance is available. Just keep going.
|
|
}
|
|
}
|
|
|
|
// Even if the wait for the named pipe failed,
|
|
// go on. We'll try once more below and bail out.
|
|
}
|
|
|
|
// All pipe instances are busy (or the service is starting),
|
|
// so wait for 1 second.
|
|
// Note: Do not use NMPWAIT_USE_DEFAULT_WAIT since the
|
|
// server of this named pipe may be spoofing our server
|
|
// and may have the set the default very high.
|
|
if ( ! WaitNamedPipeW(wszPipename, 1000) )
|
|
{
|
|
fSuccess=FALSE;
|
|
break;
|
|
}
|
|
} // end of for loop
|
|
|
|
if ( !fSuccess )
|
|
{
|
|
hr=HRESULT_FROM_WIN32(ERROR_CANTOPEN);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
|
|
ZeroMemory(ubBuf, sizeof(ubBuf));
|
|
pMSN = (PMEDIA_SERIAL_NUMBER_DATA)ubBuf;
|
|
// pMSN->SerialNumberLength = 128;
|
|
pMSN->Reserved[1] = dwDN;
|
|
|
|
DWORD cbTotalWritten = 0;
|
|
|
|
do
|
|
{
|
|
fSuccess = WriteFile(
|
|
hPipe, // pipe handle
|
|
ubBuf + cbTotalWritten, // message
|
|
sizeof(*pMSN)- cbTotalWritten, // +128, // message length
|
|
&cbWritten, // bytes written
|
|
NULL // not overlapped
|
|
);
|
|
|
|
if ( !fSuccess) // || cbWritten != sizeof(*pMSN))
|
|
{
|
|
hr=HRESULT_FROM_WIN32(ERROR_CANTWRITE);
|
|
goto ErrorExit;
|
|
}
|
|
cbTotalWritten += cbWritten;
|
|
_ASSERTE(cbTotalWritten <= sizeof(*pMSN));
|
|
}
|
|
while (cbTotalWritten < sizeof(*pMSN));
|
|
|
|
DWORD cbTotalRead = 0;
|
|
DWORD cbTotalToRead;
|
|
do
|
|
{
|
|
// Read from the pipe.
|
|
fSuccess = ReadFile(
|
|
hPipe, // pipe handle
|
|
ubBuf + cbTotalRead, // buffer to receive reply
|
|
sizeof(ubBuf) - cbTotalRead, // size of buffer
|
|
&cbRead, // number of bytes read
|
|
NULL // not overlapped
|
|
);
|
|
|
|
// This is a byte mode pipe, not a message mode one, so we
|
|
// do not expect ERROR_MORE_DATA. Anyway, let this be as is.
|
|
if ( !fSuccess && (dwErr=GetLastError()) != ERROR_MORE_DATA )
|
|
{
|
|
break;
|
|
}
|
|
cbTotalRead += cbRead;
|
|
_ASSERTE(cbTotalRead <= sizeof(ubBuf));
|
|
|
|
// We expect at least FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData)
|
|
// bytes in the response
|
|
cbTotalToRead = FIELD_OFFSET(MEDIA_SERIAL_NUMBER_DATA, SerialNumberData);
|
|
if (cbTotalRead >= cbTotalToRead)
|
|
{
|
|
pMSN = (PMEDIA_SERIAL_NUMBER_DATA)ubBuf;
|
|
if ( ERROR_SUCCESS == pMSN->Result )
|
|
{
|
|
cbTotalToRead += pMSN->SerialNumberLength;
|
|
}
|
|
else
|
|
{
|
|
cbTotalToRead = sizeof(MEDIA_SERIAL_NUMBER_DATA);
|
|
}
|
|
// Server should write exactly cbTotalToRead bytes.
|
|
// We should not have read any more because
|
|
// we wrote only 1 request. (If we write >1 request, we may
|
|
// get responses to both request.)
|
|
_ASSERTE(cbTotalRead <= cbTotalToRead);
|
|
|
|
if (cbTotalToRead > sizeof(ubBuf))
|
|
{
|
|
// We don't expect this. Server bad?
|
|
fSuccess = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// cbTotalToRead does not have to be changed
|
|
}
|
|
|
|
} while ( !fSuccess || cbTotalRead < cbTotalToRead); // repeat loop if ERROR_MORE_DATA
|
|
|
|
if ( fSuccess )
|
|
{
|
|
pMSN = (PMEDIA_SERIAL_NUMBER_DATA)ubBuf;
|
|
|
|
if ( ERROR_SUCCESS == pMSN->Result &&
|
|
pMSN->SerialNumberLength <= sizeof(pSN->pID))
|
|
{
|
|
CopyMemory(pSN->pID, pMSN->SerialNumberData, pMSN->SerialNumberLength);
|
|
pSN->SerialNumberLength = pMSN->SerialNumberLength;
|
|
pSN->dwVendorID = pMSN->Reserved[1];
|
|
pSN->cbSize = sizeof(*pSN);
|
|
hr=S_OK;
|
|
}
|
|
else if (pMSN->Result != ERROR_SUCCESS)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(pMSN->Result);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr=HRESULT_FROM_WIN32(ERROR_CANTREAD);
|
|
}
|
|
|
|
ErrorExit:
|
|
|
|
if ( hPipe != INVALID_HANDLE_VALUE )
|
|
CloseHandle(hPipe);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT UtilGetHardSN(WCHAR *wcsDeviceName, DWORD dwDriveNum, PWMDMID pSN)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
ULONG i;
|
|
|
|
DebugMsg("Entering UtilGetHardSN, drivenum %u", dwDriveNum);
|
|
CARg(pSN);
|
|
|
|
DWORD dwLastError;
|
|
|
|
if ( IsAdministrator(dwLastError) )
|
|
{
|
|
// Convert device name to an ascii char - done only on Win9x
|
|
char szTmp[MAX_PATH];
|
|
*szTmp = 0;
|
|
|
|
// Following only for NT. If we have a DOS device name, use it.
|
|
// Else, open the drive letter.
|
|
WCHAR wcsDriveName[] = L"\\\\.\\?:";
|
|
|
|
if (dwDriveNum >= 26)
|
|
{
|
|
_ASSERTE(dwDriveNum < 26);
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
LPCWSTR wcsDeviceToOpen = wcsDriveName;
|
|
wcsDriveName[4] = (WCHAR) (dwDriveNum + L'A');
|
|
|
|
// Try IOCTL calls
|
|
if ( IsWinNT() )
|
|
{
|
|
// NT, try IOCTL_GET_MEDIA_SERIAL_NUMBER method first
|
|
hr = GetMSNWithNtIoctl(wcsDeviceToOpen, pSN);
|
|
}
|
|
else
|
|
{
|
|
if ( WideCharToMultiByte(CP_ACP, NULL, wcsDeviceName, -1, szTmp, sizeof(szTmp), NULL, NULL) == 0 )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
// Try two other IOCTL calls on Win9x
|
|
hr = GetMSNWith9xIoctl( szTmp[0], pSN, 0x440D, (0x0800 | 0x75) );
|
|
if ( FAILED(hr) )
|
|
{
|
|
hr = GetMSNWith9xIoctl( szTmp[0], pSN, 0x4404, WIN9X_IOCTL_GET_MEDIA_SERIAL_NUMBER );
|
|
}
|
|
}
|
|
|
|
// Try Iomega
|
|
if ( FAILED(hr) )
|
|
{
|
|
if ( IsIomegaDrive(dwDriveNum) )
|
|
{
|
|
if ( GetIomegaDiskSerialNumber(dwDriveNum, pSN) )
|
|
{
|
|
hr=S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try new SCSI_PASS_THROUGH "Get Media Serial Number" command
|
|
if ( FAILED(hr) )
|
|
{
|
|
if ( IsWinNT() )
|
|
{
|
|
// This was pulled because it was not standardized.
|
|
// hr = GetMediaSNwithNTScsiPassThrough(szTmp, pSN);
|
|
}
|
|
else
|
|
{
|
|
// @@@@ Remove this as well?
|
|
Aspi32Util a32u;
|
|
if ( a32u.DoSCSIPassThrough(szTmp, pSN, TRUE ) )
|
|
{
|
|
hr=S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Last chance, try old 'bad'
|
|
// SCSI_PASS_THROUGH "Get Device Serial Number" command
|
|
if ( FAILED(hr) )
|
|
{
|
|
|
|
// // We are using the DEVICE serial number as a MEDIA serial number.
|
|
// // This violates the SCSI spec. We are only keeping this functionality
|
|
// // for the devices we know that needs it.
|
|
// if( CheckForKBDevice( szTmp[0] ) == FALSE )
|
|
// {
|
|
// hr = E_FAIL;
|
|
// goto Error;
|
|
// }
|
|
|
|
if ( IsWinNT() )
|
|
{
|
|
CHRg(GetDeviceSNwithNTScsiPassThrough(wcsDeviceToOpen, pSN));
|
|
}
|
|
else
|
|
{
|
|
Aspi32Util a32u;
|
|
CFRg( a32u.DoSCSIPassThrough(szTmp, pSN, FALSE ) );
|
|
}
|
|
}
|
|
}
|
|
else if (dwLastError != ERROR_SUCCESS)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwLastError);
|
|
goto Error;
|
|
}
|
|
else // If on NT and nonAdmin, try use PMSP Service
|
|
{
|
|
hr = GetMediaSerialNumberFromNTService(dwDriveNum, pSN);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
// put sanity check here
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
for ( i=0; i<(pSN->SerialNumberLength); i++ )
|
|
{
|
|
if ( pSN->pID[i] && pSN->pID[i] != 0x20 )
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
Error:
|
|
DebugMsg("Leaving UtilGetHardSN, hr = 0x%x");
|
|
return hr;
|
|
}
|
|
|
|
// fCreate is an unused parameter. Ir was used in an obsolete code path that
|
|
// has been deleted
|
|
HRESULT __stdcall UtilGetSerialNumber(WCHAR *wcsDeviceName, PWMDMID pSerialNumber, BOOL fCreate)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
DebugMsg("Entering UtilGetSerialNumber");
|
|
|
|
if (!pSerialNumber || !wcsDeviceName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DWORD dwDriveNum;
|
|
|
|
// We use only the first char of pDeviceName and expect it to
|
|
// be a drive letter. The rest of pDeviceName is not validated.
|
|
// Perhaps it should, but we don't want to break our clients.
|
|
if (wcsDeviceName[0] >= L'A' && wcsDeviceName[0] <= L'Z')
|
|
{
|
|
dwDriveNum = wcsDeviceName[0] - L'A';
|
|
}
|
|
else if (wcsDeviceName[0] >= L'a' && wcsDeviceName[0] <= L'z')
|
|
{
|
|
dwDriveNum = wcsDeviceName[0] - L'a';
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
|
|
pSerialNumber->cbSize = sizeof(WMDMID);
|
|
hr = UtilGetHardSN(wcsDeviceName, dwDriveNum, pSerialNumber);
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
if ( hr != HRESULT_FROM_WIN32(ERROR_INVALID_DATA) )
|
|
{
|
|
pSerialNumber->SerialNumberLength = 0;
|
|
pSerialNumber->dwVendorID = 0;
|
|
ZeroMemory(pSerialNumber->pID, sizeof(pSerialNumber->pID));
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
}
|
|
// hr = S_FALSE;
|
|
}
|
|
|
|
Error:
|
|
DebugMsg("Leaving UtilGetSerialNumber, hr = 0x%x", hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __stdcall UtilStartStopService(bool fStartService)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SERVICE_STATUS ServiceStatus;
|
|
|
|
DWORD dwLastError;
|
|
|
|
if ( IsAdministrator(dwLastError) )
|
|
{
|
|
//
|
|
// We are on Win 9x machine or NT machine with admin previleges. In
|
|
// either case, we don't want to run the service.
|
|
//
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, returning S_OK (IsAdmin returned TRUE)",
|
|
fStartService);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
// We ignore dwLastError
|
|
}
|
|
|
|
// open the service control manager
|
|
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
|
SC_HANDLE hService = NULL;
|
|
|
|
if ( !hSCM )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, OpenSCManager failed, last err (as hr) = 0x%x",
|
|
fStartService, hr);
|
|
goto Error;
|
|
}
|
|
|
|
// open the service
|
|
hService = OpenService(hSCM,
|
|
"WmdmPmSp",
|
|
(fStartService? SERVICE_START : SERVICE_STOP) | SERVICE_QUERY_STATUS);
|
|
|
|
if ( !hService )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, OpenService failed, last err (as hr) = 0x%x",
|
|
fStartService, hr);
|
|
goto Error;
|
|
}
|
|
|
|
if ( !QueryServiceStatus( hService, &ServiceStatus ) )
|
|
{
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, QueryServiceStatus failed, last err (as hr) = 0x%x",
|
|
fStartService, hr);
|
|
goto Error;
|
|
}
|
|
|
|
if ( fStartService && ServiceStatus.dwCurrentState != SERVICE_RUNNING)
|
|
{
|
|
// start the service
|
|
if(!StartService(hService, 0, NULL) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, StartService failed, last err (as hr) = 0x%x",
|
|
fStartService, hr);
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
if(!fStartService && ServiceStatus.dwCurrentState != SERVICE_STOP)
|
|
{
|
|
// stop the service.
|
|
if(!ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, ControlService failed, last err (as hr) = 0x%x",
|
|
fStartService, hr);
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
Error:
|
|
if ( hService )
|
|
{
|
|
CloseServiceHandle(hService);
|
|
}
|
|
if ( hSCM )
|
|
{
|
|
CloseServiceHandle(hSCM);
|
|
}
|
|
DebugMsg("UtilStartStopService(): fStartService = %d, returning hr = 0x%x",
|
|
fStartService, hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|