如何将类成员方法作为回调调用?(无std工具+模板传参场景)
内核驱动OOP架构中调用非静态成员作为DPC回调的解决方案
核心思路
内核DPC回调要求使用无this指针的函数(静态函数或全局函数),而你无法将目标回调设为静态,因此需要通过静态适配器函数中转:把Log类实例的指针存入回调上下文(NotifyRecord),适配器函数从上下文取出实例指针后,再调用对应的非静态成员方法。
具体实现步骤
1. 扩展NotifyRecord结构
在你的NOTIFY_RECORD中添加成员,用于保存Log类的实例指针:
typedef struct _NOTIFY_RECORD { KDPC Dpc; // 保留原有成员... Log* LogInstance; // 新增:存储Log类实例的指针 } NOTIFY_RECORD, *PNOTIFY_RECORD;
2. 添加静态适配器函数
在Log类中定义一个静态成员函数,严格匹配DPC回调的签名:
class Log { public: VOID LogNotifyUsermodeCallback(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2); NTSTATUS LogRegisterIrpBasedNotification(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS LogRegisterEventBasedNotification(PDEVICE_OBJECT DeviceObject, PIRP Irp); private: // 静态适配器函数,作为DPC的直接回调 static VOID LogNotifyUsermodeCallbackAdapter(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2); };
3. 实现适配器函数
适配器函数负责从上下文取出Log实例指针,转而调用非静态成员方法:
VOID Log::LogNotifyUsermodeCallbackAdapter(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) { PNOTIFY_RECORD NotifyRecord = reinterpret_cast<PNOTIFY_RECORD>(DeferredContext); // 通过实例指针调用非静态回调方法 NotifyRecord->LogInstance->LogNotifyUsermodeCallback(Dpc, DeferredContext, SystemArgument1, SystemArgument2); }
4. 修改DPC初始化代码
在LogRegisterIrpBasedNotification中,将当前Log实例指针存入NotifyRecord,再将适配器函数作为回调传入KeInitializeDpc:
NTSTATUS Log::LogRegisterIrpBasedNotification(PDEVICE_OBJECT DeviceObject, PIRP Irp) { // 假设已完成NotifyRecord的分配与初始化 NotifyRecord->LogInstance = this; // 存入当前Log实例指针 KeInitializeDpc(&NotifyRecord->Dpc, LogNotifyUsermodeCallbackAdapter, // 传入静态适配器函数 NotifyRecord // 上下文仍为NotifyRecord,包含实例指针 ); // 其他业务代码... }
关键说明
- 静态适配器函数不需要
this指针,完全符合内核DPC回调的签名要求。 - 通过上下文传递Log实例指针,让非静态成员方法能正常访问类内其他成员,不受模板参数限制。
- 需确保
NOTIFY_RECORD的生命周期覆盖DPC的执行周期,避免野指针问题。
内容的提问来源于stack exchange,提问作者Barbosso
相关产品推荐
相关产品推荐

