日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

WDM驱动程序入门

發(fā)布時間:2024/10/8 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WDM驱动程序入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

SourceUrl

WDM驅(qū)動程序入門(1)——HelloWDM

WDM驅(qū)動程序是一種很新的東西,相信很多人都跟我一樣,對它很感興趣,但是又找不到學(xué)習(xí)的切入點。究其原因,還是因為WDM是一種非常“死板板”的程序,它一運行就是工作在系統(tǒng)的底層RING 0處,提供各種接口給應(yīng)用程序調(diào)用。也正因為如此,它不像普通的應(yīng)用程序一樣,可以很快地上手——更多的時候,你是在閱讀它的技術(shù)資料和各種接口信息,你還要非常地熟悉系統(tǒng)底層的工作原理,否則一個不小心,就“藍屏”了,呵呵——話說回來,寫驅(qū)動程序的時候,死機是家常便飯。

因此很多人都對WDM望而生畏了。回想一下,我剛開始學(xué)WDM的情形還歷歷在目——看書看了整整3天,但是看完之后好像跟沒看也差不了多少,還是不知道怎么入門,甚至連怎么寫一個“Hello World”都不知道——后來才知道其實WDM是沒有所謂的“Hello World”程序的,唉,真是痛苦啊,這主要還是因為網(wǎng)絡(luò)上的WDM資料太少造成的。為了不讓大家重蹈我的覆轍并對WDM有個感性的認識,在此我給出一個最簡單的完整的WDM框架,并附有注釋,姑且可以算是一個入門的“Hello World”吧。

廢話少說,讓我們馬上開始研究,要求讀者已安裝DDK 2000。(在Win98中我還沒有測試過,不清楚是否能正常運行)

/***************************************************************
程序名稱:Hello World for WDM
文件名稱:HelloWDM.h
作者:羅聰
日期:2002-8-16
***************************************************************/

//頭文件,只是聲明一些函數(shù)和變量,比較簡單就不多說了,請讀者自行研究:

#ifdef __cplusplus

extern "C"
{
#endif

#include "ntddk.h"

#ifdef __cplusplus
}
#endif

typedef struct _DEVICE_EXTENSION
{
??? PDEVICE_OBJECT??? fdo;
??? PDEVICE_OBJECT??? NextStackDevice;
??? UNICODE_STRING??? ifSymLinkName;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
?????????????????????????? IN PDEVICE_OBJECT PhysicalDeviceObject);

NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
??????????????????????? IN PIRP Irp);

Code
/***************************************************************
程序名稱:Hello?World?for?WDM
文件名稱:HelloWDM.cpp
作者:羅聰
日期:2002-8-16
**************************************************************
*/?

//一定要的頭文件,聲明了函數(shù)模塊和變量:
#include?"HelloWDM.h"?

/***************************************************************
函數(shù)名稱:DriverEntry()
功能描述:WDM程序入口
**************************************************************
*/
//extern?"C"是必須的,表示“用C鏈接”。如果你的文件名是HelloWDM.c的話,這句可以省略。
extern?"C"
NTSTATUS?DriverEntry(????IN?PDRIVER_OBJECT?DriverObject,
????????????????????????IN?PUNICODE_STRING?RegistryPath)
{
????
//指定“添加設(shè)備”消息由函數(shù)“HelloWDMAddDevice()”來處理:
????DriverObject->DriverExtension->AddDevice?=?HelloWDMAddDevice;
????
//指定“即插即用”消息由函數(shù)“HelloWDMPnp()”來處理:
????DriverObject->MajorFunction[IRP_MJ_PNP]?=?HelloWDMPnp;?

????
//返回一個NTSTATUS值STATUS_SUCCESS。幾乎所有的驅(qū)動程序例程都必須返回一個NTSTATUS值,這些值在NTSTATUS.H?DDK頭文件中有詳細的定義。
????return?STATUS_SUCCESS;
}?

