《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 業界動態 > Windows NT 4.0下設備驅動程序的開發與應用

Windows NT 4.0下設備驅動程序的開發與應用

2009-06-02
作者:湯冬誼 于恒春

  摘 要: 介紹了Windows NT4.0內核模式設備驅動程序開發中的一般性過程。通過提供一個最小化驅動程序的核心代碼,解釋各組成部分的結構功能和使用方法。在實踐中,結合自身的開發需要,可編寫出具有實用價值的驅動程序。
  關鍵詞: Win32子系統 設備驅動 系統注冊表 I/O請求包

?

  Windows NT 以其安全、穩定及界面友好等特性逐漸成為工業控制領域的前臺操作系統。面對工業控制中大量采用的串/并行通信及總線控制等技術,要求用戶不斷開發出滿足自身需要的硬件設備,同時又要求用戶應用程序與這些硬件設備進行通信,發送控制命令,讀取狀態信息等等。Windows NT出于安全性、穩定性等考慮,不允許用戶應用程序對物理硬件進行直接訪問,這就需要使用設備驅動程序跨越操作系統邊界對物理硬件進行操作,并向上提供客戶應用程序控制接口以供調用。
1 分層結構與設備驅動程序
  Windows NT分層結構(如圖1所示)包括運行于用戶模式及內核模式的各種部件,設備驅動程序在圖1的左下角,處于內核模式下I/O管理器之中。


2 驅動程序工作方式
  內核模式驅動程序與應用程序之間的最大差別之一是驅動程序的控制結構。內核模式驅動程序沒有main或WinMain,而是由I/O管理器根據需要調用一個驅動程序例程
  · 驅動程序被裝入時;
  · 驅動程序被卸出或系統關閉時;
  · 用戶程序發出I/O系統服務調用時;
  · 共享硬件資源對驅動程序可用時;
  · 設備操作過程中的任何時候。
3 初始化過程
3.1 系統注冊表中有關設備驅動程序的項目是系統

  加載設備驅動程序的入口點
  系統注冊表中用于系統加載設備驅動程序的項目如下:
  [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DriverName]
  ″Type″ = dword:00000001
  ″Start″ = dword:00000002
  ″Group″ = ″Extended Base″
  ″ErrorControl″ = dword:00000001
  其中Start含義如下:
  SERVICE_BOOT_START (0×0) 操作系統裝入時
  SERVICE_SYSTEM_START (0×01) 操作系統初始化時
  SERVICE_AUTO_START (0×02) 服務控制管理器啟動時
  SERVICE_DEMAND_START (0×03) 服務控制管理器手工啟動
  SERVICE_DISABLED (0×04) 不啟動
  Type含義如下:
  SERVICE_KERNEL_DRIVER (0×1)
  SERVICE_FILE_SYSTEM_DRIVER (0×2)
  SERVICE_ADAPTER (0×4)
  系統注冊表中用于設備驅動程序加載后讀取的項目如下:
  [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DriverName\Parameters]
  ″Parameter1″ = dword:00000001
  ″Parameter2″ = dword:00000004
