HOWTO:将 IOCTL 发送到筛选器驱动程序
生活随笔
收集整理的這篇文章主要介紹了
HOWTO:将 IOCTL 发送到筛选器驱动程序
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
HOWTO:將 IOCTL 發送到篩選器驅動程序
察看本文應用于的產品 <script type="text/javascript">function loadTOCNode(){}</script>| 文章編號 | : | 262305 |
| 最后修改 | : | 2003年10月23日 |
| 修訂 | : | 1.4 |
概要
<script type="text/javascript">loadTOCNode(1, 'summary');</script> 本文說明如何通過創建獨立的控件 deviceobject 而不是打開由篩選器驅動程序注冊的專用設備接口 (IoRegisterDeviceInterface),將 IOCTL 請求發送到即插即用 (PNP) 篩選器驅動程序。更多信息
<script type="text/javascript">loadTOCNode(1, 'moreinformation');</script> 正在編寫篩選器驅動程序的開發人員可能需要將自定義設備 I/O 控制請求從應用程序或另一個驅動程序發送到它們的篩選器驅動程序,以便控制其行為。在基于 Windows 2000 的計算機上,Microsoft 建議驅動程序在 AddDevice 例程中為要與它們進行交互的其他應用程序或驅動程序注冊設備接口。按照此建議,篩選器驅動程序編寫者通過在 PhysicalDeviceObject (PDO) 上注冊他們自己的 GUID(在 AddDevice 例程中收到),編寫自定義應用程序以枚舉此接口 GUID 并將 IOCTL 發送到驅動程序。 status = IoRegisterDeviceInterface ( PhysicalDeviceObject, (LPGUID) &MY_SPECIAL_INTERFACE_GUID, NULL, &devExt->InterfaceName);
只要篩選器是堆棧中最上面的篩選器(類篩選器),此方法就會起作用,因為該篩選器首先處理請求。如果篩選器驅動程序位于堆棧中的其他任何位置,則 IOCTL 請求可能被其他篩選器或它上面的功能驅動程序拒絕。篩選器驅動程序拒絕它不知道的請求是不適當的;但是,功能驅動程序可能會這樣做。因此,如果篩選器驅動程序是一個低層篩選器,功能驅動程序肯定會拒絕不知道的所有 IOCTL 請求。
避免此問題的唯一方法是創建另一個名為 controlobject 的獨立控件和一個符號鏈接(如通常對 Microsoft Windows NT 4.0 驅動程序所做的那樣),而不是在 PDO 上注冊接口。應用程序可以打開符號鏈接并將 IOCTL 發送到篩選器。這些 I/O 請求會被直接發送到控件 deviceobject,而不是遍歷整個堆棧,不管篩選器驅動程序位于堆棧中的什么位置。
以下代碼顯示如何為通用 toaster 篩選器示例 (Filter.c) 提供自定義 IOCTL 支持,該示例位于 Windows 2000 和 Windows XP DDK 中,在 <DDK 根目錄>/Src/General/Toaster/Filter/ 下。提供 IOCTL 支持所需的所有代碼都位于條件編譯指令內。您必須在源文件中定義 IOCTL_INTERFACE(-DIOCTL_INTERFACE=1),以包括 IOCTL 接口支持。
與在 Windows 2000 DDK 中提供的示例相比,除了為演示 IOCTL 接口而添加的代碼之外,在代碼中還有一些增強和錯誤更正。 #include <ntddk.h> #include "filter.h"#ifdef ALLOC_PRAGMA #pragma alloc_text (INIT, DriverEntry) #pragma alloc_text (PAGE, FilterAddDevice)#pragma alloc_text (PAGE, FilterDispatchPnp) #pragma alloc_text (PAGE, FilterUnload) #endif// // Define IOCTL_INTERFACE in your sources file if you want your // app to have private interaction with the filter driver.Read KB Q262305 // for more information. // #ifdef IOCTL_INTERFACE#ifdef ALLOC_PRAGMA #pragma alloc_text (PAGE, FilterCreateControlObject) #pragma alloc_text (PAGE, FilterDeleteControlObject) #pragma alloc_text (PAGE, FilterDispatchIo) #endif FAST_MUTEX ControlMutex; ULONG InstanceCount = 0; PDEVICE_OBJECT ControlDeviceObject;#endifNTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) /*++例程說明:可安裝的驅動程序初始化入口點。 此入口點由 I/O 系統直接調用。參數:DriverObject - 指向驅動程序對象的指針RegistryPath - 指向表示路徑的 unicode 字符串,該路徑是 注冊表中驅動程序特定的鍵的路徑。返回值:STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise.--*/ { NTSTATUS status = STATUS_SUCCESS; ULONG ulIndex; PDRIVER_DISPATCH * dispatch;UNREFERENCED_PARAMETER (RegistryPath);DebugPrint (("Entered the Driver Entry/n"));// // Create dispatch points// for (ulIndex = 0, dispatch = DriverObject->MajorFunction; ulIndex <= IRP_MJ_MAXIMUM_FUNCTION; ulIndex++, dispatch++) {*dispatch = FilterPass;}DriverObject->MajorFunction[IRP_MJ_PNP] = FilterDispatchPnp; DriverObject->MajorFunction[IRP_MJ_POWER] = FilterDispatchPower; DriverObject->DriverExtension->AddDevice = FilterAddDevice; DriverObject->DriverUnload = FilterUnload;#ifdef IOCTL_INTERFACE// // Set the following dispatch points as we will be doing // something useful to these requests instead of just // passing them down. // DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FilterDispatchIo;// // Mutex is to synchronize multiple threads creating & deleting // control deviceobjects.// ExInitializeFastMutex (&ControlMutex);#endifreturn status; }NTSTATUS FilterAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) /*++例程說明:"即插即用"子系統為我們提供了一個全新的 PDO,我們要 (通過 INF 注冊的方法)為其提供驅動程序。我們需要確定是否需要處于該設備的驅動程序堆棧中。 創建功能設備對象以連接到堆棧 初始化該設備對象 返回狀態成功。請記住:實際上我們不能將任何非 pnp IRPS 發送到給定的驅動程序 堆棧,除非已經接收到了 IRP_MN_START_DEVICE。參數:DeviceObject - 指向設備對象的指針。PhysicalDeviceObject - 指向 最下層總線驅動程序創建的設備對象的指針。返回值:NT status code.--*/ { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT deviceObject = NULL;PDEVICE_EXTENSION deviceExtension; ULONG deviceType = FILE_DEVICE_UNKNOWN;PAGED_CODE ();// // IoIsWdmVersionAvailable(1, 0x20) returns TRUE on os after Windows 2000.// if (!IoIsWdmVersionAvailable(1, 0x20)) {// // Win2K system bugchecks if the filter attached to a storage device // doesn't specify the same DeviceType as the device it's attaching // to.This bugcheck happens in the filesystem when you disable // the devicestack whose top level deviceobject doesn't have a VPB. // To workaround we will get the toplevel object's DeviceType and // specify that in IoCreateDevice.// deviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject); deviceType = deviceObject->DeviceType; ObDereferenceObject(deviceObject);}// // Create a filter device object.// status = IoCreateDevice (DriverObject, sizeof (DEVICE_EXTENSION), NULL, // No Name deviceType, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);if (!NT_SUCCESS (status)) {// // Returning failure here prevents the entire stack from functioning, // but most likely the rest of the stack will not be able to create // device objects either, so it is still OK.// return status;}DebugPrint (("AddDevice PDO (0x%x) FDO (0x%x)/n", PhysicalDeviceObject, deviceObject));deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;deviceExtension->NextLowerDriver = IoAttachDeviceToDeviceStack ( deviceObject, PhysicalDeviceObject);// // Failure for attachment is an indication of a broken plug & play system.// if(NULL == deviceExtension->NextLowerDriver) {IoDeleteDevice(deviceObject); return STATUS_UNSUCCESSFUL;}deviceObject->Flags |= deviceExtension->NextLowerDriver->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE );deviceObject->DeviceType = deviceExtension->NextLowerDriver->DeviceType;deviceObject->Characteristics = deviceExtension->NextLowerDriver->Characteristics;deviceExtension->Self = deviceObject;// // Set the initial state of the Filter DO// INITIALIZE_PNP_STATE(deviceExtension);DebugPrint(("AddDevice:%x to %x->%x /n", deviceObject, deviceExtension->NextLowerDriver, PhysicalDeviceObject));deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;return STATUS_SUCCESS;}NTSTATUS FilterPass ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) /*++例程說明:默認的調度例程。如果此驅動程序不識別 IRP,那么它應該將它不經修改就向下發送。 如果該設備正在處理其他一些 IRP,此 IRP 必須在設備擴展中排隊 不需要完成例程。只是為了進行演示,我們才會將所有(非"即插即用")Irp 向下傳遞 到堆棧上(因為我們是篩選器驅動程序)。實際的驅動程序可能會選擇 為這些 Irp 中的一部分提供服務。由于我們不清楚正在傳遞哪個函數,所以,我們不能假定自己是否在比較高的 IRQL 上被調用。 因此,此函數必須置于非分頁的池 (也稱默認位置)中。參數:DeviceObject - 指向設備對象的指針。Irp - 指向 I/O 請求數據包的指針。返回值:NT 狀態代碼--*/ { PDEVICE_EXTENSION deviceExtension;deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;IoSkipCurrentIrpStackLocation (Irp); return IoCallDriver (deviceExtension->NextLowerDriver, Irp); }NTSTATUS FilterDispatchPnp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) /*++例程說明:"即插即用"調度例程。這些驅動程序中,多數都將會完全忽略。 在所有情況下,它都必須把 IRP 傳遞到較低級別的驅動程序。參數:DeviceObject - 指向設備對象的指針。Irp - 指向 I/O 請求數據包的指針。返回值:NT 狀態代碼--*/ { PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; NTSTATUS status;PAGED_CODE ();deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(Irp);DebugPrint(("FilterDO %s IRP:0x%x /n", PnPMinorFunctionString(irpStack->MinorFunction), Irp));switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE:// // The device is starting.// // We cannot touch the device (send it any non pnp irps) until a // start device has been passed down to the lower drivers.// IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) FilterStartCompletionRoutine, NULL, TRUE, TRUE, TRUE);return IoCallDriver (deviceExtension->NextLowerDriver, Irp);case IRP_MN_REMOVE_DEVICE:IoSkipCurrentIrpStackLocation (Irp);status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);SET_NEW_PNP_STATE(deviceExtension, Deleted);#ifdef IOCTL_INTERFACE FilterDeleteControlObject(); #endif IoDetachDevice(deviceExtension->NextLowerDriver); IoDeleteDevice(DeviceObject); return status;case IRP_MN_QUERY_STOP_DEVICE: SET_NEW_PNP_STATE(deviceExtension, StopPending); status = STATUS_SUCCESS; break;case IRP_MN_CANCEL_STOP_DEVICE:// // Check to see whether you have received cancel-stop // without first receiving a query-stop.This could happen if someone // above us fails a query-stop and passes down the subsequent // cancel-stop.// if(StopPending == deviceExtension->DevicePnPState){// // We did receive a query-stop, so restore.// RESTORE_PREVIOUS_PNP_STATE(deviceExtension);} status = STATUS_SUCCESS; // We must not fail this IRP. break;case IRP_MN_STOP_DEVICE: SET_NEW_PNP_STATE(deviceExtension, Stopped); status = STATUS_SUCCESS; break;case IRP_MN_QUERY_REMOVE_DEVICE:SET_NEW_PNP_STATE(deviceExtension, RemovePending); status = STATUS_SUCCESS; break;case IRP_MN_SURPRISE_REMOVAL:SET_NEW_PNP_STATE(deviceExtension, SurpriseRemovePending); status = STATUS_SUCCESS; break;case IRP_MN_CANCEL_REMOVE_DEVICE:// // Check to see whether you have received cancel-remove // without first receiving a query-remove.This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove.// if(RemovePending == deviceExtension->DevicePnPState){// // We did receive a query-remove, so restore.// RESTORE_PREVIOUS_PNP_STATE(deviceExtension);}status = STATUS_SUCCESS; // We must not fail this IRP. break;case IRP_MN_DEVICE_USAGE_NOTIFICATION:// // On the way down, pagable might become set.Mimic the driver // above us.If no one is above us, just set pagable.// if ((DeviceObject->AttachedDevice == NULL) || (DeviceObject->AttachedDevice->Flags & DO_POWER_PAGABLE)) {DeviceObject->Flags |= DO_POWER_PAGABLE;}IoCopyCurrentIrpStackLocationToNext(Irp);IoSetCompletionRoutine( Irp, FilterDeviceUsageNotificationCompletionRoutine, NULL, TRUE, TRUE, TRUE);return IoCallDriver (deviceExtension->NextLowerDriver, Irp);default:// // If you don't handle any IRP you must leave the // status as is.// status = Irp->IoStatus.Status;break;}// // Pass the IRP down and forget it.// Irp->IoStatus.Status = status; return FilterPass(DeviceObject, Irp); }NTSTATUS FilterStartCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) /*++ 例程說明: 一個完成例程,在調用我們的篩選器設備對象所附加的低層設備對象時 使用該例程。參數:DeviceObject - 指向 deviceobject 的指針 Irp - 指向 PnP Irp 的指針。 上下文 - NULL 返回值:返回 NT 狀態。--*/ { PDEVICE_EXTENSION deviceExtension;UNREFERENCED_PARAMETER(Context);deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;if (Irp->PendingReturned) {IoMarkIrpPending(Irp);}if (NT_SUCCESS (Irp->IoStatus.Status)) {// // As we are successfully now back, we will // first set our state to Started.// SET_NEW_PNP_STATE(deviceExtension, Started);// // On the way up inherit FILE_REMOVABLE_MEDIA during Start. // This characteristic is available only after the driver stack is started!.// if (deviceExtension->NextLowerDriver->Characteristics & FILE_REMOVABLE_MEDIA) {DeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;}#ifdef IOCTL_INTERFACE// // If the PreviousPnPState is stopped then we are being stopped temporarily // and restarted for resource rebalance. // if(Stopped != deviceExtension->PreviousPnPState) {// // Device is started for the first time.// FilterCreateControlObject(DeviceObject);} #endif}return STATUS_SUCCESS;}NTSTATUS FilterDeviceUsageNotificationCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) /*++ 例程說明: 一個完成例程,在調用我們的篩選器 deviceobject 所附加的低層設備對象時 使用該例程。參數:DeviceObject - 指向 deviceobject 的指針 Irp - 指向 PnP Irp 的指針。 上下文 - NULL 返回值:返回 NT 狀態。--*/ { PDEVICE_EXTENSION deviceExtension;UNREFERENCED_PARAMETER(Context);deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;if (Irp->PendingReturned) {IoMarkIrpPending(Irp);}// // On the way up, pagable might become clear.Mimic the driver below us.// if (!(deviceExtension->NextLowerDriver->Flags & DO_POWER_PAGABLE)) {DeviceObject->Flags &= ~DO_POWER_PAGABLE;}return STATUS_SUCCESS;}NTSTATUS FilterDispatchPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) /*++例程說明:此例程是 power irp 的調度例程。參數:DeviceObject - 指向設備對象的指針。Irp - 指向請求數據包的指針。返回值:NT 狀態代碼 --*/ { PDEVICE_EXTENSION deviceExtension;deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation (Irp); return PoCallDriver(deviceExtension->NextLowerDriver, Irp); }VOID FilterUnload( IN PDRIVER_OBJECT DriverObject) /*++例程說明:釋放 DriverEntry 等中所有已分配的資源。參數:DriverObject - 指向驅動程序對象的指針。返回值:VOID.--*/ { PAGED_CODE ();// // The device object(s) should be NULL now // (since we unload, all the devices objects associated with this // driver must be deleted.// ASSERT(DriverObject->DeviceObject == NULL);// // We should not be unloaded until all the devices we control // have been removed from our queue.// DebugPrint (("unload/n"));return; }#ifdef IOCTL_INTERFACE NTSTATUS FilterCreateControlObject( IN PDEVICE_OBJECT DeviceObject ) { UNICODE_STRING ntDeviceName; UNICODE_STRING symbolicLinkName; PCONTROL_DEVICE_EXTENSION deviceExtension; NTSTATUS status;ExAcquireFastMutex (&ControlMutex);// // If this is a first instance of the device, then create a controlobject // and register dispatch points to handle ioctls.// if(1 == ++InstanceCount){// // Initialize the unicode strings// RtlInitUnicodeString(&ntDeviceName, NTDEVICE_NAME_STRING); RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);// // Create a named deviceobject so that applications or drivers // can directly talk to us without going throuhg the entire stack. // This call could fail if there are not enough resources or // another deviceobject of same name exists (name collision).// status = IoCreateDevice(DeviceObject->DriverObject, sizeof(CONTROL_DEVICE_EXTENSION), &ntDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &ControlDeviceObject);if (NT_SUCCESS( status )) {ControlDeviceObject->Flags |= DO_BUFFERED_IO;status = IoCreateSymbolicLink( &symbolicLinkName, &ntDeviceName );if (!NT_SUCCESS (status)) { IoDeleteDevice(ControlDeviceObject); DebugPrint(("IoCreateSymbolicLink failed %x/n", status)); goto End;}deviceExtension = ControlDeviceObject->DeviceExtension; deviceExtension->ControlData = NULL;ControlDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;}else { DebugPrint(("IoCreateDevice failed %x/n", status));}}End:ExReleaseFastMutex (&ControlMutex); return status;}VOID FilterDeleteControlObject( ) { UNICODE_STRING symbolicLinkName;ExAcquireFastMutex (&ControlMutex);// // If this is the last instance of the device then delete the controlobject // and symbolic link to enable the pnp manager to unload the driver.// if(!(--InstanceCount) && ControlDeviceObject){ RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);IoDeleteSymbolicLink(&symbolicLinkName); IoDeleteDevice(ControlDeviceObject); ControlDeviceObject= NULL;}ExReleaseFastMutex (&ControlMutex); }NTSTATUS FilterDispatchIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) /*++例程說明:此例程是非 passthru irp 的調度例程。 我們將檢查輸入設備對象以了解請求是否 要用于控制設備對象。如果是,我們將 處理并完成 IRP,如果不是,我們會將它向下傳遞到 較低級別的驅動程序。參數:DeviceObject - 指向設備對象的指針。Irp - 指向請求數據包的指針。返回值:NT 狀態代碼 --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status;PAGED_CODE ();// // Please note that this is a common dispatch point for controlobject and // filter deviceobject attached to the pnp stack. // if(DeviceObject != ControlDeviceObject) {// // We will just the request down as we are not interested in handling // requests that come on the PnP stack.// return FilterPass(DeviceObject, Irp);}// // Else this is targeted at our control deviceobject so let's handle it. // Here we will handle the IOCTl requests that come from the app.// status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation(Irp);switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: DebugPrint(("Create /n")); break;case IRP_MJ_CLOSE: DebugPrint(("Close /n")); break;case IRP_MJ_CLEANUP: DebugPrint(("Cleanup /n")); break;case IRP_MJ_DEVICE_CONTROL: DebugPrint(("DeviceIoControl/n")); switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {// //case IOCTL_CUSTOM_CODE: // default: status = STATUS_INVALID_PARAMETER; break;} default: break;}Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }#endif
對于附加了篩選器的設備的所有實例,該控件設備對象是公用的。因此,當啟動設備的第一個實例時,會創建它 (FilterCreateControlObject);當刪除設備的最后一個實例時,會刪除它 (FilterDeleteControlObject)。如果在移除設備的最后一個實例之前沒有刪除控件對象,則控件對象將阻止篩選器動態卸載。此示例使用了一個互斥體,還使用一個全局計數器來跟蹤實例。之所以將互斥體用于同步而不是使用自旋鎖,是因為訪問全局計數器的所有例程都在 IRQL PASSIVE_LEVEL 上運行。
總結
以上是生活随笔為你收集整理的HOWTO:将 IOCTL 发送到筛选器驱动程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: connection getconnec
- 下一篇: C++如何使用MySQL数据库