/***************************************************************
函數(shù)名稱:HelloWDMAddDevice()
功能描述:處理“添加設(shè)備”消息
**************************************************************
*/
NTSTATUS?HelloWDMAddDevice(IN?PDRIVER_OBJECT?DriverObject,
???????????????????????????IN?PDEVICE_OBJECT?PhysicalDeviceObject)
{
????
//定義一個NTSTATUS類型的返回值:
????NTSTATUS?status;
????
//定義一個功能設(shè)備對象(Functional?Device?Object):
????PDEVICE_OBJECT?fdo;?

????
//創(chuàng)建我們的功能設(shè)備對象,并儲存到fdo中:
????status?=?IoCreateDevice(
????????DriverObject,????????????????
//驅(qū)動程序?qū)ο?/span>
????????sizeof(DEVICE_EXTENSION),????//要求的設(shè)備擴展的大小
????????NULL,????????????????????????//設(shè)備名稱,這里為NULL
????????FILE_DEVICE_UNKNOWN,????????//設(shè)備的類型,在標(biāo)準(zhǔn)頭文件WDM.H或NTDDK.H中列出的FILE_DEVICE_xxx值之一
????????0,????????????????????????????//各種常量用OR組合在一起,指示可刪除介質(zhì)、只讀等。
????????FALSE,????????????????????????//如果一次只有一個線程可以訪問該設(shè)備,為TRUE,否則為FALSE
????????&fdo);????????????????????????//返回的設(shè)備對象?

????
//NT_SUCCESS宏用于測試IoCreateDevice內(nèi)核是否成功完成。不要忘記檢查對內(nèi)核的所有調(diào)用是否成功。NT_ERROR宏不等同于!NT_SUCCESS,最好使用!NT_SUCCESS,因為除了錯誤外,它還截獲警告信息。
????if(?!NT_SUCCESS(status))
????????
return?status;?

????
//創(chuàng)建一個設(shè)備擴展對象dx,用于存儲指向fdo的指針:
????PDEVICE_EXTENSION?dx?=?(PDEVICE_EXTENSION)fdo->DeviceExtension;
????dx
->fdo?=?fdo;?

????
//用IoAttachDeviceToDeviceStack函數(shù)把HelloWDM設(shè)備掛接到設(shè)備棧:
????dx->NextStackDevice?=?IoAttachDeviceToDeviceStack(fdo,?PhysicalDeviceObject);?

????
//設(shè)置fdo的flags。有兩個“位”是必須改變的,一個是必須清除DO_DEVICE_INITIALIZING標(biāo)志,如果在DriverEntry例程中調(diào)用IoCreateDevice(),就不需要清除這個標(biāo)志位。還有一個是必須設(shè)置DO_BUFFER_IO標(biāo)志位:
????fdo->Flags?|=?DO_BUFFERED_IO?|?DO_POWER_PAGABLE;
????fdo
->Flags?&=?~DO_DEVICE_INITIALIZING;?

????
//返回值:
????return?STATUS_SUCCESS;
}?

/***************************************************************
函數(shù)名稱:HelloWDMPnp()
功能描述:處理“即插即用”消息
**************************************************************
*/
NTSTATUS?HelloWDMPnp(IN?PDEVICE_OBJECT?fdo,
????????????????????????IN?PIRP?Irp)
{
????
//創(chuàng)建一個設(shè)備擴展對象dx,用于存儲指向fdo的指針:
????PDEVICE_EXTENSION?dx=(PDEVICE_EXTENSION)fdo->DeviceExtension;?

????
//首先要通過函數(shù)IoGetCurrentIrpStackLocation()得到當(dāng)前的IRP,并由此得到Minor?Function:
????PIO_STACK_LOCATION?IrpStack?=?IoGetCurrentIrpStackLocation(Irp);
????ULONG?MinorFunction?
=?IrpStack->MinorFunction;?

????
//然后把這個Minor?Function傳遞給下一個設(shè)備棧:
????IoSkipCurrentIrpStackLocation(Irp);
????NTSTATUS?status?
=?IoCallDriver(?dx->NextStackDevice,?Irp);?

????
//處理“即插即用”次功能代碼:
????
//當(dāng)Minor?Function等于IRP_MN_REMOVE_DEVICE時,說明有設(shè)備被拔出或卸下,這時要取消資源分配并刪除設(shè)備:
????if(?MinorFunction==IRP_MN_REMOVE_DEVICE)
????{
????????
//取消設(shè)備接口:
????????IoSetDeviceInterfaceState(&dx->ifSymLinkName,?FALSE);
????????RtlFreeUnicodeString(
&dx->ifSymLinkName);
????????
//調(diào)用IoDetachDevice()把fdo從設(shè)備棧中脫開:
????????if?(dx->NextStackDevice)
????????????IoDetachDevice(dx
->NextStackDevice);
????????
//刪除fdo:
????????IoDeleteDevice(fdo);
????}?

????
//返回值:
????return?status;
}?

