驱动程序怎样和应用程序通信?
2007-12-26 16:11
190 查看
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;
}
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;
}
相关文章推荐
- 应用程序与驱动程序6种通信方式
- 【转帖】如何建立应用程序和驱动程序间的通信
- 驱动开发之 用DeviceIoControl实现应用程序与驱动程序通信
- 驱动程序和应用程序之间通信
- 驱动程序和应用程序之间通信(ForWinCE)(转载)
- 应用程序与驱动程序的通信
- 驱动程序和应用程序通信方法
- 驱动程序与应用程序之间的通信
- 驱动程序与应用程序之间的通信
- 驱动开发之 用DeviceIoControl实现应用程序与驱动程序通信
- 应用程序与驱动程序的通信
- 驱动程序和应用程序之间通信(For Win2000 or later )
- 驱动程序与应用程序之间的通信
- 驱动程序与应用程序之间的通信
- CreateFile DeviceIoControl dwIoControlCode——应用程序与驱动程序通信
- 驱动程序与应用程序之间的通信
- 驱动程序与应用程序之间的通信
- kmdf驱动教程2——驱动程序与应用程序通信
- 驱动程序与应用程序之间的通信
- 【转帖】驱动程序与应用程序之间的通信