728x90
반응형
윈도우 클라이언트를 개발하다 보면 특정 PC의 고유 값을 얻어야 할 때가 있다. 보통 하드디스크 시리얼, Mac 주소 등의 조합으로 하드웨어를 특정 짓는다.
이번에 알아본 방법은 DeviceIoControl를 이용하여 하드디스크 시리얼을 구하는 방법이다.
BOOL GetDiskSerialNumber(CString &szSerialNumber)
{
TCHAR szWindowDir[MAX_PATH] = { 0, };
if (ExpandEnvironmentStrings(_T("%windir%"), szWindowDir, MAX_PATH) == 0)
return FALSE;
szSerialNumber.Empty();
// Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on or '\\\\.\\\\C:').
CString strDrivePath;
strDrivePath.Format(_T("\\\\.\\\\%c:"), szWindowDir[0]);
// call CreateFile to get a handle to physical drive
HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hDevice)
return FALSE;
// set the input STORAGE_PROPERTY_QUERY data structure
STORAGE_PROPERTY_QUERY storagePropertyQuery;
ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY));
storagePropertyQuery.PropertyId = StorageDeviceProperty;
storagePropertyQuery.QueryType = PropertyStandardQuery;
// get the necessary output buffer size
STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = { 0 };
DWORD dwBytesReturned = 0;
if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
&storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
&dwBytesReturned, NULL))
{
::CloseHandle(hDevice);
return FALSE;
}
// allocate the necessary memory for the output buffer
const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
BYTE* pOutBuffer = new BYTE[dwOutBufferSize];
ZeroMemory(pOutBuffer, dwOutBufferSize);
// get the storage device descriptor
if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
pOutBuffer, dwOutBufferSize,
&dwBytesReturned, NULL))
{
delete[]pOutBuffer;
::CloseHandle(hDevice);
return FALSE;
}
// Now, the output buffer points to a STORAGE_DEVICE_DESCRIPTOR structure
// followed by additional info like vendor ID, product ID, serial number, and so on.
STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer;
const DWORD dwProductIdOffset = pDeviceDescriptor->ProductIdOffset;
if (dwProductIdOffset != 0) {
TCHAR *szVMProductName[] = { _T("Virtual HD"), NULL };
CString szProductName = CString(pOutBuffer + dwProductIdOffset);
wprintf(L"ProductId : %s\n", szProductName.GetBuffer(0));
BOOL bVM = FALSE;
for (INT i = 0; szVMProductName[i] != '\0'; ++i) {
if (_tcsnicmp(szProductName.GetBuffer(0), szVMProductName[i], _tcslen(szVMProductName[i])) == 0)
bVM = TRUE;
/*if (szProductName.CompareNoCase(szVMProductName[i]) == 0)
bVM = TRUE;*/
}
if (bVM == TRUE) {
delete[]pOutBuffer;
::CloseHandle(hDevice);
return FALSE;
}
}
const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
if (dwSerialNumberOffset != 0)
{
// finally, get the serial number
szSerialNumber = CString(pOutBuffer + dwSerialNumberOffset);
szSerialNumber.Trim();
}
else {
delete[]pOutBuffer;
::CloseHandle(hDevice);
return FALSE;
}
// perform cleanup and return
delete[]pOutBuffer;
::CloseHandle(hDevice);
return TRUE;
}
물론 하드디스크 시리얼은 WMI등으로도 구할 수 있다.
참고로 가상머신 같은 일부 PC에서는 정확히 값을 얻어 낼 수 없다.
728x90
반응형
'개발 > Windows' 카테고리의 다른 글
[C++/WinRT] 윈도우C++프로젝트에서 json파싱하기 (0) | 2024.11.23 |
---|---|
[WTL] Visual studio 2022에서 WTL Wizard 설치하기 (1) | 2024.08.26 |
[WinUI3/c++] 창 사이즈 변경하기 (0) | 2024.08.17 |
Openssl Windows용 빌드 하기(Openssl 3.0) + jom 병렬 빌드하기 (0) | 2024.07.20 |
[Winui3] Unpackaged 프로젝트로 설정하기 (0) | 2024.05.26 |
댓글