HOWTO:将 IOCTL 发送到筛选器驱动程序

流微型驱动开发指南(五) PORT_CONFIGURATION_INFORMATION各成员解释如下:·SizeOfThisPacket  设定本结构的大小,由Class Driver负责填写该域。·HwDeviceExtension  指向Minidriver的设备扩展结构(Device Extension)的指针。Minidriver会藉此buffer记录一些对Minidriver来说是公有的,但是对外是私有的信息。此 阅读详情

HOWTO:将 IOCTL 发送到筛选器驱动程序

文章编号:262305
最后修改:2003年10月23日
修订:1.4
本文的发布号曾为 CHS262305

概要

本文说明如何通过创建独立的控件 deviceobject 而不是打开由筛选器驱动程序注册的专用设备接口 (IoRegisterDeviceInterface),将 IOCTL 请求发送到即插即用 (PNP) 筛选器驱动程序。

更多信息

正在编写筛选器驱动程序的开发人员可能需要将自定义设备 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;

#endif

NTSTATUS
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);
    
#endif

return 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 上运行。 
一次意外的ioctl调用错误—论不同版本内核的ioctl函数实现 前言          人要经常学会反思总结,这样才能不断的进步。同样,一个合格优秀的软件工程师也需要经常的总结反思自己工作中遇到的问题,这样才能使自己的能力不断的提升。我从来不给自己定位为程序猿,多年后,请叫我软件工程师乃至软件架构师,哈哈,又装逼了我!纵使我现在还年轻,能力阅历还未达到大师级别,但是人要有梦想,万一实现了呢?可是相比较梦想,我觉得有目标比较实际。卧槽,每次写博客都是这样,先是 阅读详情

相关推荐

Verilog实战:手把手教你实现四路组相联Cache(附完整代码解析)

本文提供了一份详细的Verilog实战指南,手把手教你实现一个四路组相联Cache。内容涵盖从设计规格、核心存储阵列、LRU替换策略到状态机设计的完整流程,并附有代码解析与优化技巧,旨在帮助硬件设计者掌握Cache控制器的RTL实现与调试方法。

pp12345的博客 516

Windows 驱动开发笔记(五)

Windows 驱动开发笔记(五)一个驱动除去能接收DeviceIoControl传过的操作代码外。还应该能够与用户进程交换数据。为了能交换数据windows设计了三种方式与用户交互 Buffered,Direct和 Neither。用户通过Createfile打开一个设备时,系统为用户创建一个文件句柄同时也创建一个IRP。这个文件句柄和IRP随同系统的进程一同管理。也就是说用户的进程消亡了这些对

bigbat的专栏 1757

AppStore逆向分析:从网络抓包到自动化模拟的完整实践

在移动应用生态中,理解客户端与服务器之间的通信协议是进行自动化测试、数据分析和系统集成的关键技术基础。通过分析网络请求与响应,可以深入理解认证、会话管理和数据交换的原理,这对于构建稳定的自动化流程至关重要。其技术价值在于能够实现合法场景下的流程模拟,例如应用元数据监控、沙盒环境测试或内部工具开发。在实际应用场景中,开发者常需处理登录态维持、请求签名验证及风控策略应对等挑战。本文聚焦于AppStore这一封闭生态,详细拆解了其登录、查询等核心环节的通信机制,并探讨了使用Python结合抓包工具进行安全逆向分析

weixin_42524171的博客 926

三键屏蔽

由于三键是winlogon在启动时注册的,在原始输入线程(raw input thread)中处理的, 所以很难屏蔽 但是在2k下屏蔽三键的方法还是有不少,常见的是 1、替换GINA 2、进程注入到winlogon 这两种方法在网上已经很普遍了,源代码也可以找到,缺点是容易闪屏,而且处理比较麻烦 理论上还有不少屏蔽方法,在系统消息的各个处理界面将其屏...

diegu9287的博客 368

