顯示具有 技術文章 標籤的文章。 顯示所有文章
顯示具有 技術文章 標籤的文章。 顯示所有文章

2008年5月13日 星期二

如何偵測 USB Flash 的實際磁碟機(Physical Drive)代號

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))
{
...
...
}
}
}
}
}