A customer approached me recently to ask if I had any code that demonstrated how to use STORAGE_IDENTIFICATION, which is the data structure used to get the Storage ID from a disk. I didn’t have anything, which of course sends me off writing code and blogging about it.
Simple enough, right? Go read the documentation for STORAGE_IDENTIFICATION which lead me to IOCTL_DISK_GET_STORAGEID. Except that the documentation for IOCTL_DISK_GET_STORAGEID seems to have a problem. The most obvious problem is that it shows how to call CreateFile() to get the handle to use with DeviceIoControl(), but doesn’t show how to call DeviceIoControl(). That is odd, but not really a problem. But, the call to CreateFile() seems to be wrong, or at least it was in my testing.
The documentation shows the call to be:
hVolume = CreateFile(TEXT("\Storage Card\Vol:"), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
I tried that, but my testing with an SD card mounted as Storage Card failed on the call to CreateFile(). I tried several variations of this, but none worked. Then I remembered that some time ago I wrote an article about enumerating the disks (Windows CE: Displaying Disk Information). I pulled up that code and tried again with both the disk device name and the partition volume name. The disk device name worked. The device names are DSKx:, where x is the disk number.
I created the following function to output the Manufacturer ID and Serial Number returned from IOCTL_DISK_GET_STORAGEID:
#include "windows.h"
#include "Diskio.h"
BOOL DisplayDiskID( TCHAR *Disk )
{
STORAGE_IDENTIFICATION *StoreID = NULL;
STORAGE_IDENTIFICATION GetSizeStoreID;
DWORD dwSize;
HANDLE hVol;
TCHAR VolumeName[MAX_PATH];
TCHAR *ManfID;
TCHAR *SerialNumber;
BOOL RetVal = FALSE;
DWORD GLE;
// Note that either of the following works
//_stprintf(VolumeName, _T("\\%s\\Vol:"), Disk);
_stprintf(VolumeName, _T("\\%s"), Disk);
hVol = CreateFile( Disk, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if( hVol != INVALID_HANDLE_VALUE )
{
if(DeviceIoControl(hVol, IOCTL_DISK_GET_STORAGEID, (LPVOID)NULL, 0, &GetSizeStoreID, sizeof(STORAGE_IDENTIFICATION), &dwSize, NULL) == FALSE)
{
GLE = GetLastError();
if( GLE == ERROR_INSUFFICIENT_BUFFER )
{
StoreID = (STORAGE_IDENTIFICATION *)malloc( GetSizeStoreID.dwSize );
if(DeviceIoControl(hVol, IOCTL_DISK_GET_STORAGEID, (LPVOID)NULL, 0, StoreID, GetSizeStoreID.dwSize, &dwSize, NULL) != FALSE)
{
RETAILMSG( 1, (TEXT("DisplayDiskID: Flags %X\r\n"), StoreID->dwFlags ));
if( !(StoreID->dwFlags & MANUFACTUREID_INVALID) )
{
ManfID = (TCHAR *)((DWORD)StoreID + StoreID->dwManufactureIDOffset);
RETAILMSG( 1, (TEXT("DisplayDiskID: Manufacture ID %s\r\n"), ManfID ));
}
if( !(StoreID->dwFlags & SERIALNUM_INVALID) )
{
SerialNumber = (TCHAR *)((DWORD)StoreID + StoreID->dwSerialNumOffset);
RETAILMSG( 1, (TEXT("DisplayDiskID: Serial Number %s\r\n"), SerialNumber ));
}
RetVal = TRUE;
}
else
RETAILMSG( 1, (TEXT("DisplayDiskID: DeviceIoControl failed (%d)\r\n"), GLE));
free(StoreID);
}
else
RETAILMSG( 1, (TEXT("No Disk Identifcation available for %s\r\n"), VolumeName ));
}
else
RETAILMSG( 1, (TEXT("DisplayDiskID: DeviceIoControl succeeded (and shouldn't have)\r\n")));
CloseHandle (hVol);
}
else
RETAILMSG( 1, (TEXT("DisplayDiskID: Failed to open volume (%s)\r\n"), VolumeName ));
return RetVal;
}
Further testing showed that both \DSKx: and \DSKx:\Vol: work when calling CreateFile();
Copyright © 2010 – Bruce Eitman
All Rights Reserved