windows的磁碟操作之九——區分本地磁碟與移動硬碟

來源:互聯網
上載者:User
原創作品,允許轉載,轉載時請務必以超連結形式標明文章
原始出處 、作者資訊和本聲明。否則將追究法律責任。http://cutebunny.blog.51cto.com/301216/674443

最近碰到了個新問題,記錄下來作為windows的磁碟操作那個系列的續篇吧。

一些時候我們的程式需要區分本機存放區裝置和USB存放裝置。在網上搜一搜一般會找到一個最直接的API,GetDriveType,其原型為UINT GetDriveType(LPCTSTR lpRootPathName)參數lpRootPathName是存放裝置的根目錄,例如C:\,傳回值即為裝置類型。

Return code Description
DRIVE_REMOVABLE The drive has removable media; for example, a floppy drive, thumb drive, or flash card reader.
DRIVE_FIXED The drive has fixed media; for example, a hard drive or flash drive.
或者採用一種稍微複雜一點的方法,使用我們第一節http://cutebunny.blog.51cto.com/301216/624027中介紹的GetDriveGeometry()函數,其輸出參數DISK_GEOMETRY
*pdg中的MediaType欄位代表裝置類型。typedef enum _MEDIA_TYPE{…RemovableMediaFixedMedia…}MEDIA_TYPE; 這兩個方法看似能方便快捷的解決我們的需求,但事實上當你使用GetDriveType()去擷取一塊移動硬碟的類型時,程式會坑爹的告訴你這塊移動硬碟的類型是DRIVE_FIXED,根本無法與本地磁碟區分開來。GetDriveGeometry()函數的結果也是如此。事實上,上述方法只對小容量的隨身碟有效,會返回給你DRIVE_REMOVABLE的結果;而對移動硬碟甚至是一塊稍大容量的隨身碟(比如我有一塊格式化為FAT32格式的4G
隨身碟),就無能為力了。 所以,我們必須採用別的思路了,這裡我介紹一種通過查看匯流排類型來區分本地磁碟和USB磁碟的方法。當然,其基礎還是我們那萬能的DeviceIoControl,不過這次的控制碼為IOCTL_STORAGE_QUERY_PROPERTY。同時對應的輸入參數為STORAGE_PROPERTY_QUERY結構,輸出參數為STORAGE_DEVICE_DESCRIPTOR結構體。typedef struct _STORAGE_PROPERTY_QUERY {
  STORAGE_PROPERTY_ID  PropertyId;
  STORAGE_QUERY_TYPE  QueryType;
  UCHAR  AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;調用時需設定輸入參數中的欄位PropertyId = StorageDeviceProperty;QueryType = PropertyStandardQuery;以表明我們要查詢一個device descriptor,也就是說,只有指定這種類型,輸出參數才會得到STORAGE_DEVICE_DESCRIPTOR類型資料。typedef struct _STORAGE_DEVICE_DESCRIPTOR {
  ULONG  Version;
  ULONG  Size;
  UCHAR  DeviceType;
  UCHAR  DeviceTypeModifier;
  BOOLEAN  RemovableMedia;
  BOOLEAN  CommandQueueing;
  ULONG  VendorIdOffset;
  ULONG  ProductIdOffset;
  ULONG  ProductRevisionOffset;
  ULONG  SerialNumberOffset;
  STORAGE_BUS_TYPE  BusType;
  ULONG  RawPropertiesLength;
  UCHAR  RawDeviceProperties[1];
} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;其中,BusType定義為typedef enum _STORAGE_BUS_TYPE {
  BusTypeUnknown = 0x00,
  BusTypeScsi,
  BusTypeAtapi,
  BusTypeAta,
  BusType1394,
  BusTypeSsa,
  BusTypeFibre,
  BusTypeUsb,
  BusTypeRAID,
  BusTypeiScsi,
  BusTypeSas,
  BusTypeSata,
  BusTypeSd,
  BusTypeMmc,
  BusTypeMax,
  BusTypeMaxReserved = 0x7F
} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;明白了吧,如果匯流排類型為BusTypeUsb,就是找到了我們的USB移動硬碟了。但此時還需要解決一個問題,STORAGE_DEVICE_DESCRIPTOR可以理解為一個變長緩衝區,最後一個欄位RawDeviceProperties[1]是可以動態擴充的(windows
API經常有這種情況),那麼函數DeviceIoControl()中的參數nOutBufferSize應該填多少呢?這時我們需要藉助另一個資料結構STORAGE_DESCRIPTOR_HEADER,在我們不知道device
descriptor實際需要多大的緩衝區時,可以先把STORAGE_DESCRIPTOR_HEADER作為輸出參數以獲得device descriptor的緩衝區大小,其大小被存入header的size欄位中。typedef struct _STORAGE_DESCRIPTOR_HEADER {
  ULONG  Version;
  ULONG  Size;
} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER; 以下是具體代碼/******************************************************************************* Function: get the bus type of an disk* input: drive name (c:)* output: bus type* return: Succeed, 0*         Fail, -1******************************************************************************/DWORD GetDriveTypeByBus(const CHAR *drive, WORD *type){    HANDLE hDevice;               // handle to the drive to be examined    BOOL result;                 // results flag    DWORD readed;                   // discard results     STORAGE_DESCRIPTOR_HEADER *pDevDescHeader;    STORAGE_DEVICE_DESCRIPTOR *pDevDesc;    DWORD devDescLength;    STORAGE_PROPERTY_QUERY query;     hDevice = CreateFile(                    drive, // drive to open                    GENERIC_READ | GENERIC_WRITE,     // access to the drive                    FILE_SHARE_READ | FILE_SHARE_WRITE, //share mode                    NULL,             // default security attributes                    OPEN_EXISTING,    // disposition                    0,                // file attributes                    NULL            // do not copy file attribute                    );    if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive    {        fprintf(stderr, "CreateFile() Error: %ld\n", GetLastError());        return DWORD(-1);    }     query.PropertyId = StorageDeviceProperty;    query.QueryType = PropertyStandardQuery;     pDevDescHeader = (STORAGE_DESCRIPTOR_HEADER *)malloc(sizeof(STORAGE_DESCRIPTOR_HEADER));    if (NULL == pDevDescHeader)    {        return (DWORD)-1;    }        result = DeviceIoControl(                    hDevice,     // device to be queried                    IOCTL_STORAGE_QUERY_PROPERTY,     // operation to perform                    &query,                    sizeof query,               // no input buffer                    pDevDescHeader,                    sizeof(STORAGE_DESCRIPTOR_HEADER),     // output buffer                    &readed,                 // # bytes returned                    NULL);      // synchronous I/O    if (!result)        //fail    {        fprintf(stderr, "IOCTL_STORAGE_QUERY_PROPERTY Error: %ld\n", GetLastError());        free(pDevDescHeader);        (void)CloseHandle(hDevice);        return DWORD(-1);    }     devDescLength = pDevDescHeader->Size;    pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(devDescLength);    if (NULL == pDevDesc)    {        free(pDevDescHeader);        return (DWORD)-1;    }     result = DeviceIoControl(                    hDevice,     // device to be queried                    IOCTL_STORAGE_QUERY_PROPERTY,     // operation to perform                    &query,                    sizeof query,               // no input buffer                    pDevDesc,                    devDescLength,     // output buffer                    &readed,                 // # bytes returned                    NULL);      // synchronous I/O    if (!result)        //fail    {        fprintf(stderr, "IOCTL_STORAGE_QUERY_PROPERTY Error: %ld\n", GetLastError());        free(pDevDescHeader);        free(pDevDesc);        (void)CloseHandle(hDevice);        return DWORD(-1);    }     //printf("%d\n", pDevDesc->BusType);    *type = (WORD)pDevDesc->BusType;    free(pDevDescHeader);    free(pDevDesc);     (void)CloseHandle(hDevice);    return 0;} 代碼說明:1. 調用CreateFile開啟並獲得裝置控制代碼。2. 在輸入參數STORAGE_PROPERTY_QUERY query中指定查詢類型。3. 以STORAGE_DESCRIPTOR_HEADER *pDevDescHeader為輸出參數,叫用作業碼為IOCTL_STORAGE_QUERY_PROPERTY的DeviceIoControl函數獲得輸出緩衝區大小。4. 按3中獲得的緩衝區大小為STORAGE_DEVICE_DESCRIPTOR *pDevDesc分配空間,以pDevDesc為輸出參數,叫用作業碼為IOCTL_STORAGE_QUERY_PROPERTY的DeviceIoControl函數獲得device
descriptor。5. 從device descriptor中獲得BusType。 

本文出自 “bunny技術坊” 部落格,請務必保留此出處http://cutebunny.blog.51cto.com/301216/674443

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.