驱动程序怎样和应用程序通信?

本文介绍了两种内核通知应用层的方式:通过VxD使用Shell_PostMessage传递消息,以及通过Sys驱动程序创建设备并利用DeviceIoControl进行异步通知。提供了具体代码示例,包括IM_CTRL_Open、IM_CTRL_Close等函数的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、内核通知应用层方法: 
a、如果是vxd,使用shell_postmessage是最简单的方法,但是只能传递两个DWORD。walter oney的 
那本关于vxd的书中有更详细的描述,该书的中文版可以在侯俊杰的网站上下载。还有一本关于vxd得好书, 
《windows vxd与设备驱动权威指南》,孙喜明译,作者名字太怪,我记不住,但是个msj上的牛人。这本 
书翻译的不错,孙喜明是98/99活跃在tsinghua bbs上的vxd高手。 
b、如果是sys,思路如下:首先在driver中IoCreateDevice,然后让应用层创建一个线程,调用deviceioctl, 
异步调用,然后等待事件。驱动程序到了需要通知应用层的时候,iocompleteirp,应用层的那个事件就 
变成有信号的,然后就可以得到通知的数据。你可以参考我的代码(附件1,附件2)。该方法同样适用于 
vxd,但是由于vxd没有系统队列的概念,因此你需要使用自定义队列管理应用层请求。稍稍费劲,可以参考 
98ddk/src/net/ndis/vpacket目录下的实现。 


附件1、 
请注意看notifyevent函数。 
当驱动程序需要通知应用层的时候,调用notifyevent函数。 

/*++  

Copyright (c) 2001  

Module Name:  

devctrl.c  

Abstract:  



Author:  

Environment:  


Revision History:  


--
*/  


#include 
"ioctl.h"  



NTSTATUS  
IM_CTRL_Open(  
             IN PDEVICE_OBJECT DeviceObject,  
             IN PIRP Irp  
             )  

/*++  

Routine Description:  

This is the dispatch routine for create/open and close requests.  
These requests complete successfully.  

Arguments:  

DeviceObject - Pointer to the device object.  

Irp - Pointer to the request packet.  

Return Value:  

Status is returned.  

--
*/  

{  
    NTSTATUS status 
= STATUS_SUCCESS;  
    
    DBGPRINT((
"OpenAdapter "));  
    
    Irp
->IoStatus.Status = status;  
    IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    
return status;  
    
}  



NTSTATUS  
IM_CTRL_Close(  
              IN PDEVICE_OBJECT DeviceObject,  
              IN PIRP Irp  
              )  

/*++  

Routine Description:  

This is the dispatch routine for create/open and close requests.  
These requests complete successfully.  

Arguments:  

DeviceObject - Pointer to the device object.  

Irp - Pointer to the request packet.  

Return Value:  

Status is returned.  

--
*/  

{  
    
    NTSTATUS status 
= STATUS_SUCCESS;  
    
    DBGPRINT((
"CloseAdapter  "));  
    
    Irp
->IoStatus.Status = status;  
    IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    
return status;  
}  

NTSTATUS  
IM_CTRL_Cleanup(  
                IN PDEVICE_OBJECT DeviceObject,  
                IN PIRP Irp  
                )  

/*++  

Routine Description:  

This is the dispatch routine for cleanup requests.  
This routine is called whenever a handle to the device  
is closed.  

Arguments:  

DeviceObject - Pointer to the device object.  

Irp - Pointer to the request packet.  

Return Value:  

Status is returned.  

--
*/  

{  
    
    NTSTATUS status 
= STATUS_SUCCESS;  
    
    DBGPRINT((
"Packet: Cleanup "));  
    
    Irp
->IoStatus.Status = status;  
    IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    
return status;  
}  
/*  
VOID  
IM_CTRL_Unload(  
IN PDRIVER_OBJECT DriverObject  
)  
{  

UNICODE_STRING win32DeviceName;  

DBGPRINT(("Unload Enter "));  

//  
// First delete the Control deviceobject and the corresponding  
// symbolicLink  
//  

RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);  
IoDeleteSymbolicLink(&win32DeviceName);  
if(Globals.ControlDeviceObject)  
IoDeleteDevice(Globals.ControlDeviceObject);  

DBGPRINT(("Unload Exit "));  

}  
*/  

