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

4 則留言:

蕭沖 提到...

請問你的系統是否為 x64 os?

匿名 提到...

版主, 你好:
剛好在找取得PhysicalDirve的方法, 看到你的方法, 謝謝了!!
我試了用MSDN原始的定義是可行的(我用BCB6.0), 不過PhysicalDrive的代號應該是在VOLUME_DISK_EXTENTS裏的Extents[0].DiskNumber, 而且邏輯磁碟機的磁區應該要分佈在同一個PhysicalDrive,例如: 同一個硬碟裏的C,D.., 根據MSDN的說法, 如果邏輯磁碟機的磁區分佈在不同的Physical Drive, 則DeviceIoControl會傳回FALSE, 然後用GetLastError()可能會得到ERROR_MORE_DATA, 此時就要更改傳入DeviceIoControl的Output Buf, 然後重新呼叫一次, 不過這種分割方式,一般好像比較少用...
以下是我測試用的Code...

/**
找出邏輯磁碟機對應的實體磁碟機代號
傳入值:
DriveLetter: 邏輯磁碟機的符號, 如; C, D, E...
DiskNum : 傳回的實體磁碟機代號, 如果要進一步用CreateFile()開啟實體磁碟
機, 可用"\\\\.\\PHYSICALDRIVEn", 做為第一個參數, 其中n就是
DiskNum
傳回值:
成功傳回true, 實體磁碟機的代號放在DiskNum, 否則傳回false

Note:
1. 根據MSDN的說明, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS傳回的
VOLUME_DISK_EXTENTS結構裏 , NumberOfDiskExtents表示此邏輯磁碟機"分佈"
的實體磁碟機數量, 一般來說, 此值應該為1, 表示傳入的邏輯磁碟機的磁區均
位於同一顆實體磁碟中, 例如: 一顆硬碟分割成C,D,E三槽, 則用C,D,E傳入此
函式時, 得到的 DiskExtent.Extents[0].DiskNumber應該相同

2. 如果邏輯磁碟機的磁區分佈於不同的實體磁碟機, 則NumberOfDiskExtents的
值不為1, 而DeviceIoControl()失敗後, 呼叫 GetLastError()應該會傳回
ERROR_MORE_DATA, 此時要修正傳入 DeviceIoControl 的Output Buffer大小,

3. 此函式只處理第一種狀況, 第二種狀況就當做fail
*/
bool GetPhysicalDisk(char DriveLetter, DWORD &DiskNum)
{
VOLUME_DISK_EXTENTS DiskExtent;

HANDLE hDrive;
DWORD BytesRet;
BOOL Success;
char DriveStr[]="\\\\.\\X:";

DriveStr[4] = DriveLetter;

hDrive = ::CreateFile( DriveStr,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );

Success = FALSE;
DiskNum = -1;

if (hDrive != INVALID_HANDLE_VALUE)
{
Success = ::DeviceIoControl( hDrive, // handle to device
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
&DiskExtent, // output buffer
sizeof(DiskExtent), // size of output buffer
&BytesRet, // number of bytes returned
NULL); // OVERLAPPED structure
if (Success)
DiskNum = DiskExtent.Extents[0].DiskNumber;

::CloseHandle(hDrive);
}
return (bool)Success;
}

匿名 提到...

真愛旅舍視頻聊天室
真愛旅舍視頻聊天室
真愛旅舍視頻聊天室
6699視訊美女
上海聊天室交友
視訊美女聊天交友
視訊網絡聊天室第九視頻
九聊視頻
異性視頻交友
男人女人做愛視頻
視訊1905電影網在線觀看
電影在線觀看免費網
土豆網電影在線觀看
愛上擼綜合成人網
色人居情色網
亞洲xooo8綜合成人社區
人妻管理員2視頻
天天色成人綜合網
成人小說在線視頻
90後成人色情圖片
成人色系電影
狼群影院
伊人成人影院
久久色悠悠綜合網
天天色綜合區
操一操電影
色夜AV影院
色AV成人網
狼群影院
色也色
哥也色蝴蝶谷
咪咪影院
情色咪咪網
酒色網
一一成人電影網
青色波波首頁
成人人妻小說
有色成人網
成人黃色三級片電影
色妹妹電影院
色姐姐綜合網
歐美成人影院
色小姐成人影院
歡樂吧視頻聊天室-真人秀視頻聊天室
哪個視頻聊天室最開放-熟女倫理性愛自拍圖片論壇
CF視頻聊天室-成熟女人做愛成人交友網
179視頻聊天室-女性異性按摩視頻
比較開放的視頻聊天室-九聊語音視頻聊天
視頻交友互動平台-人人碰人人摸視頻
我秀視頻聊天-超碰人人摸網在線視頻
我秀美女主播-胖老婆人人摸視頻
我秀聊天室-馬上色在視頻網
六間房視頻聊天室-色視頻高清在線觀看
163聊免費聊天室-真人美女黃片視頻
天上人間聊天視頻-日本毛片視頻在線觀看
QQ真人視訊交友網-免費A片網站
QQ愛真人視頻交友聊天室-完全免費在線AV視頻
免費成人視頻FC2視頻-免費A片網站
人人碰免費視頻-完全免費在線AV視頻
人人碰成人社區-毛片群視頻
人人碰在線視頻-免費毛片快播A片
超碰人人碰視頻-韓國毛片視頻高清
夫妻視頻的qq群-成人快播毛片網站

Unknown 提到...

視頻交友秀
色群視頻秀
時裝秀視頻
視頻秀網盤
視頻秀
免費寂寞交友聊天
大秀視頻
視頻秀聊天室
QQ群視頻
視頻秀場
夜店之王視頻秀插件
一對一視頻交友
視訊交友0214
視訊聊天交友網
國外視頻交友聊天網
真愛旅舍
真愛旅舍聊天室
真愛旅舍聊天室破解
真愛旅舍第一
真愛旅舍視頻聊天
真愛旅舍破解
真愛旅舍視頻破解
真愛旅舍視頻網破解
聊天室VIP破解
泰國真愛視頻
視訊堂
交友網站約炮
國外隨機視頻聊天網
免費國外視頻聊天網
全球隨機視頻聊天網
全球隨機視頻網
免費寂寞交友聊天
國外視頻網站你懂的
國外視頻交友聊天
國外視頻
國外在線視頻聊天
視頻吧聊天交友網
影音視訊聊天室
同城交友網只為性
床友交友
視訊聊天室
國外視訊聊天室
韓國kenzo的視訊聊天
視訊聊天MFC
誰有視頻聊天網
同城夜情交友網
視頻聊天網
寂寞聊天交友網站
秀吧視頻社區
都秀
三聊視頻聊天網