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.
The last problem is that the dwFlags flag is wrong Manufacturer ID in the STORAGE_IDENTIFICATION documentation. It documents MANUFACTURERID_INVALID but the actual flag is  MANUFACTUREID_INVALID. Look very closely, there is a missing ‘R’.
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"
 
void RETAILMSG_ASCII(char *Str, DWORD NumChars)
{
                DWORD Index;
 
                for( Index = 0; *Str != '\0' && Index < NumChars; Index++ )
                {
                                RETAILMSG( 1, (TEXT("%c"), *Str++));
                }
}
 
BOOL DisplayDiskID( TCHAR *Disk )
{
                STORAGE_IDENTIFICATION *StoreID = NULL;
                STORAGE_IDENTIFICATION GetSizeStoreID;
                DWORD dwSize;
                HANDLE hVol;
                TCHAR VolumeName[MAX_PATH];
                char *ManfID;
                char *SerialNumber;
                BOOL RetVal = FALSE;
                DWORD GLE;
 
                //_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)
                                                                {
                                                                                if( !(StoreID->dwFlags & MANUFACTUREID_INVALID) )
                                                                                {
                                                                                                ManfID = (char *)((DWORD)StoreID + StoreID->dwManufactureIDOffset);
                                                                                                RETAILMSG( 1, (TEXT("DisplayDiskID: Manufacture ID ")));
                                                                                                RETAILMSG_ASCII( ManfID, StoreID->dwSerialNumOffset - StoreID->dwManufactureIDOffset);
                                                                                                RETAILMSG( 1, (TEXT("\r\n")));
                                                                                }
                                                                                if( !(StoreID->dwFlags & SERIALNUM_INVALID) )
                                                                                {
                                                                                                SerialNumber = (char *)((DWORD)StoreID + StoreID->dwSerialNumOffset);
                                                                                                RETAILMSG( 1, (TEXT("DisplayDiskID: Serial Number ")));
                                                                                                RETAILMSG_ASCII( SerialNumber, GetSizeStoreID.dwSize - StoreID->dwSerialNumOffset );
                                                                                                RETAILMSG( 1, (TEXT("\r\n")));
                                                                                }
                                                                                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;
}

Note that the manufature ID and serial number are ASCII strings, so I included a little function to output those on the debug serial port.  I also found that some of the memory card drivers don't handle the strings very well, so I had to limit the strings by length rather than by looking for the null character.

Further testing showed that both \DSKx: and \DSKx:\Vol: work when calling CreateFile();

 
Copyright © 2010 – Bruce Eitman
All Rights Reserved