SAP S/4HANA 物料分类账(ML)/实际成本核算(Actual Costing)——底表全景 & CKMLCP 执行后数据变化

插入 ML 重估凭证行项目:Dr/Cr 库存科目(期末库存调整)、Dr/Cr COGS/消耗科目(消耗重估)、Cr/Dr ML 重估抵消科目(PRY/PRV 类逻辑)also STPRS/VERPR/PEINH/LBKUM 等(但 S/4 很多“真理”在 ACDOCA)MLPP / MLPPF / MLCR / MLCRF / MLCD / CKMLMV003/004 等。Material Ledger Document(行项目明细:收货/发票价差/结算写入/重估相关)间接(PUP在CKMLCR;

weixin_52203666的博客 585

保姆级教程:用VESTA软件5分钟搞定纳米颗粒Wulff Construction建模(以Au金为例)

本文提供了一份详细的VESTA软件教程,指导用户如何在5分钟内完成纳米颗粒Wulff Construction建模,特别以金(Au)为例。从环境搭建、基础晶体结构创建到Wulff Construction设置和可视化优化,涵盖了全流程操作步骤和常见问题解决方案,适合科研新手快速上手。

weixin_29311017的博客 436

设备对象(DEVICE_OBJECT)

设备对象(DEVICE_OBJECT)

wendyWJGU的博客 1601

FPGA新手必看:Create HDL Wrapper和Generating Output Products到底该先用哪个?

本文深入解析了FPGA设计中Create HDL Wrapper与Generating Output Products的正确使用顺序,帮助新手避免常见错误。详细介绍了两者的功能差异、执行顺序的底层逻辑以及工程管理的最佳实践,特别适合使用Vivado进行FPGA开发的初学者。

xk7n92h3p5m的博客 1065

sfilter开源驱动分析(一)--文件过滤的基本步骤

NT的I/O管理器支持分层的驱动程序模式。         当应用层的CreateFile() (R3层)  --> || NtCreateFile() [I/O管理器在这一层,ntdll.dll]  -->|| 内核驱动层(R0层) ,这里讨论的主要是针对最后的内核驱动层的处理。          当每个IRP被处理的时候,它会经过驱动层中的各个驱动程序,直到最终被某个驱动程序调用IoCo

jimk1983的专栏 2697

【txt文本加密】使用 cryptography 库实现加密和解密

cryptography 库是一个强大的 Python 库,用于实现加密和解密功能。它提供了各种加密算法,包括对称加密、非对称加密、哈希函数等。

📷 图像处理践行者 | 传统算法 · 深度学习 · 多模态 | 分享实战经验与技术洞见,探索从像素到智能的无限可能。 2667

控制算法研发工程师(博士)职位深度解析与面试指南

摘要:广东万和新电气股份有限公司招聘控制算法研发工程师(博士),工作地点佛山顺德。职位要求2026届博士学历,电子信息工程或控制科学与工程专业。主要职责包括:1)燃气热水、热泵等系统的电控软件设计与优化;2)开发PID、模糊控制、ADRC、MPC等智能算法,应用于恒温控制、变频调节等场景。重点考察算法研发能力、系统稳定性优化及嵌入式实现经验。该职位提供三年资深工程师培养计划,需具备扎实的控制理论基础和工程实践能力,能够处理非线性系统、多工况自适应等复杂控制问题。

郑伟强dev的专栏 139

Windows驱动开发(7) - DEVICE_OBJECT结构体

