Microsoft KB Archive/262305

{|
 * width="100%"|

INFO: Sending IOCTLs to a Filter Driver

 * }

Q262305

-

The information in this article applies to:


 * Microsoft Windows 2000 Advanced Server
 * Microsoft Windows 2000 Server
 * Microsoft Windows 2000 Professional
 * Microsoft Windows 2000 Driver Development Kit (DDK)

-

SUMMARY
This article explains the problem with registering a device interface (IoRegisterDeviceInterface) in a filter driver to receive custom I/O controls (IOCTLs) from applications, and how you can work around that problem by creating a named control device object and a symbolic link.

MORE INFORMATION
Developers who are writing filter drivers may want to send custom device I/O control requests (IOCTL) from an application or another driver to their filter driver in order to control its behavior. On a Windows 2000-based computer, Microsoft recommends that drivers register the device interface in the AddDevice routine for other applications or drivers to interact with them.

Filter driver writers, following this recommendation, register an interface with their own GUID on the Physical DeviceObject (PDO) they receive in the AddDevice routine, and write a custom application to enumerate this interface GUID and send IOCTLs to the driver.

status = IoRegisterDeviceInterface (               PhysicalDeviceObject,                (LPGUID) &MY_SPECIAL_INTERFACE_GUID,                NULL,                 &devExt->InterfaceName); This approach works as long as the filter is the upper-most filter (class filter) in the stack, because that is the one that handles the request first. If the filter driver is anywhere else in the stack, the IOCTL request may be failed by either other filters or the function driver above it. It is inappropriate for a filter driver to fail requests that it doesn't know about; however, a function driver may do so. Therefore, if the filter driver is a lower filter, all the IOCTL requests unknown to the function driver are guaranteed to be failed.

The only way to avoid this problem is to create another named control device object and a symbolic link on it in the DriverEntry (as is normally done on Microsoft Windows NT 4.0), instead of registering an interface on the PDO. The application can open the symbolic link directly and send IOCTLs to it. These I/O requests are sent directly to the control device object instead of going through the entire stack, irrespective of where the filter driver is located in the stack.

Following are code examples to demonstrate how you can provide custom IOCTLs support to the generic filter sample (Filter.c) that is present in the Windows 2000 DDK toaster sample in the Src\General\Toaster\Filter\ folder (shown are only the routines that need to be modified for this purpose):

#define SYMBOLIC_NAME_STRING   L&quot;\\DosDevices\\TFilter&quot; PDEVICE_OBJECT                 ControlDeviceObject = NULL;
 * 1) define NTDEVICE_NAME_STRING   L&quot;\\Device\\TFilter&quot;

NTSTATUS FilterDispatchIo(   IN PDEVICE_OBJECT    DeviceObject,    IN PIRP              Irp    ); These lines should be added in the global section of the source:

NTSTATUS DriverEntry(   IN PDRIVER_OBJECT  DriverObject,    IN PUNICODE_STRING RegistryPath    ) /*++

--*/ {   NTSTATUS            status = STATUS_SUCCESS; ULONG              ulIndex; PDRIVER_DISPATCH * dispatch; UNICODE_STRING     NtDeviceName; UNICODE_STRING     SymbolicLinkName;

UNREFERENCED_PARAMETER (RegistryPath);

DebugPrint ((&quot;Entered the Driver Entry\n&quot;));

//    // Set all dispatch points to passthru. //    for (ulIndex = 0, dispatch = DriverObject->MajorFunction;         ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;         ulIndex++, dispatch++) {

*dispatch = FilterPass; }

//    // Now set the dispath points that we must handle as a filter. //    DriverObject->MajorFunction[IRP_MJ_PNP]            = FilterDispatchPnp; DriverObject->MajorFunction[IRP_MJ_POWER]         = FilterDispatchPower; DriverObject->DriverExtension->AddDevice          = FilterAddDevice; DriverObject->DriverUnload                        = FilterUnload;

//    // 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 through the entire stack. // This call could fail if there are not enough resources, or   // another deviceobject of same name exists (name collision). //    status = IoCreateDevice(DriverObject,                            0,                            &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); goto End; }       //         // Set the following dispatch points because we will be doing // something useful to these requests instead of just // passing it down. //        DriverObject->MajorFunction[IRP_MJ_CREATE]     = DriverObject->MajorFunction[IRP_MJ_CLOSE]     = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverObject->MajorFunction[IRP_MJ_CLEANUP]   = FilterDispatchIo; } End: //    // If you don't want the entire devicestack to fail because // of some error in your filter then return success. //    return STATUS_SUCCESS; } Because the control device object is common for all the instances of the devices that the filter attaches to, it should be created in the DriverEntry and deleted in the Unload routine. One drawback of creating device objects in DriverEntry is that the filter is not unloaded automatically if the last device stack the filter attached to is removed. You must explicitly run &quot;Net Stop&quot; on the filter service to call the filter Unload routine and delete the device object and symbolic link:

NTSTATUS FilterDispatchIo(   IN PDEVICE_OBJECT    DeviceObject,    IN PIRP              Irp    ) /*++

--*/ {   PDEVICE_EXTENSION   deviceExtension; PIO_STACK_LOCATION irpStack; NTSTATUS           status; deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

if(DeviceObject != ControlDeviceObject) { IoSkipCurrentIrpStackLocation (Irp); return IoCallDriver (deviceExtension->NextLowerDriver, Irp); }   //     // Else this is targeted at our control deviceobject so let's handle. //    status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation (Irp);

switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: DebugPrint((&quot;Create \n&quot;)); break; case IRP_MJ_CLOSE: DebugPrint((&quot;Close \n&quot;)); break; case IRP_MJ_CLEANUP: DebugPrint((&quot;Cleanup \n&quot;)); break; case IRP_MJ_DEVICE_CONTROL: // Insert your IOCTL code here. DebugPrint((&quot;Ioctl \n&quot;)); break; }   Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } This routine first checks to see whether the I/O request is meant for the control device object or for the device object that is attached to the actual device stack. If the IRP is for the control device object, it processes and completes the IRP. If the IRP is for the device stack, the routine passes it down:

VOID FilterUnload(   IN PDRIVER_OBJECT DriverObject    ) /*++

--*/ {   UNICODE_STRING      NtDeviceName; UNICODE_STRING     SymbolicLinkName;

PAGED_CODE ;

DebugPrint ((&quot;unload\n&quot;));

//    // All the devices objects associated with this // driver must be deleted. //

RtlInitUnicodeString(&SymbolicLinkName, SYMBOLIC_NAME_STRING);

IoDeleteSymbolicLink(&SymbolicLinkName); IoDeleteDevice(ControlDeviceObject);

//    // The device object(s) should be NULL now. //    ASSERT(DriverObject->DeviceObject == NULL); return; } Additional query words:

Keywords : kbDDK kbKMode kbOSWin2000 kbPlugPlay _IK kbGrpDSNTDDK

Issue type : kbinfo

Technology : kbwin2000AdvServ kbwin2000AdvServSearch kbwin2000Serv kbwin2000ServSearch kbwin2000Search kbwin2000ProSearch kbwin2000Pro kbwin2000DDK kbAudDeveloper kbWinDDKSearch kbWinAdvServSearch