I've written a class that resembles a hard drive. I'm already able using the Windows API to get information such as the remaining free bytes, the sectors and clusters,a nd it all works fine.
The last step that I need is to obtain the serial number of the harddrive in question. From what I can understand in the MSDN library you need to take into account that a Volume can span multiple disks etc, but I don't wanne waste time on that right now, I'd just be happy if I can read the serial number of a single disk.
That kept in mind, i've written a function that retrieves all the data I need, i'm just a bit scared about the part for retrieving the serial. I've read somewhere that I need a VOLUME_DISK_EXTENTS structure and use a 20bytes offset and 20 bytes length to read the serial number.
I've come up with this code so far:
Expand|Select|Wrap|Line Numbers
- bool BigBrother::IO::Drive::LoadDriveData() const
- {
- // Create the return values
- bool ResultOne, ResultTwo, ResultThree;
- // Create the UNC compatible root of the drive.
- AnsiString root = AnsiString(mDriveLetter) + ":\\";
- // Set all the datamembers to 0 first, so that we have clean
- // values to work with.
- mSectorsPerCluster = 0;
- mBytesPerSector = 0;
- mFreeClusters = 0;
- mTotalClusters = 0;
- mTotalBytes = 0;
- mFreeBytes = 0;
- // Use the Windows API to fill the datamembers. Store the result
- // of the API call in a boolean.
- ResultOne = ::GetDiskFreeSpace(root.c_str(), &mSectorsPerCluster, &mBytesPerSector, &mFreeClusters, &mTotalClusters);
- ResultTwo = ::GetDiskFreeSpaceEx(root.c_str(), 0, (_ULARGE_INTEGER *)&mTotalBytes, (_ULARGE_INTEGER *)&mFreeBytes);
- // Calculate the AllocationUnitSiwe of the disk.
- mAllocationUnitSize = (mBytesPerSector * mSectorsPerCluster);
- // Create the string to point to our device.
- AnsiString DeviceString = "\\\\.\\" + AnsiString(mDriveLetter) + ":";
- // Create a handle to our drive, so we can pass this further down in the
- // Windows API to retrieve the windows Serial.
- HANDLE DriveHandle = ::CreateFileA(DeviceString.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ |FILE_SHARE_WRITE, OPEN_EXISTING, 0, 0);
- // Check if the handle is valid before continuing down this path.
- if(DriveHandle != INVALID_HANDLE_VALUE)
- {
- // Create a COLUME_DISK_EXTENTS structure and read the info about the drive.
- VOLUME_DISK_EXTENTS VolumeInfo;
- long BytesRead;
- ResultThree = ::DeviceIoControl(DriveHandle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &VolumeInfo, sizeof(VolumeInfo), &BytesReturned, 0);
- // Copy the serial number to our datamember.
- // We need to offset the extend with 20 and read a length of 20 bytes to get the entire serial.
- memcpy(&mSerial, VolumeInfo->StartingOffset + 0x20, 0x20);
- }
- // Return the logical result of the Windows API calls.
- return (ResultOne && ResultTwo);
- }