實戰DeviceIoControl系列 之一:通過API訪問裝置驅動程式

來源:互聯網
上載者:User

Q:在 NT/2000/XP 中,我想用 VC 編寫應用程式訪問硬體裝置,如擷取磁碟參數、讀寫絕對扇區資料、測試光碟機實際
速度等,該從哪裡入手呢?

A:

在 NT/2000/XP 中,應用程式可以通過 API 函數 DeviceIoControl
來實現對裝置的訪問—擷取資訊,發送命令,交換資料等。利用該介面函數向指定的裝置驅動發送正確的控制碼及資料,然
後分析它的響應,就可以達到我們的目的。 

 

DeviceIoControl 的函數原型為:
BOOL DeviceIoControl(
                     HANDLE hDevice, // 裝置控制代碼
                     DWORD dwIoControlCode, // 控制碼
                     LPVOID lpInBuffer, // 輸入資料緩衝區指標
                     DWORD nInBufferSize, // 輸入資料緩衝區長度
                     LPVOID lpOutBuffer, // 輸出資料緩衝區指標
                     DWORD nOutBufferSize, // 輸出資料緩衝區長度
                     LPDWORD lpBytesReturned, // 輸出資料實際長度單元長度
                     LPOVERLAPPED lpOverlapped // 重疊操作結構指標
                     );

  裝置控制代碼用來標識你所訪問的裝置。

  
發送不同的控制碼,可以調用裝置驅動程式的不同類型的功能。在標頭檔winioctl.h 中,預定義的標準裝置控制碼,都以
IOCTL 或 FSCTL 開頭。例如,IOCTL_DISK_GET_DRIVE_GEOMETRY
是對物理磁碟機取結構參數(介質類型、柱面數、每柱面磁軌數、每磁軌扇區數等)的控制碼,FSCTL_LOCK_VOLUME
是對邏輯磁碟機的卷加鎖的控制碼。

  輸入輸出資料緩衝區是否需要,是何種結構,以及佔多少位元組空間,完全由不同裝置的不同操作類型決定。在標頭檔 winioctl.h 中,已經為標準裝置預定義了一些輸入輸出資料結構。重疊操作結構指標設定
為 NULL,DeviceIoControl 將進行阻塞調用;否則,應在編程時按非同步作業設計。

 

Q: 裝置控制代碼是從哪裡獲得的?

A:

裝置控制代碼可以用 API
函數 CreateFile 獲得。它的原型為:

HANDLE CreateFile(
                  LPCTSTR lpFileName, // 檔案名稱
                  DWORD dwDesiredAccess, // 訪問方式 DWORD dwShareMode, // 共用方式
                  LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全性描述元指標
                  DWORD dwCreationDisposition, // 建立方式
                  DWORD dwFlagsAndAttributes, // 檔案屬性及標誌
                  HANDLE hTemplateFile // 模板檔案的控制代碼
                  );

CreateFile
這個函數用處很多,這裡我們用它“開啟”裝置驅動程式,得到裝置的控制代碼。操作完成後用 CloseHandle 關閉裝置控制代碼。

與普通檔案名稱有所不同,裝置驅動的“檔案名稱”形式固定為“.DeviceName”(注意在 C 程式中該字串寫法為“.DeviceName”),DeviceName 必須與裝置驅動程式內規定的裝置名稱一致。

  一般地,調用
CreateFile 獲得裝置控制代碼時,訪問方式參數設定為 0 或GENERIC_READ|GENERIC_WRITE,共用方式參數設定為

  FILE_SHARE_READ|FILE_SHARE_WRITE,建立方式參數設定為 OPEN_EXISTING,其它參數設定為 0 或 NULL。

 

Q: 可是,我怎麼知道裝置名稱是什麼呢?

A:

一些存放裝置的名稱是微軟規定好的,不可能有什麼變化。大體列出如下

  軟碟機 A:, B:

  邏輯磁碟機 C:,
D:, E:, ……

  物理磁碟機 PHYSICALDRIVEx

  CD-ROM, DVD/ROM CDROMx

 
 磁帶機 TAPEx

  其中,物理磁碟機不包括軟碟機和光碟機。邏輯磁碟機可以是 IDE/SCSI/PCMCIA/USB介面的硬碟分區(卷)、光碟機、MO、CF 卡等,甚至是虛擬盤。x=0,1,2 ……

  其它的裝置名稱需通過驅動介面的 GUID
調用裝置管理函數族取得,這裡暫不討論。

 

Q:請舉一個簡單的例子說明如何通過DeviceIoControl
訪問裝置驅動程式。

A:

這裡有一個從 MSDN 上摘抄來的 demo 程式,示範在 NT/2000/XP 中如何通過

 
 DeviceIoControl 擷取硬碟的基本參數。

/* The code of interest is in the subroutine GetDriveGeometry. The 
code in main shows how to interpret the results of the IOCTL call. */
#include 
#include  BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)
{
    HANDLE hDevice; // handle to the drive to be examined 
    BOOL bResult; // results flag
    DWORD junk; // discard results
    hDevice = CreateFile(.PhysicalDrive0, // drive to open
        0, // no access to the drive
        FILE_SHARE_READ | // share mode
        FILE_SHARE_WRITE, 
        NULL, // default security attributes
        OPEN_EXISTING, // disposition
        0, // file attributes
        NULL); // do not copy file attributes
    if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
    {
        return (FALSE);
    }
    bResult = DeviceIoControl(hDevice, // device to be queried
        IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform
        NULL, 0, // no input buffer
        pdg, sizeof(*pdg), // output buffer
        &junk, // # bytes returned
        (LPOVERLAPPED) NULL); // synchronous I/O
    CloseHandle(hDevice);
    return (bResult);
}
int main(int argc, char *argv[])
{
    DISK_GEOMETRY pdg; // disk drive geometry structure
    BOOL bResult; // generic results flag
    ULONGLONG DiskSize; // size of the drive, in bytes
    bResult = GetDriveGeometry (&pdg);
    if (bResult) 
    {
        printf(Cylinders = %I64d
            , pdg.Cylinders);
        printf(Tracks per cylinder = %ld
            , (ULONG) pdg.TracksPerCylinder); printf(Sectors per track = %ld
            , (ULONG) pdg.SectorsPerTrack);
        printf(Bytes per sector = %ld
            , (ULONG) pdg.BytesPerSector);
        DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *
            (ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;
        printf(Disk size = %I64d (Bytes) = %I64d (Mb)
            , DiskSize,
            DiskSize / (1024 * 1024));
    } 
    else 
    {
        printf (GetDriveGeometry failed. Error %ld.
            , GetLastError ());
    }
    return ((int)bResult);
}

 

Q: 如果將裝置名稱換成“A:”就可以取 A
盤參數,換成“CDROM0”就可以取 CDROM參數,是這樣嗎?

A

這個問題暫不回答你。請動手試一下看看。

 
 現在我們總結一下通過 DeviceIoControl訪問裝置驅動程式的“三步曲”:首先用 CreateFile
取得裝置控制代碼,然後用DeviceIoControl 與裝置進行 I/O,最後別忘記用 CloseHandle 關閉裝置控制代碼

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.