?

WDM驅(qū)動程序入門(2)——驅(qū)動程序的小秘密


WDM程序編譯出來的并不是我們常見的.exe,而是.sys文件,在未經(jīng)設(shè)置編譯環(huán)境之前,是不能直接用VC來編譯的(這就是為什么會有幾百個錯誤了)。這種類型的文件你可以在WINNT\System32\Drivers里面找到很多。其實驅(qū)動程序也是一種PE文件,它同樣由DOS MZ header開頭,也有完整的DOS stub和PE header,同樣擁有Import table和Export table——hoho……那跟普通的PE文件有什么不一樣呢?

其實.sys跟.exe文件一樣,都是一種PE文件來的。不同的是,.sys文件Import的通常是NTOSKRNL.EXE,而.exe文件Import的通常是KERNEL32.DLL和USER32.DLL。

知道了這些有什么用呢?實際上,由于.sys通常不調(diào)用KERNEL32.DLL和USER32.DLL,所以你是不能在設(shè)備驅(qū)動程序里面調(diào)用任何C、C++和Win32函數(shù)的,而且也不能用C++關(guān)鍵字new和delete等(可以用malloc和free來代替),而必須使用大量的內(nèi)核函數(shù)。

為了讀者的方便,下面我列出一些常見的驅(qū)動程序可用的內(nèi)核函數(shù):
Ex…??????? 執(zhí)行支持
Hal…??????? 硬件抽象層(僅NT/Windows 2000)
Io…??????? I/O管理器(包括即插即用函數(shù))
Ke…??????? 內(nèi)核
Ks…??????? 內(nèi)核流IRP管理函數(shù)
Mm…??????? 內(nèi)存管理器
Ob…??????? 對象管理器
Po…??????? 電源管理
Ps…??????? 進程結(jié)構(gòu)
Rtl…??????? 運行時庫
Se…??????? 安全引用監(jiān)視
Zw…??????? 其他函數(shù)


寫設(shè)備驅(qū)動程序時必須注意的一些問題:

1、內(nèi)核宏
如果查看DDK頭文件,會發(fā)現(xiàn)有幾個內(nèi)核函數(shù)是以宏的方式實現(xiàn)的。這種宏中有幾個宏的定義是相當(dāng)糟糕的。例如,我們看到RemoveHeadList的定義如下:#define RemoveHeadList(ListHead)
??????? (ListHead)->Flink;
??????? {RemoveEntryList((ListHead)->Flink)}


如果以以下方式調(diào)用RemoveHeadList,則將編譯錯誤的代碼:if(SomethingInList)
??????? Entry = RemoveHeadList(list);


使這個調(diào)用安全的唯一方法是使用花括號:if(SomethingInList)
??? {
??????? Entry = RemoveHeadList(list);
??? }

?

所以我們切勿為了貪圖一時的方便,而使用不太規(guī)范的寫法,最好是在所有的if、for和while等語句中使用花括號。

2、驅(qū)動程序函數(shù)名稱
跟C/C++的main()函數(shù)一樣,設(shè)備驅(qū)動程序也有一個必須存在,而且只能以DriverEntry()為名稱的入口函數(shù)。然而,除此之外,我們可以使用任何名字來給其他函數(shù)命名——只要你自己記得就行了,當(dāng)然,最好符合某些特定的規(guī)范啦,例如匈牙利命名法……

3、安裝時的問題
·在Windows98中驅(qū)動程序可執(zhí)行文件必須是8.3文件名。(別問我為什么,我也不知道,我只能建議你去問比爾該死)
·如果INF文件中含有非法節(jié)的詳細資料,Windows將不使用這個INF文件。


?WDM驅(qū)動程序入門(3)——安裝步驟


DDK分為98 DDK和2000 DDK兩種,它們工作起來是大同小異的,不過有些驅(qū)動程序只能在2000 DDK中使用。由于Win98注定是一種即將被淘汰的操作系統(tǒng)了,所以我也不打算介紹如何在98 DDK中進行編譯,以下的所有內(nèi)容都是針對2000 DDK的。

·準(zhǔn)備工作
1、確定你已經(jīng)安裝了Visual C++
2、安裝2000 DDK
3、安裝2000 DDK成功后,在“開始”->“程序”里應(yīng)該有“Development Kits”->“Windows 2000 DDK”的項目。
(注意一定要先安裝好VC,然后才安裝DDK,這個順序決不能顛倒!!)
4、保證DDKROOT環(huán)境變量設(shè)置為Windows 2000 DDK的基目錄,如果不是的話,請在控制面板“系統(tǒng)”屬性的“高級”標(biāo)簽環(huán)境變量編輯器中設(shè)置好這個環(huán)境變量。