NTSTATUS  
IM_CTRL_IoControl(  
                  IN PDEVICE_OBJECT DeviceObject,  
                  IN PIRP Irp  
                  )  
{  
    NTSTATUS Status 
= STATUS_SUCCESS;  
    PIO_STACK_LOCATION irpStack;  
    PVOID ioBuffer;  
    ULONG inputBufferLength;  
    ULONG outputBufferLength;  
    ULONG ioControlCode;  
    ULONG RequireLength
=0;  
    PADAPT pAdapt;  
    UINT AdapterNum;  
    PDEVICE_EXTENSION pDevExt;  
    KIRQL OldIRQL;  
    
    pDevExt 
= DeviceObject->DeviceExtension;  
    
    irpStack 
= IoGetCurrentIrpStackLocation(Irp);  
    
    ioControlCode
= irpStack->Parameters.DeviceIoControl.IoControlCode;  
    
    ioBuffer 
= Irp->AssociatedIrp.SystemBuffer;  
    inputBufferLength 
= irpStack->Parameters.DeviceIoControl.InputBufferLength;  
    outputBufferLength 
= irpStack->Parameters.DeviceIoControl.OutputBufferLength;  
    Status 
= NDIS_STATUS_SUCCESS;  
    
    KeAcquireSpinLock(
&ImdGlobals.SpinLock,&OldIRQL);  
    
    
switch (ioControlCode)  
    {  
    
case GET_EVENT_MSG:  
        
if(outputBufferLength<sizeof(EVENTMSG))  
        {  
            Status 
= STATUS_BUFFER_TOO_SMALL;  
            
break;  
        }  
        
        IoMarkIrpPending(Irp);  
        IoStartPacket(DeviceObject,Irp,NULL,CancelIrp);  
        Status 
= STATUS_PENDING;  
        KeReleaseSpinLock(
&ImdGlobals.SpinLock,OldIRQL);  
        
return Status;  
    
case SET_OPTION :  
        
// ............ more case  
    default:  
        Status 
= STATUS_INVALID_PARAMETER;  
        
break;  
    }  
    
    KeReleaseSpinLock(
&ImdGlobals.SpinLock,OldIRQL);  
    
    Irp
->IoStatus.Status = Status;  
    Irp
->IoStatus.Information = outputBufferLength;  
    
    IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    
    
return Status;  
}  

VOID  
CancelIrp(  
          IN PDEVICE_OBJECT DeviceObject,  
          IN PIRP Irp  
          )  
{  
    
if(Irp == DeviceObject->CurrentIrp)  
    {  
        IoReleaseCancelSpinLock(Irp
->CancelIrql);  
        IoStartNextPacket(DeviceObject,TRUE);  
    }  
    
else  
    {  
        KeRemoveEntryDeviceQueue(  
            
&DeviceObject->DeviceQueue,  
            
&Irp->Tail.Overlay.DeviceQueueEntry  
            );  
        IoReleaseCancelSpinLock(Irp
->CancelIrql);  
    }  
    Irp
->IoStatus.Status = STATUS_CANCELLED;  
    Irp
->IoStatus.Information;  
    IoCompleteRequest(Irp,IO_NO_INCREMENT);  
    
return;  
}  

VOID  
StartIo(  
        IN PDEVICE_OBJECT DeviceObject,  
        IN PIRP Irp  
        )  
{  
    
return;  
}  

BOOLEAN  
NotifyEvent(  
            IN PEVENTMSG EventMsg  
            )  
{  
    PDEVICE_OBJECT DeviceObject 
= ImdGlobals.ControlDeviceObject ;  
    PIRP Irp ;  
    PVOID ioBuffer;  
    ULONG inputBufferLength;  
    ULONG outputBufferLength;  
    NTSTATUS Status 
= STATUS_SUCCESS;  
    PIO_STACK_LOCATION irpStack;  
    KIRQL CancelIrql;  
    
    Irp 
= DeviceObject->CurrentIrp;  
    
    
if(!Irp) return FALSE;  
    
    IoAcquireCancelSpinLock(
&CancelIrql);  
    
if(Irp->Cancel)  
    {  
        IoReleaseCancelSpinLock(CancelIrql);  
        
return FALSE;  
    }  
    IoSetCancelRoutine(Irp,NULL);  
    IoReleaseCancelSpinLock(CancelIrql);  
    irpStack 
= IoGetCurrentIrpStackLocation(Irp);  
    ioBuffer 
= Irp->AssociatedIrp.SystemBuffer;  
    inputBufferLength 
= irpStack->Parameters.DeviceIoControl.InputBufferLength;  
    outputBufferLength 
= irpStack->Parameters.DeviceIoControl.OutputBufferLength;  
    
    
if(outputBufferLength<sizeof(EVENTMSG))  
    {  
        outputBufferLength 
= 0;  
        Status 
= STATUS_BUFFER_TOO_SMALL;  
    }  
    
else  
    {  
        RtlCopyMemory(ioBuffer,EventMsg,
sizeof(EVENTMSG));  
        outputBufferLength 
= sizeof(EVENTMSG);  
    }  
    
    Irp
->IoStatus.Status = Status;  
    Irp
->IoStatus.Information = outputBufferLength;  
    
    IoStartNextPacket(DeviceObject,TRUE);  
    
    IoCompleteRequest(Irp,IO_NO_INCREMENT);  
    
    
return TRUE;  
    
}  

