windowsNT4.0下設備驅(qū)動程序的開發(fā)與應用
RtlInitUnicodeString(Win32DeviceName, SelfWin32Name);
//聯(lián)接內(nèi)部設備名與Win32子系統(tǒng)下的設備名
Status = IoCreateSymbolicLink( Win32DeviceName, NtDeviceName);
//利用RtlQueryRegistryValues函數(shù)讀出注冊表中Parameters下的參數(shù)值,初始化自己的硬件
...
}
4 驅(qū)動程序服務例程
驅(qū)動程序初始化之后,始終等待發(fā)自用戶的命令或由其它事件源引起的事件。一旦命令或事件發(fā)生,I/O管理器就調(diào)用相應的服務例程提供服務。而幾乎所有的I/O都是通過I/O請求包IRP驅(qū)動的。所謂IRP驅(qū)動,就是I/O管理器負責在非分頁的系統(tǒng)內(nèi)存中分配一定空間,當接受用戶發(fā)出的命令或由事件引發(fā)后,將工作指令按一定的數(shù)據(jù)結構置于其中,傳遞到驅(qū)動程序服務例程。換言之,IRP包含了驅(qū)動程序服務例程所需要的信息指令。表2、表3為IRP的一些數(shù)據(jù)結構。
同時,I/O管理器和驅(qū)動程序都需要在所有時候知道一個I/O設備所進行的情況。系統(tǒng)提供Device對象以滿足此要求。該對象在DriverEntry例程中生成設備時由系統(tǒng)創(chuàng)建后,分配給驅(qū)動程序,并在整個驅(qū)動程序生存期內(nèi)有效。當I/O管理器調(diào)用驅(qū)動程序服務例程時,傳遞該對象。表4為Device對象的外部可見域。
表2 IRP標頭中外部可見的域
表3 IRP堆棧單元的一些內(nèi)容
表4 Device 對象的外部可見域
其中,DeviceExtension域是一個重要的數(shù)據(jù)結構。它是由I/O管理器創(chuàng)建并自動掛接到Device對象的非分頁池,是保存驅(qū)動程序任意全局變量的最好辦法。因為DeviceExtension是驅(qū)動程序特定的,要自定義它的數(shù)據(jù)結構。
下面是一個驅(qū)動程序服務例程利用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);
//得到由用戶應用程序發(fā)來的用戶數(shù)據(jù),并在需要時,將結果通過此變量返回給用戶
pIOBuffer=PULONGpIrp->AssociatedIrp.System
Buffer;
// 由IRP攜帶的信息決定驅(qū)動程序的執(zhí)行
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:
//執(zhí)行功能代碼
Field1 = pLDI->SelfField1;
...
break;
case IOCTL_Function2:
//執(zhí)行功能代碼
...
break;
}
break
}
// 返回I/O操作的狀態(tài)
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp IO_NO_INCREMENT);
return Status;
}
5 驅(qū)動程序終止例程
Unload例程負責取消由DriverEntry例程所做的任何事情,包括解除屬于該驅(qū)動程序的任何硬件資源的分配,以及刪除屬于驅(qū)動程序的任何內(nèi)核對象。通常這僅在系統(tǒng)關閉時需要。
VOID XxUnload(PDRIVER_OBJECT DriverObject)
{
PLOCAL_DEVICE_INFO pLDI;
UNICODE_STRING Win32DeviceName;
// 得到全局數(shù)據(jù),根據(jù)全局數(shù)據(jù)進行清理工作
pLDI=PLOCAL_DEVICE_INFODriverObject->Device
Object->DeviceExtension
if (pLDI->Field2 == TRUE)
{
...
// 刪除分配的設備名及設備
RtlInitUnicodeString(Win32DeviceName, SelfWin32 Name);
IoDeleteSymbolicLink(Win32DeviceName);
IoDeleteDevice(pLDI->DeviceObject);
}
6 用戶層應用程序與驅(qū)動程序間的接口
驅(qū)動程序完成后,將在系統(tǒng)重新引導時裝入并初始化(由DriverEntry例程完成)。此時,驅(qū)動程序處于可用狀態(tài),等待用戶層應用程序使用。用戶層應用程序可以:
·打開該設備文件(由IRP_MJ_CREATE功能代碼完成)
·讀出數(shù)據(jù)(由IRP_MJ_READ功能代碼完成)
·寫入數(shù)據(jù)(由IRP_MJ_WRITE功能代碼完成)
·執(zhí)行用戶自定義的功能代碼(由IRP_MJ_DEVICE_CONTROL功能代碼完成)
·關閉該設備文件(由IRP_MJ_CLOSE功能代碼完成)
以下是部分實現(xiàn)代碼:
void main()
{
HANDLE hndFile; // 由CreateFile得到
union {
ULONG LongData;
USHORT ShortData;
UCHAR CharData;
}DataBuffer; //從設備驅(qū)動程序中得到的數(shù)據(jù)
LONG IoctlCode; //功能代碼
ULONG DataLength;
LONG Parameter1;
//調(diào)用IRP中的IRP _MJ_CREATE功能
hndFile = CreateFile(
″\\.\SelfWin32Name″, // 打開設備文件″ SelfWin32Name″
評論