·編寫必需的文件
編譯WDM程序的時候,有兩個文件是必須要有的,它們是:
1、makefile
(這個是什么啊?你可能會問。)對于比較年輕的程序員來說,有可能沒有見過這個文件吧。其實在VC這些IDE出現(xiàn)之前,我們都必須使用makefile來確定項目中哪些文件需要重新編譯,現(xiàn)在的IDE都把這個工作自動做好了。(Well……其實這樣也好。)
我們要做的工作很簡單,就是提供這樣一個文件,它的內(nèi)容是:
#
# DO NOT EDIT THIS FILE!!!? Edit .\sources. If you want to add a new source
# file to this component.? This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)\makefile.def

?

正如它所述,不要編輯這個文件。事實上每個WDM程序所需要的makefile的內(nèi)容都是一樣的,也就是說,我們只需要簡單地copy一個makefile到新的項目中就可以了。(呵呵,是不是很方便呢?)

2、Sources
TARGETNAME=HelloWDM
TARGETTYPE=DRIVER
DRIVERTYPE=WDM
TARGETPATH=OBJ

INCLUDES=$(BASEDIR)\inc;\
???????? $(BASEDIR)\inc\ddk;\

TARGETLIBS=$(BASEDIR)\lib\*\free\usbd.lib\

SOURCES=HelloWDM.cpp\

?

這個文件指定了驅(qū)動程序目標(biāo)名是HelloWDM.sys,是一個WDM驅(qū)動程序,生成的文件存放在OBJ目錄中。值得注意的是,“=”前后不能有空格,否則編譯的時候會出錯。


·開始編譯
娃哈哈,前面羅羅嗦嗦講了一大堆,現(xiàn)在終于到重點了。WDM程序的編譯過程比較特殊,它不是在VC里面按F7來編譯的(盡管你可以通過設(shè)置來達到這一目的),而是通過一個DDK實用工具build來完成。下面我們來講講具體步驟:
1、“Debug”版的生成
首先,我們假設(shè)你的源代碼放在D:\HelloWDM里面。請跟著以下步驟:

“開始”->“程序”->“Development Kits”->“Windows 2000 DDK”->“Checked Build Environment”

屏幕將顯示:(有“回車”的那行是需要讀者你親自打進去的)
New or updated MSVC detected.? Updating DDK environment….

Setting environment for using Microsoft Visual C++ tools.
Starting dirs creation…Completed.

D:\NTDDK>cd\HelloWDM??? (回車)

D:\HelloWDM>build??? (回車)

?

如果源代碼沒有錯誤的話,生成的HelloWDM.sys將存放在objchk\i386目錄中。

2、“Release”版的生成
請跟著以下步驟:

“開始”->“程序”->“Development Kits”->“Windows 2000 DDK”->“Free Build Environment”

隨后的步驟跟“Debug”版相同,不同的是生成的HelloWDM.sys將存放在objfre\i386目錄中。


·安裝
如果前面的編譯過程沒有錯誤的話,現(xiàn)在我們應(yīng)該已經(jīng)得到了一個HelloWDM.sys文件,假設(shè)它是放在D:\HelloWDM\objfre\i386中。

我們還要干什么呢?…………對啦,就是安裝它!不然辛辛苦苦編譯出來有什么用?

安裝WDM驅(qū)動程序可以用兩種方法,一種是利用注冊表,還有一種是利用INF文件。我們一般是采用INF文件(這是微軟推薦的)。INF文件可以在 WINNT\INF 目錄中找到很多。為了順利安裝,我在這里先給出 HelloWDM 所需要的 HelloWDM.INF 文件:

?

Code
;;?The?Win2K?DDK?documentation?contains?an?excellent?INF?reference.

;---------?Version?Section?---------------------------------------------------

[Version]
Signature
="$CHICAGO$"
Provider
=LC_Device
DriverVer
=8/21/2002,3.0.0.3

;?If?device?fits?one?of?the?standard?classes,?use?the?name?and?GUID?here,
;
?otherwise?create?your?own?device?class?and?GUID?as?this?example?shows.

