Getting HDD Serial of C drive.

S

Sin Jeong-hun

Below is the code in Managed C++. It was originally written in C, and
posted somewhere around the Internet (I forgot where I copied this
code), and I changed it into Managed C++. This code returnes the
serial string like "WD-WC1234567" of the hard disk where C drive is
on.

Now, I would like to change this code into C#, but there are so many
API's, structures and macroes. I've searched the Internet for
equivalent C# code but I couldn't find a working one. Is there any
existing C# equivalent code, or do I need to stick to this MC++ code?
Thank you.

static String^ GetHddSerial()
{
String^ test=System::String::Empty;
LPCWSTR damn=L"\\\\.\\c:";
HANDLE hPhysicalDriveIOCTL = CreateFile(damn, GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
NULL);
if(hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
DWORD dwBytesReturned = 0;
//Get Physical Drive Information
VOLUME_DISK_EXTENTS vdExtents;
ZeroMemory(&vdExtents, sizeof(vdExtents));
if(!DeviceIoControl(hPhysicalDriveIOCTL,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,
&vdExtents, sizeof(vdExtents), &dwBytesReturned, NULL))
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Error volumes that
span multiple disks are not supported");
}

//Get SMART version information
GETVERSIONINPARAMS gvopVersionParams;
ZeroMemory(&gvopVersionParams, sizeof(gvopVersionParams));
if(!DeviceIoControl(hPhysicalDriveIOCTL, SMART_GET_VERSION,
NULL, 0,
&gvopVersionParams, sizeof(gvopVersionParams),
&dwBytesReturned, NULL))
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Error cannot get
SMART version information from device");
}

if(gvopVersionParams.bIDEDeviceMap > 0)
{
//Setup SMART request
SENDCMDINPARAMS InParams = {
IDENTIFY_BUFFER_SIZE, { 0, 1, 1, 0, 0,
((vdExtents.Extents[0].DiskNumber & 1) ? 0xB0 : 0xA0),
((gvopVersionParams.bIDEDeviceMap >>
vdExtents.Extents[0].DiskNumber & 0x10) ? ATAPI_ID_CMD : ID_CMD) },
(BYTE)vdExtents.Extents[0].DiskNumber
};

DWORD dwBufSize = sizeof(SENDCMDOUTPARAMS) +
IDENTIFY_BUFFER_SIZE;
PSENDCMDOUTPARAMS pbtIDOutCmd = (PSENDCMDOUTPARAMS) new
BYTE[dwBufSize];
ZeroMemory(pbtIDOutCmd, dwBufSize);

//Get SMART information
if(DeviceIoControl(hPhysicalDriveIOCTL, SMART_RCV_DRIVE_DATA,
&InParams, sizeof(SENDCMDINPARAMS),
pbtIDOutCmd, dwBufSize, &dwBytesReturned, NULL))
{
//Little Endian To Big Endian
USHORT *pIDSector = (USHORT*)pbtIDOutCmd->bBuffer;
for(int nShort = 10; nShort < 21; nShort++)
pIDSector[nShort] = (((pIDSector[nShort] & 0x00FF) << 8) +
((pIDSector[nShort] & 0xFF00) >> 8));

//Get Drive Serial Number
LPSTR lpszSerialNumber1 = new CHAR[21];
ZeroMemory(lpszSerialNumber1, 21);
RtlCopyMemory(lpszSerialNumber1, &pIDSector[10], 20);

//Remove those horrible spaces caused because of endianess
//and print out the serial
LPSTR lpszSerialNumber2 = lpszSerialNumber1;
while(*lpszSerialNumber2 == ' ') lpszSerialNumber2++;
test= gcnew System::String(lpszSerialNumber2);
delete lpszSerialNumber1;
}
delete pbtIDOutCmd;
}
else
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Unknown error");
}
CloseHandle (hPhysicalDriveIOCTL);
}
return test;
}
 
B

Ben Voigt [C++ MVP]

Sin Jeong-hun said:
Below is the code in Managed C++. It was originally written in C, and
posted somewhere around the Internet (I forgot where I copied this
code), and I changed it into Managed C++. This code returnes the
serial string like "WD-WC1234567" of the hard disk where C drive is
on.