附件2、 
你需要仔细看的函数是GetEventMsg。 

 

#include "stdafx.h"  
#include 
"winioctl.h"  
#include 
"define.h"  





typedef 
struct _ANSY_IMD_EVENT_MSG  
{  
    OVERLAPPED OverLapped;  
    UCHAR Buffer[
sizeof(IMDEVENTMSG)];  
} ANSY_IMDEVENTMSG, 
*PANSY_IMDEVENTMSG;  

//  
// hEventStop must be created by such code:  
// hEventStop = CreateEvent(  
// 0,  
// TRUE,  
// FALSE,  
// NULL  
// );  
// when caller want the GetEventMsg exit the block,  
// just SetEvent(hEventStop);  

BOOL  
GetEventMsg(  
            IN HANDLE hDev,  
            IN HANDLE hEventStop,  
            OUT PIMDEVENTMSG EventMsg  
            )  
{  
    BOOL bRet;  
    
static ANSY_IMDEVENTMSG Packet[32];  
    
static HANDLE hEvent[32+1];  
    
static bool s_bFirstCall = TRUE;  
    DWORD cb;  
    HANDLE hEventNew;  
    
int i,j,k;  
    
    
if(s_bFirstCall) // if first call ,let's call 32 times readfile first  
    {  
        
for(i=0;i<32;i++)  
        {  
            Packet.OverLapped.Offset
=0;  
            Packet.OverLapped.OffsetHigh
=0;  
            Packet.OverLapped.hEvent
=CreateEvent(  
                
0,  
                TRUE,  
                FALSE,  
                NULL  
                ); 
// manual reset,initial=false  
            hEvent=Packet.OverLapped.hEvent;  
            
            bRet 
= DeviceIoControl(  
                hDev,  
                GET_EVENT_MSG,  
                NULL,  
                
0,  
                Packet.Buffer,  
                
sizeof(IMDEVENTMSG),  
                
&cb,  
                
&Packet.OverLapped  
                );  
        }  
        hEvent[
32]=hEventStop;  
        
        s_bFirstCall
=false;  
    }  
    
    i
= WaitForMultipleObjects( // which read return?  
        33,  
        hEvent,  
        
false// wait untill one hevent signal  
        INFINITE // wait forever  
        );  
    
    
if(i==WAIT_FAILED) return false;  
    
    
if(i==32)  
    {  
        ASSERT(hEvent 
== hEventStop);  
        
return true// hEventStop raise  
    }  
    
    
for(j=0;j<32;j++)  
    {  
        
if(Packet[j].OverLapped.hEvent ==hEvent) break// which read return?  
    }  
    
    k
=j;  
    
    cb
=0;  
    bRet
=GetOverlappedResult(  
        hDev,  
        
&Packet[k].OverLapped,  
        
&cb,  
        
false  
        );  
    
    
if(!bRet)  
    {  
        printf(
"GetOverlappedResult failed!!! ");  
        
return false;  
    }  
    
    ASSERT(cb 
== sizeof(IMDEVENTMSG));  
    
    memcpy((
void *)EventMsg,(void *)Packet[k].Buffer,cb);  
    
    CloseHandle(Packet[k].OverLapped.hEvent);  
    
    
for(j=i;j<32;i++) hEvent=hEvent[++j];  
    
    hEventNew
=CreateEvent(0, TRUE, 0, NULL);  
    
if(!hEventNew)  
    {  
        printf(
"Can not create event! ");  
        
return false;  
    }  
    
    Packet[k].OverLapped.hEvent
=hEventNew;  
    memset(Packet[k].Buffer,
0,sizeof(IMDEVENTMSG));  
    hEvent[
31]=hEventNew;  
    
    
// k返回了,就再读K一次  
    bRet = DeviceIoControl(  
        hDev,  
        GET_EVENT_MSG,  
        NULL,  
        
0,  
        Packet[k].Buffer,  
        
sizeof(IMDEVENTMSG),  
        
&cb,  
        
&Packet[k].OverLapped  
        );  
    
    
return bRet;  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值