3.2 加載驅動程序的裝入例程
  I/O管理器調用驅動程序的DriverEntry例程,執行初始化。該例程完成:
  · 初始化其它例程的入口;
  · 創建命名設備對象;
  · 讀取系統注冊表中相關項目并聲明必要的資源;
  · 設置內核驅動程序名與Win32子系統名的聯接;
  · 創建或初始化任意驅動程序使用的對象、類型和資源;
  · 返回狀態值。
  I/O管理器建立與設備關聯的Driver對象,并將其傳遞給DriverEntry例程。實際上Driver對象基本上是一個目錄,含有指向各個驅動程序服務例程函數的指針,其結構如表1所示。


  I/O管理器能夠找到DriverEntry例程,是因為它有一個公認的名字,而其他的例程則通過下列兩種方法查找:
  ·在Driver對象中有明確槽的函數,如DirverObject->DriverUnload;
  ·在Driver對象的MajorFunction數組中——Driver對象的MajorFunction支持兩種類型的功能代碼。一種為標準的功能代碼,如IRP_MJ_CREATE。另一種是用戶自定義的功能代碼,如IRP_MJ_DEVICE_CONTROL。
  所有驅動程序必須支持IRP_MJ_CREATE功能代碼,這是因為Win32子系統下的用戶程序調用CreateFile函數創建設備時,產生該功能代碼。如果不處理這個功能代碼,Win32程序就不能得到設備句柄。
  用戶自定義的功能代碼IRP_MJ_DEVICE_CONTROL只有在用戶模式下的客戶程序執行自定義的功能時可用。
  NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
  {
  //聲明設備對象
  PDEVICE_OBJECT DeviceObject;
  //生成函數接口指針
  DriverObject->MajorFunction[IRP_MJ_CREATE]=XxSelfDispatch;
  DriverObject->MajorFunction[IRP_MJ_CLOSE]=XxSelfDispatch;
  DriverObject->MajorFunction[IRP_MJ_READ]=XxReadDispatch;
  DriverObject->MajorFunction[IRP_MJ_WRITE]=XxWriteDispatch;
  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=XxSelfDispatch;
  DriverObject->DriverUnload=XxUnload;
  //生成Windows NT Executive知道的設備名
  RtlInitUnicodeString(&NtDeviceName, SelfDeviceName);
  //生成自己的設備
  Status=IoCreateDevice(
  DriverObject, // Driver對象
    sizeof(SELF_DEVICE_INFO), // Device對象
    Extension結構大小
    &NtDeviceName,
    DeviceType,
    0,
    FALSE, // 不執行
    &DeviceObject //Device對象指針
  );
  //生成Win32子系統下的用戶程序可識別的設備名
  RtlInitUnicodeString(&Win32DeviceName, SelfWin32Name);
  //聯接內部設備名與Win32子系統下的設備名
  Status = IoCreateSymbolicLink( &Win32DeviceName, &NtDeviceName );
  //利用RtlQueryRegistryValues函數讀出注冊表中Parameters下的參數值,初始化自己的硬件
  ...
  }
4 驅動程序服務例程
  驅動程序初始化之后,始終等待發自用戶的命令或由其它事件源引起的事件。一旦命令或事件發生,I/O管理器就調用相應的服務例程提供服務。而幾乎所有的I/O都是通過I/O請求包(IRP)驅動的。所謂IRP驅動,就是I/O管理器負責在非分頁的系統內存中分配一定空間,當接受用戶發出的命令或由事件引發后,將工作指令按一定的數據結構置于其中,傳遞到驅動程序服務例程。換言之,IRP包含了驅動程序服務例程所需要的信息指令。表2、表3為IRP的一些數據結構。

?


  同時,I/O管理器和驅動程序都需要在所有時候知道一個I/O設備所進行的情況。系統提供Device對象以滿足此要求。該對象在DriverEntry例程中生成設備時由系統創建后,分配給驅動程序,并在整個驅動程序生存期內有效。當I/O管理器調用驅動程序服務例程時,傳遞該對象。表4為Device對象的外部可見域。


  其中,DeviceExtension域是一個重要的數據結構。它是由I/O管理器創建并自動掛接到Device對象的非分頁池,是保存驅動程序任意全局變量的最好辦法。因為DeviceExtension是驅動程序特定的,要自定義它的數據結構。
  下面是一個驅動程序服務例程利用Device對象和IRP的片段:
  NTSTATUS XxSelfDispatch(IN PDEVICE_OBJECT pDO, IN PIRP pIrp);
  {
  PLOCAL_DEVICE_INFO pLDI;
  PIO_STACK_LOCATION pIrpStack;
  PULONG pIOBuffer;//得到全局信息
  pLDI = (PSELF_DEVICE_INFO)pDO->DeviceExtension;
  pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  //得到由用戶應用程序發來的用戶數據,并在需要時,將結果通過此變量返回給用戶
  pIOBuffer=(PULONG)pIrp->AssociatedIrp.System Buffer;
  // 由IRP攜帶的信息決定驅動程序的執行
  switch (pIrpStack->MajorFunction)
  {
    case IRP_MJ_CREATE:
    case IRP_MJ_CLOSE:
    Status = STATUS_SUCCESS;
    break;
    case IRP_MJ_DEVICE_CONTROL:
    //由Parameters進一步解釋控制代碼含義
  switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
  {
  case IOCTL_Function1:  //執行功能代碼
  Field1 = pLDI->SelfField1;
  ...
  break;
  case IOCTL_Function2:  //執行功能代碼
  ...
  break;
  }
  break;
  }
  // 返回I/O操作的狀態
  pIrp->IoStatus.Status = Status;
  IoCompleteRequest(pIrp, IO_NO_INCREMENT );
  return Status;
  }