Now, I would like to change this code into C#, but there are so many
API's, structures and macroes. I've searched the Internet for
equivalent C# code but I couldn't find a working one. Is there any
existing C# equivalent code, or do I need to stick to this MC++ code?
Thank you.

That's C++/CLI, not Managed Extensions for C++, and you are much better off
using that for Windows API calls than C#. Not only can you use the C
headers intact, avoiding p/invoke declaration bugs, but it's faster as well.
static String^ GetHddSerial()
{
String^ test=System::String::Empty;
LPCWSTR damn=L"\\\\.\\c:";
HANDLE hPhysicalDriveIOCTL = CreateFile(damn, GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
NULL);
if(hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
DWORD dwBytesReturned = 0;
//Get Physical Drive Information
VOLUME_DISK_EXTENTS vdExtents;
ZeroMemory(&vdExtents, sizeof(vdExtents));
if(!DeviceIoControl(hPhysicalDriveIOCTL,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,
&vdExtents, sizeof(vdExtents), &dwBytesReturned, NULL))
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Error volumes that
span multiple disks are not supported");
}

//Get SMART version information
GETVERSIONINPARAMS gvopVersionParams;
ZeroMemory(&gvopVersionParams, sizeof(gvopVersionParams));
if(!DeviceIoControl(hPhysicalDriveIOCTL, SMART_GET_VERSION,
NULL, 0,
&gvopVersionParams, sizeof(gvopVersionParams),
&dwBytesReturned, NULL))
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Error cannot get
SMART version information from device");
}

if(gvopVersionParams.bIDEDeviceMap > 0)
{
//Setup SMART request
SENDCMDINPARAMS InParams = {
IDENTIFY_BUFFER_SIZE, { 0, 1, 1, 0, 0,
((vdExtents.Extents[0].DiskNumber & 1) ? 0xB0 : 0xA0),
((gvopVersionParams.bIDEDeviceMap >>
vdExtents.Extents[0].DiskNumber & 0x10) ? ATAPI_ID_CMD : ID_CMD) },
(BYTE)vdExtents.Extents[0].DiskNumber
};

DWORD dwBufSize = sizeof(SENDCMDOUTPARAMS) +
IDENTIFY_BUFFER_SIZE;
PSENDCMDOUTPARAMS pbtIDOutCmd = (PSENDCMDOUTPARAMS) new
BYTE[dwBufSize];
ZeroMemory(pbtIDOutCmd, dwBufSize);

//Get SMART information
if(DeviceIoControl(hPhysicalDriveIOCTL, SMART_RCV_DRIVE_DATA,
&InParams, sizeof(SENDCMDINPARAMS),
pbtIDOutCmd, dwBufSize, &dwBytesReturned, NULL))
{
//Little Endian To Big Endian
USHORT *pIDSector = (USHORT*)pbtIDOutCmd->bBuffer;
for(int nShort = 10; nShort < 21; nShort++)
pIDSector[nShort] = (((pIDSector[nShort] & 0x00FF) << 8) +
((pIDSector[nShort] & 0xFF00) >> 8));

//Get Drive Serial Number
LPSTR lpszSerialNumber1 = new CHAR[21];
ZeroMemory(lpszSerialNumber1, 21);
RtlCopyMemory(lpszSerialNumber1, &pIDSector[10], 20);

//Remove those horrible spaces caused because of endianess
//and print out the serial
LPSTR lpszSerialNumber2 = lpszSerialNumber1;
while(*lpszSerialNumber2 == ' ') lpszSerialNumber2++;
test= gcnew System::String(lpszSerialNumber2);
delete lpszSerialNumber1;
}
delete pbtIDOutCmd;
}
else
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Unknown error");
}
CloseHandle (hPhysicalDriveIOCTL);
}
return test;
}
 
P

