USB Flash 的資料存取方式, 以邏輯上來看和硬碟是相同的, 也就是由一個個
磁區所組成, 因此當要存取 USB Flash 裏的任一個磁區的資料時, 就需要把
USB Flash 的實際磁碟機代號找出來, 再用 CreateFile 去打開, 就可以存取
任意的磁區了, 方法如下:
1.GetDriveType 判斷邏輯磁碟機是否為 Removable.
(這裏的邏輯磁碟機指的是使用者看到的代號, 如 "D:\", "E:\" 等)
2.GetVolumeNameForVolumeMountPoint 把這個邏輯磁碟機的 GUID 找出來
3.CreateFile, 第一個參數使用剛剛找到的 GUID, 產生一個 handle
4.DeviceIoControl, HANDLE 當然是用剛才產生的 handle, dwIoControlCode
使用 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 成功後, 傳回的結構
VOLUME_DISK_EXTENTS.NumberOfDiskExtents 就是實際磁碟代號了
實際上在使用這個 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 時, 有發現
OS 所回的結構和 MSDN 上講的不同, MSDN 的如下:
typedef struct _DISK_EXTENT
{
ULONG DiskNumber;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER ExtentLength;
} DISK_EXTENT, *PDISK_EXTENT;
typedef struct _VOLUME_DISK_EXTENTS
{
ULONG NumberOfDiskExtents;
DISK_EXTENT Extents[1];
} VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;
但實際我測試結果如下:
typedef struct _my_DISK_EXTENT {
DWORD DiskNumber;
DWORD rr; // 多出來的
LARGE_INTEGER StartingOffset;
LARGE_INTEGER ExtentLength;
} my_DISK_EXTENT;
typedef struct _my_VOLUME_DISK_EXTENTS {
DWORD NumberOfDiskExtents;
DWORD r1; // 多出來的
my_DISK_EXTENT Extents[1];
} my_VOLUME_DISK_EXTENTS, *my_PVOLUME_DISK_EXTENTS;
不知是我對MSDN有誤解或看不懂, 試了 XP & Vista 後, 都需要用我修改過
的結構才能正確的得到回傳值, 不知是否有人能幫我解釋一下, 問題在那
程式碼:
char drv_name[64],guidbuf[512];
for(i=0; i<23;i++>
{
// format the drive name from "D"
sprintf_s(drv_name, sizeof drv_name, "%c:\\", i+0x44);
// if the drive is removable device?
if(GetDriveType(drv_name) == DRIVE_REMOVABLE)
{
if(GetVolumeNameForVolumeMountPoint(drv_name,
&guidbuf[0], sizeof guidbuf))
{
HANDLE hDrv,hDrv2;
DWORD dReturn;
my_VOLUME_DISK_EXTENTS my_vd_ex;
guidbuf[strlen(guidbuf)-1]=0; // mask last "\"
// create the volume's handle by specify GUID
hDrv = CreateFile(guidbuf, GENERIC_READ, FILE_READ_DATA FILE_WRITE_DATA, 0, OPEN_EXISTING, 0, 0 );
if(hDrv != INVALID_HANDLE_VALUE) // if open success?
{
// get the volume's extent information
if(DeviceIoControl(hDrv, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &my_vd_ex, sizeof my_vd_ex, &dReturn, 0))
{
...
...
}
}
}
}
}