5 驅動程序終止例程
  Unload例程負責取消由DriverEntry例程所做的任何事情,包括解除屬于該驅動程序的任何硬件資源的分配,以及刪除屬于驅動程序的任何內核對象。通常這僅在系統關閉時需要。
  VOID XxUnload(PDRIVER_OBJECT DriverObject)
  {
  PLOCAL_DEVICE_INFO pLDI;
  UNICODE_STRING Win32DeviceName;
  // 得到全局數據,根據全局數據進行清理工作
  pLDI=(PLOCAL_DEVICE_INFO)DriverObject->Device
  Object->DeviceExtension;
  if (pLDI->Field2 == TRUE)
  {
    ...
  }
  // 刪除分配的設備名及設備
  RtlInitUnicodeString(&Win32DeviceName, SelfWin32Name);
  IoDeleteSymbolicLink(&Win32DeviceName);
  IoDeleteDevice(pLDI->DeviceObject);
  }
6 用戶層應用程序與驅動程序間的接口
  驅動程序完成后,將在系統重新引導時裝入并初始化(由DriverEntry例程完成)。此時,驅動程序處于可用狀態,等待用戶層應用程序使用。用戶層應用程序可以:
  ·打開該設備文件(由IRP_MJ_CREATE功能代碼完成)
  ·讀出數據(由IRP_MJ_READ功能代碼完成)
  ·寫入數據(由IRP_MJ_WRITE功能代碼完成)
  ·執行用戶自定義的功能代碼(由IRP_MJ_DEVICE_CONTROL功能代碼完成)
  ·關閉該設備文件(由IRP_MJ_CLOSE功能代碼完成)
  以下是部分實現代碼:
  void main()
  {
  HANDLE hndFile; // 由CreateFile得到
  union {
    ULONG LongData;
    USHORT ShortData;
    UCHAR CharData;
    } DataBuffer; //從設備驅動程序中得到的數據
    LONG IoctlCode; //功能代碼
        ULONG DataLength;
        LONG Parameter1;
        //調用IRP中的IRP _MJ_CREATE功能
        hndFile = CreateFile(
        ″\\\\.\\SelfWin32Name″, // 打開設備文件″SelfWin32Name″
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
        );
        if (hndFile == INVALID_HANDLE_VALUE)
        {
        printf(″Unable to open the device.\n″);
        exit(1);
        }
        IoctlCode = IOCTL_Function1; //自定義功能代碼
        Parameter1 = 1;
        DataLength = sizeof(DataBuffer.CharData);
        IoctlResult = DeviceIoControl(
        hndFile, //設備文件句柄
        IoctlCode,//功能代碼,對應IRP中的Parameter.
        //DeviceIoControl.IoControlCode域&Parameter1,//傳遞到驅動程序的參數緩沖區,對應
        //IRP中的AssociatedIrp.SystemBuffer
        sizeof(Parameter1), //參數緩沖區長度
        &DataBuffer, //從驅動程序傳出的數據緩沖區
        DataLength, //緩沖區長度
        &ReturnedLength, //返回的實際緩沖區長度
        NULL //等待,直到操作完成
    );
    if (!CloseHandle(hndFile)) //關閉設備
    {
    printf(″Failed to close device.\n″);
   }
  }
  以上介紹了Windows NT4.0設備驅動程序開發中的一般性過程。用戶可利用NT SDK 及DDK開發工具包,并根據自身需要,對以上核心代碼進行擴充完成所需任務。