Peter Bromberg [C# MVP]

This article is quite old, but it looks like it has what you want (also
CPUId, MACaddress, etc.)
http://www.eggheadcafe.com/articles/20030511.asp
-- Peter
Site: http://www.eggheadcafe.com
UnBlog: http://petesbloggerama.blogspot.com
MetaFinder: http://www.blogmetafinder.com


Sin Jeong-hun said:
Below is the code in Managed C++. It was originally written in C, and
posted somewhere around the Internet (I forgot where I copied this
code), and I changed it into Managed C++. This code returnes the
serial string like "WD-WC1234567" of the hard disk where C drive is
on.

Now, I would like to change this code into C#, but there are so many
API's, structures and macroes. I've searched the Internet for
equivalent C# code but I couldn't find a working one. Is there any
existing C# equivalent code, or do I need to stick to this MC++ code?
Thank you.

static String^ GetHddSerial()
{
String^ test=System::String::Empty;
LPCWSTR damn=L"\\\\.\\c:";
HANDLE hPhysicalDriveIOCTL = CreateFile(damn, GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
NULL);
if(hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
DWORD dwBytesReturned = 0;
//Get Physical Drive Information
VOLUME_DISK_EXTENTS vdExtents;
ZeroMemory(&vdExtents, sizeof(vdExtents));
if(!DeviceIoControl(hPhysicalDriveIOCTL,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0,
&vdExtents, sizeof(vdExtents), &dwBytesReturned, NULL))
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Error volumes that
span multiple disks are not supported");
}

//Get SMART version information
GETVERSIONINPARAMS gvopVersionParams;
ZeroMemory(&gvopVersionParams, sizeof(gvopVersionParams));
if(!DeviceIoControl(hPhysicalDriveIOCTL, SMART_GET_VERSION,
NULL, 0,
&gvopVersionParams, sizeof(gvopVersionParams),
&dwBytesReturned, NULL))
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Error cannot get
SMART version information from device");
}

if(gvopVersionParams.bIDEDeviceMap > 0)
{
//Setup SMART request
SENDCMDINPARAMS InParams = {
IDENTIFY_BUFFER_SIZE, { 0, 1, 1, 0, 0,
((vdExtents.Extents[0].DiskNumber & 1) ? 0xB0 : 0xA0),
((gvopVersionParams.bIDEDeviceMap >>
vdExtents.Extents[0].DiskNumber & 0x10) ? ATAPI_ID_CMD : ID_CMD) },
(BYTE)vdExtents.Extents[0].DiskNumber
};

DWORD dwBufSize = sizeof(SENDCMDOUTPARAMS) +
IDENTIFY_BUFFER_SIZE;
PSENDCMDOUTPARAMS pbtIDOutCmd = (PSENDCMDOUTPARAMS) new
BYTE[dwBufSize];
ZeroMemory(pbtIDOutCmd, dwBufSize);

//Get SMART information
if(DeviceIoControl(hPhysicalDriveIOCTL, SMART_RCV_DRIVE_DATA,
&InParams, sizeof(SENDCMDINPARAMS),
pbtIDOutCmd, dwBufSize, &dwBytesReturned, NULL))
{
//Little Endian To Big Endian
USHORT *pIDSector = (USHORT*)pbtIDOutCmd->bBuffer;
for(int nShort = 10; nShort < 21; nShort++)
pIDSector[nShort] = (((pIDSector[nShort] & 0x00FF) << 8) +
((pIDSector[nShort] & 0xFF00) >> 8));

//Get Drive Serial Number
LPSTR lpszSerialNumber1 = new CHAR[21];
ZeroMemory(lpszSerialNumber1, 21);
RtlCopyMemory(lpszSerialNumber1, &pIDSector[10], 20);

//Remove those horrible spaces caused because of endianess
//and print out the serial
LPSTR lpszSerialNumber2 = lpszSerialNumber1;
while(*lpszSerialNumber2 == ' ') lpszSerialNumber2++;
test= gcnew System::String(lpszSerialNumber2);
delete lpszSerialNumber1;
}
delete pbtIDOutCmd;
}
else
{
CloseHandle(hPhysicalDriveIOCTL);
throw gcnew System::ApplicationException("Unknown error");
}
CloseHandle (hPhysicalDriveIOCTL);
}
return test;
}
 
Top