Windows驅動程式模型(Windows Driver Model,簡稱WDM),是微軟Windows作業系統的驅動程式設計架構,包括對於各項裝置(Device)的支援,如鍵盤(Keyboard)、滑鼠(Mouse)、網路卡(Network Driver Interface Specification,Ndis)、通用序列匯流排(Universal Serial Bus,USB)等。WDM可支援Windows 98, Windows 98 Second Edition, Windows Me, Windows 2000, Windows XP以及Windows Server 2003在x86平台上的建制工作。這個架構分成好幾個管理層面:
驅動程式的種類有匯流排驅動程式(bus driver)、功能驅動程式(function driver)、篩選驅動程式(filter driver)三種:
如同許多語言從main函式開始,WDM驅動程式的載入(Loading)乃至於動作,以及其卸載(Unload)行為,都有其步驟與規則。WDM驅動程式可以動態式的載入與卸載,當偵測到裝置(Device)插入的時候,依據「PnP Manager」會自動地載入相對應的裝置驅動程式,然後成為「Driver Object」,並呼叫DriverEntry函式。所有的WDM驅動程式,都必須擁有這個DriverEntry常式(routine),而且「此一名稱不可改變」的,所有的驅動程式也是從這裡開始執行的,I/O Manager首先呼叫驱动程式的DriverEntry()。DriverEntry在DDK Compiler編譯出來的輸出符號表是“DriverEntry@8”,原因是微軟的C編譯器把stdcall函示(例如VcDCall)的名稱加上“記號”,加上一個@符號,在附上參數的總位元組個數,8指此function的所有參數所佔的byte數。
DriverEntry函式有兩個參數,其中第一个参数PDRIVER_OBJECT DriverObject是指向该驅動程式对应的物件指標;PUNICODE_STRING RegistryPath,驅動程式的服务主要鍵碼,這個參數的使用時機並不多。以下是一個簡單而標準的DriverEntry基本實作:
NTSTATUSDriverEntry(PDRIVER_OBJECTDriverObject,PUNICODE_STRINGpRegistryString){//PDEVICE_OBJECT DriverObject;UNICODE_STRINGdeviceName;RtlInitUnicodeString(&deviceName,DEVICE_NAME);status=IoCreateDevice(DriverObject,0,&deviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,true,&pDeviceObj);UNICODE_STRINGlinkName;RtlInitUnicodeString(&linkName,LINK_NAME);status=IoCreateSymbolicLink(&linkName,&deviceName);DriverObject->DriverUnload=DriverUnload;DriverObject->MajorFunction[IRP_MJ_CREATE]=DriverObject->MajorFunction[IRP_MJ_CLOSE]=DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=xxDriverDispatch;DriverObject->DriverUnload=xxUnload;returnSTATUS_SUCCESS;}
DriverEntry運作在IRQL = PASSIVE_LEVEL等級,所以可以使用分頁內存。WDM有數個經常實作的PASSIVE_LEVEL等級如下:
另外還有幾個DISPATCH_LEVEL等級的函式如下:
當DriverEntry函式完成物件的初始化與系統註冊之後,接下來的重點便會落在Dispatch Function身上。每當I/O Manager得到一個請求時(例如按鍵,移動滑鼠),它使用請求的函數代碼(IoControlCode)呼叫驅動程序中幾個Dispatch行程。
NTSTATUSxxDispatch(INPDEVICE_OBJECTDeviceObject,INPIRPpIrp){NTSTATUSntStatus=STATUS_SUCCESS;ULONGIoControlCodes=0;PIO_STACK_LOCATIONIrpStack=NULL;pIrp->IoStatus.Status=STATUS_SUCCESS;pIrp->IoStatus.Information=0;IrpStack=IoGetCurrentIrpStackLocation(pIrp);switch(IrpStack->MajorFunction){caseIRP_MJ_CREATE:break;caseIRP_MJ_CLOSE:break;caseIRP_MJ_DEVICE_CONTROL:IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode;switch(IoControlCodes){caseIOCTL_1:break;caseIOCTL_2:break;default:pIrp->IoStatus.Status=STATUS_INVALID_PARAMETER;break;}break;default:break;}ntStatus=pIrp->IoStatus.Status;IoCompleteRequest(pIrp,IO_NO_INCREMENT);returnntStatus;}
Unload負責在驅動程式被停止前做一些必要的處理動作,如释放资源,记录最後状态等。
VOIDDriverUnLoad(INPDRIVER_OBJECTDriverObject){if(DeviceObject){IoUnregisterFileSystem(DeviceObject);IoDeleteDevice(DeviceObject);//DeviceObject = 0;}
驅動程式的编译需要使用DDK(Device Driver Kit)中的build指令,它是一道命令行程序,一般會在後面加上參數:-ceZ。例如:
C:\driver sample>build.exe -ceZDDK可用於建立用於 Windows 2000、Windows XP、Microsoft Windows Server 2003、Vista的建置環境,但在Windows作業系統並非預設的功能,必須另行安裝。安装完成後你會看到Build Enviroment,free是指release版,check則是debug版。
build指令一開始呼叫Build.exe編譯連結器,從系統「環境變數」(Environment Variable)Include中得到引用文件的地址,然後呼叫Visual C++的编译链接器Nmake.exe进行实际的编译链接工作。在編譯過程中遇到的错误,遇到的警告,會記錄到buildxxx.log,buildxxx.wrn,buildxxx.err等文件中。
安裝過程分成兩個步驟:
Microsoft DDK提供了大量的WDM範例(samples)參考,這些範例隨著DDK的安裝,會進駐我們的系統之中(WINDDK\xx00\src)。一般人不大可能從輪子造起一個新的驅動程式,大部份要靠“既有的範例”來改良一個新的驅動程式。