Class
=Unknown
ClassGUID
={ff646f80-8def-11d2-9449-00105a075f6b}

;---------?SourceDiskNames?and?SourceDiskFiles?Section?-----------------------

;?These?sections?identify?source?disks?and?files?for?installation.?They?are
;
?shown?here?as?an?example,?but?commented?out.

[SourceDisksNames]
1?=?"HelloWDM",Disk1,,

[SourceDisksFiles]
HelloWDM.sys?
=?1,objfre\i386,

;---------?ClassInstall/ClassInstall32?Section?-------------------------------

;?Not?necessary?if?using?a?standard?class

;?9X?Style
[ClassInstall]
Addreg
=Class_AddReg

;?NT?Style
[ClassInstall32]
Addreg
=Class_AddReg

[Class_AddReg]
HKR
,,,,%DeviceClassName%
HKR
,,Icon,,"-5"

;---------?DestinationDirs?Section?-------------------------------------------

[DestinationDirs]
YouMark_Files_Driver?
=?10,System32\Drivers

;---------?Manufacturer?and?Models?Sections?----------------------------------

[Manufacturer]
%MfgName%
=Mfg0

[Mfg0]

;?PCI?hardware?Ids?use?the?form
;
?PCI\VEN_aaaa&DEV_bbbb&SUBSYS_cccccccc&REV_dd
;
改成你自己的ID
%DeviceDesc%=YouMark_DDI,?PCI\VEN_9999&DEV_9999

;----------?DDInstall?Sections?-----------------------------------------------
;
?---------?Windows?9X?-----------------

;?Experimentation?has?shown?that?DDInstall?root?names?greater?than?19?characters
;
?cause?problems?in?Windows?98

[YouMark_DDI]
CopyFiles
=YouMark_Files_Driver
AddReg
=YouMark_9X_AddReg

[YouMark_9X_AddReg]
HKR
,,DevLoader,,*ntkern
HKR
,,NTMPDriver,,HelloWDM.sys
HKR
,?"Parameters",?"BreakOnEntry",?0x00010001,?0

;?---------?Windows?NT?-----------------

[YouMark_DDI.NT]
CopyFiles
=YouMark_Files_Driver
AddReg
=YouMark_NT_AddReg

[YouMark_DDI.NT.Services]
Addservice?
=?HelloWDM,?0x00000002,?YouMark_AddService

[YouMark_AddService]
DisplayName?
=?%SvcDesc%
ServiceType?
=?1?;?SERVICE_KERNEL_DRIVER
StartType?=?3?;?SERVICE_DEMAND_START
ErrorControl?=?1?;?SERVICE_ERROR_NORMAL
ServiceBinary?=?%10%\System32\Drivers\HelloWDM.sys

[YouMark_NT_AddReg]
HKLM
,?"System\CurrentControlSet\Services\HelloWDM\Parameters",\
"BreakOnEntry",?0x00010001,?0


;?---------?Files?(common)?-------------

[YouMark_Files_Driver]
HelloWDM.sys

;---------?Strings?Section?---------------------------------------------------

[Strings]
ProviderName
="Flying?L?Co.,Ltd."
MfgName
="LC?Soft"
DeviceDesc
="Hello?World?WDM!"
DeviceClassName
="LC_Device"
SvcDesc
="???"


注意它可以同時在Win98或者Win2000中使用(系統(tǒng)會通過這個INF文件里面的字段名稱,自動選擇適合當(dāng)前系統(tǒng)的安裝方法的)。由于INF文件的各個字段含義比較復(fù)雜,限于篇幅,我在這里就不詳細講解了,請讀者自行參閱有關(guān)的文章或者書籍。

準(zhǔn)備好這個 HelloWDM.INF 文件后,讓我們打開控制面板,雙擊“添加/刪除硬件”,選擇“添加/排除設(shè)備故障”->“添加新設(shè)備”->“否,我想從列表選擇硬件”->“其它設(shè)備”->“從磁盤安裝”,選擇 HelloWDM.INF 所在的路徑,然后安裝。

當(dāng)安裝完成后,系統(tǒng)就會添加上你寫好的驅(qū)動程序了。(可以在“設(shè)備管理器”中查看到)。然后重啟電腦,這個驅(qū)動程序就投入使用啦。

轉(zhuǎn)載于:https://www.cnblogs.com/dubingsky/archive/2009/06/29/1513100.html

總結(jié)

以上是生活随笔為你收集整理的WDM驱动程序入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。