Windows驱动开发(7) - DEVICE_OBJECT结构体typedef struct _DEVICE_OBJECT { CSHORT Type; USHORT Size; LONG ReferenceCount; struct _DRIVER_OBJECT

Vinx Blog 2488

华为OD机试双机位C卷-组装新的数组(Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【组装新的数组】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 组装新的数组。

qq_45776114的博客 1145

Ioctl返回-1 出错,解决办法

Ioctl返回-1 出错,解决办法通过APK 操作gpio驱动 点灯时,发现ioctl(gpio_fileHandler, cmd, arg) 函数返回值一直是-1.驱动无法执行ioctl 中gpio request等其他操作.我怀疑是ioctl函数有问题.发现file_operations 中ioctl用的是 .unlocked_ioctl .static const struct file_op

GUOmingbao博客 1万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

内核安全编程(一)读写驱动程序1.1

内核安全编程(一)读写驱动程序 读写驱动程序,即应用程序或者上层驱动程序发送主功能码为IRP_MJ_READ和IRP_MJ_WRITE的IO请求包(IRP) DriverEntry函数如下: NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { UNICODE_S

Debug Hacker 1626

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Windows驱动设备对象中的Flags

Flgas:此域是一个32位的无符号整型。每一个位有具体的含义,其主要位如表所示 其中比较重要的是读写操作有BUFFER和DIRECT方式,根据自己需要二选一。

苞米地里捉小鸡的博客 509

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

设备对象(DEVICE_OBJECT)

DEVICE_OBJECT结构体是操作系统用来表示某个具体的设备对象,一个设备对象是一个逻辑上的,或者虚拟的,或者物理上的设备的具体抽象,驱动通过设备对象来处理I/O请求。 typedef struct _DEVICE_OBJECT { CSHORT Type; USHORT Size; LONG

门没锁的专栏 6068

windows内核情景分析---设备驱动

设备驱动 设备栈:从上层到下层的顺序依次是:过滤设备、类设备、过滤设备、小端口设备【过、类、过滤、小端口】 驱动栈:因设备堆栈原因而建立起来的一种堆栈  老式驱动:指不提供AddDevice的驱动,又叫NT式驱动 Wdm驱动:指提供了AddDevice的驱动 驱动初始化:指IO管理器加载驱动后,调用驱动的DriverEntry、AddDevice函数 设备栈中上层设备与下层设备的绑定关

maomao171314的专栏 2055

计算机筛选器无法搜索,大师为你win7系统搜索时提示“没有与搜索条件匹配的项”的操作方法...

随着电脑的使用率越来越高,我们有时候可能会遇到win7系统搜索时提示“没有与搜索条件匹配的项问题,如果我们遇到了win7系统搜索时提示“没有与搜索条件匹配的项的问题,要怎么处理win7系统搜索时提示“没有与搜索条件匹配的项呢?我们只用1、先确定Windows Search 服务已经启动,依次打开“控制面板”》“管理工具”》“服务”,找到“Windows Search“服务,如果该服务没有启动,则先...

weixin_33240862的博客 3278

Commit failed - exit code 1 received

如何解決這個問題? 先去submodel里边, $ cd themes/next $ git add . $ git commit -m "update" $ git push origin master 然后在 git push

Kp0fS的草稿纸 284

为什么中断不能休眠

1. 中断处理的时候,不应该发生进程切换,因为在中断context中,唯一能打断当前中断handler的只有更高优先级的中断,它不会被进程打断(这点对 于softirq,tasklet也一样,因此这些bottom half也不能休眠),如果在中断context中休眠,则没有办法唤醒它,因为所有的 wake_up_xxx都是针对某个进程而言的,而在中断context中,没有进程的概念,没有一个tas

jmflovezlf的专栏 1419

windows 驱动开发基础(二)事件通知---关于irp处理,DPC,链表等

代码来源及参考:wdk 7,路径:C:\WinDDK\7600.16385.1\src\general\event 这个例子演示了两种关于当硬件事件发生时,驱动如何通知应用程序的方法。一种是基于event的,一种是基于IRP。但是样例驱动程序实际上没有与任何硬件通信,所以就通过 timer DPC 来模拟硬件事件。应用程序告诉驱动是通过设置event 信号还是完成 pending IRP 来通知自己,并给出一个相对的超时时限。 两种方法的处理流程: 1,基于event的方法 应用程序通过...

pureman_mega的博客 1163
上一篇: 对USB驱动程序的理解
下一篇: Template Metaprogramming
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值