參考文獻
1 Art Baker. Windows NT設備驅動程序設計指南.
2 Microsoft. Windows NT DDK聯機手冊.

本站內容除特別聲明的原創文章之外,轉載內容只為傳遞更多信息,并不代表本網站贊同其觀點。轉載的所有的文章、圖片、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創文章及圖片等內容無法一一聯系確認版權者。如涉及作品內容、版權和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當措施,避免給雙方造成不必要的經濟損失。聯系電話:010-82306118;郵箱:aet@chinaaet.com。
亚洲一区二区欧美_亚洲丝袜一区_99re亚洲国产精品_日韩亚洲一区二区
亚洲乱码一区二区| 亚洲人成77777在线观看网| 精品av久久久久电影| 国产精品九色蝌蚪自拍| 欧美精品系列| 欧美刺激午夜性久久久久久久| 久久精品女人天堂| 亚洲欧美电影在线观看| 亚洲午夜av在线| 亚洲最新合集| 日韩视频一区二区三区在线播放| 欧美亚洲一区二区在线| 性欧美暴力猛交69hd| 亚洲伦理一区| 99re8这里有精品热视频免费 | 亚洲一级在线| 亚洲在线免费| 午夜精品久久| 久久本道综合色狠狠五月| 先锋影音网一区二区| 性欧美8khd高清极品| 欧美一区二区三区免费观看视频 | 国产一区二区中文字幕免费看| 国产亚洲人成a一在线v站 | 久久久亚洲午夜电影| 久久久久久久久岛国免费| 久久久免费精品视频| 久久亚洲免费| 久久天天综合| 欧美—级a级欧美特级ar全黄| 欧美精品一区在线| 国产精品a久久久久久| 欧美日韩国产一中文字不卡| 欧美色欧美亚洲另类二区| 国产精品亚洲一区| 狠狠狠色丁香婷婷综合激情| 1769国内精品视频在线播放| 亚洲日本精品国产第一区| 一区二区三区久久精品| 亚洲欧美日本国产专区一区| 久久狠狠婷婷| av成人免费在线观看| 亚洲综合国产| 久久久精品欧美丰满| 欧美国产日韩xxxxx| 欧美天堂亚洲电影院在线播放| 国产精品人人爽人人做我的可爱| 国产婷婷色综合av蜜臀av| 在线观看日韩av| 一区二区不卡在线视频 午夜欧美不卡'| 午夜精品久久久久久久蜜桃app| 欧美在线关看| 日韩亚洲欧美一区| 亚洲欧美日韩一区在线| 久久精品一二三| 欧美日韩成人网| 国产日韩欧美在线看| 亚洲第一页在线| 中国女人久久久| 亚洲国产二区| 亚洲综合色婷婷| 免费日韩av电影| 欧美性大战久久久久| 国内外成人免费激情在线视频网站| 亚洲精品黄网在线观看| 亚洲欧美99| 99国内精品久久| 久久精品人人做人人爽电影蜜月| 欧美精品亚洲二区| 国产综合久久| 中文在线一区| 亚洲欧洲精品一区二区三区| 午夜精品免费| 欧美激情中文字幕在线| 国产一区二区日韩| 亚洲精品日韩在线观看| 久久精品一区二区国产| 亚洲女同精品视频| 欧美激情2020午夜免费观看| 国产精品网红福利| 日韩亚洲在线观看| 亚洲第一视频| 欧美一级淫片播放口| 欧美极品一区二区三区| 韩国在线一区| 亚洲欧美综合v| 亚洲一级在线| 欧美精品国产精品日韩精品| 国产欧美精品久久| 一区二区三区欧美激情| 亚洲精选一区二区| 久久亚洲美女| 国产亚洲欧美日韩日本| 亚洲一区二区在线播放| 99亚洲一区二区| 麻豆成人精品| 国产一区二区在线观看免费播放| 亚洲午夜一区二区三区| 一区二区免费在线观看| 欧美粗暴jizz性欧美20| 国内精品福利| 亚洲欧美日韩综合| 亚洲免费视频观看| 欧美性生交xxxxx久久久| 日韩午夜免费| 妖精成人www高清在线观看| 免费久久99精品国产| 激情欧美国产欧美| 一区二区欧美激情| 亚洲美女毛片| 99xxxx成人网| 欧美黄色精品| 亚洲欧洲一区二区三区久久| 亚洲黄色av| 另类成人小视频在线| 黄色一区三区| 久久精品99国产精品| 久久人人97超碰国产公开结果| 国产日韩欧美夫妻视频在线观看| 亚洲视频在线二区| 亚洲免费人成在线视频观看| 国产精品v亚洲精品v日韩精品| 一区二区三区精品国产| 亚洲一区在线播放| 国产精品日韩欧美一区二区三区| 亚洲午夜久久久久久尤物| 亚洲免费影视第一页| 国产精品萝li| 午夜精品一区二区三区在线视| 欧美在线亚洲| 红杏aⅴ成人免费视频| 91久久久久久| 欧美黄色aaaa| 日韩一级黄色av| 亚洲欧美资源在线| 国产精品日本一区二区| 午夜精品久久久久| 久久伊人免费视频| 亚洲高清资源| 中文日韩欧美| 国产乱子伦一区二区三区国色天香| 一本久久综合| 欧美一区二区日韩| 国产一区久久| 亚洲精品久久久蜜桃| 欧美精品一卡| 亚洲天堂久久| 久久精品三级| 最新成人av在线| 亚洲在线免费| 国产一区二区三区在线观看视频| 亚洲电影天堂av| 欧美精品午夜| 亚洲综合电影| 免费观看亚洲视频大全| 日韩视频一区二区三区在线播放| 午夜精品亚洲一区二区三区嫩草| 国产视频自拍一区| 亚洲欧洲一区二区在线观看| 欧美日韩一区二区精品| 亚洲午夜国产成人av电影男同| 久久福利毛片| 亚洲日韩视频| 欧美在线观看视频一区二区三区 | 亚洲国产女人aaa毛片在线| 亚洲视频在线免费观看| 国产欧美日韩精品丝袜高跟鞋| 欧美日韩精品免费观看视频完整| 亚洲第一级黄色片| 午夜在线精品偷拍| 在线看片成人| 亚洲网站视频福利| 国内精品写真在线观看| 99精品热6080yy久久| 国产精品手机视频| 亚洲国产精品毛片| 国产精品三级视频| 亚洲国产综合在线| 国产精品视频免费一区| 亚洲经典三级| 国产伦精品一区二区三区在线观看 | 欧美精品一区二区三区在线看午夜| 亚洲欧美在线网| 欧美精品入口| 久久精品电影| 欧美午夜视频在线观看| 欧美乱妇高清无乱码| 亚洲少妇诱惑| 免费成人av| 亚洲欧美日韩精品久久亚洲区| 女仆av观看一区| 午夜精品久久久久久久| 欧美久色视频| 亚洲电影网站| 国产美女诱惑一区二区| 一区二区日韩欧美| 伊人久久久大香线蕉综合直播| 亚洲一区二区三区777| 亚洲韩国一区二区三区| 久久久国产午夜精品|