静下来,定好方向,好好干。
分类: WINDOWS
2008-05-21 14:09:50
《设备驱动程序通知应用程序的几种方法》
各部分实现的部分代码如下:
. init()
{
VMINFO *pVmInfo;
if(bCreated){
pVmInfo = _HeapAllocate(sizeof(VMINFO),0);
if(pVmInfo){
pVmInfo ->bCreated = TRUE;
pVmInfo ->hVm = 0;
strcpy(pVmInfo->buffer, "Apc test program!");
_VWIN32_QueueUserApc(backcallFunc,(DWORD)pVmInfo,appThread);
//向应用程序发送消息,调用回调函数。
}
}
return;
}
hEventRing3 = CreateEvent( 0,FALSE,FALSE,NULL); //主线程:创建一个Ring3事件
if(!hEventRing3){
AfxMessageBox("Cannot Create the event!");
exit(1);
}
hKernel32Dll = LoadLibrary("Kernel32.dll"); //加载未公开的动态链接库。
if(!hKernel32Dll){
AfxMessageBox("Cannot load the Kernel32.dll");
exit(1);
}
pfOpenVxDHandle = (HANDLE(WINAPI*)(HANDLE))
GetProcAddress(hKernel32Dll,"OpenVxDHandle");
//调用GetProcAddress获取OpenVxDHandle的地址。
if(!pfOpenVxDHandle){
AfxMessageBox("Cannot Open the VxD handler");
exit(1);
}
hEventRing0 = (*pfOpenVxDHandle)(hEventRing3); //得到Ring3事件的Ring0句柄。
if(!hEventRing0){
AfxMessageBox("Cannot create the ring0 handler!");
exit(1);
}
hDevice = CreateFile("\\\\.\\eventvxd.vxd",0,0,0,
CREATE_NEW,FILE_FLAG_DELETE_ON_CLOSE,0); //动态加载设备驱动程序
if(!hDevice){
report("Cannot Load VxD eror = %x",GetLastError());
exit(1);
}
DWORD x;
DWORD cbBytesReturn;
if(!DeviceIoControl(hDevice,EVENT_REGISTER,hEventRing0,sizeof(hEventRing0),&x,sizeof(DWORD),&cbBytesReturn,0)){ //将事件的Ring0句柄传送给设备驱动程序。
report("DeviceIoControl failed:error %x",GetLastError());
exit(1);
}
pVmDDB = (VmDDB *)x;
AfxBeginThread(backCallFunc,GetSafeHwnd()); //创建一个辅助线程等待事件的有信号。
……………………………… //主线程干其它的事情。
UINT backCallFunc(LPVOID lParam) //辅助线程
{
while(1)
{
WaitForSingleObject((HANDLE)hEventRing3,INFINITE);//等待事件的发生。
……………………………… //响应VxD的通知。
}
return 0;
}
设备驱动程序部分:
case EVENT_REGISTER:
hEventRing0 = p->dioc_InBuf; //得到事件的Ring0句柄。
*(DWORD *)p->dioc_OutBuf = (DWORD *)(&pVmDDB);
*(DWORD *)p->dioc_bytesret = sizeof (DWORD);//(DWORD *)(&pVmDDB);
returnCode = 0;
break;
case EVENT_MESSAGE:
oper.a = ((operators*)(p->dioc_InBuf))->a;
oper.b = ((operators*)(p->dioc_InBuf))->b;
pVmDDB.z = oper.a * oper.b;
_VWIN32_SetWin32Event(hEventRing0);
//条件成熟时,设备驱动程序将事件设置为有信号状态。
returnCode = 0;
break;
#define WM_MY_MESSAGE 0x0410 //自定义消息
BEGIN_MESSAGE_MAP(CIrqTest, CDialog) //将自定义消息加入消息循环。
ON_MESSAGE(WM_MY_MESSAGE,MyMessage)
//{{AFX_MSG_MAP(CIrqTest)
ON_BN_CLICKED(IDC_START, OnStart)
ON_BN_CLICKED(IDC_STOP, OnStop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CIrqTest::OnStart()
{
// TODO: Add your control notification handler code here
hDevice =
CreateFile("\\\\.\\testirq.vxd",0,0,0,CREATE_NEW,FILE_FLAG_DELETE_ON_CLOSE,0);
//动态加载设备驱动程序。
if(hDevice == INVALID_HANDLE_VALUE){
DWORD errorCode;
errorCode = GetLastError();
AfxMessageBox("Cannot load the testIrq.vxd");
if(errorCode == ERROR_NOT_SUPPORTED){
DeleteFile("\\\\.\\testirq");
}
exit(1);
}
HWND hWnd = GetSafeHwnd(); //获得当前窗口的句柄。
if(!DeviceIoControl(hDevice,W32IF_PASS_EVENT,&hWnd,sizeof(DWORD),NULL,0,NULL,0)) //将当前窗口句柄传送给设备驱动程序。
AfxMessageBox("DeviceIoControl failed!");
GetDlgItem(IDC_START)->EnableWindow(FALSE);
}
LRESULT CIrqTest::MyMessage(WPARAM wParam, LPARAM lParam)
//自定义消息处理函数
{
UpdateData(TRUE);
if(m_nLing == "")
m_nLing = "lingling";
else
m_nLing = "";
UpdateData(FALSE);
return 0;
}
设备驱动程序部分:
#define WM_MY_MESSAGE 0x0410 //自定义消息
case W32IF_PASS_EVENT:
PostMsghWnd=(DWORD*)p->dioc_InBuf;
hWnd=(HANDLE)*PostMsghWnd; //获得主窗口句柄
returnCode = 0;
break;
VOID _stdcall EventHandler(VMHANDLE hVM,PVOID RefData,CLIENT_STRUCT *pRegs)
{
//在中断服务例程中,对中断计数器计数并向Ring 3层应用程序发送自定义消息;
if( hWnd && ( TickCounter%100 == 0 ) ){
SHELL_PostMessage(hWnd,WM_MY_MESSAGE,0,0,NULL,NULL);
//条件成熟时,设备驱动程序向应用程序发送消息。
}
TickCounter++;
ReadCMOS(STATREG_C);//清除RTC状态标志
}
HANDLE hWdm1 = CreateFile("\\\\.\\Wdm1dev-0", //加载设备驱动程序。
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
if( hWdm1==INVALID_HANDLE_VALUE){
printf("XXX Could not find open Wdm1 device\n");
return 1;
}
printf(" Opened OK\n");
DWORD junk;
OVERLAPPED Overlapped;
DWORD BytesReturned;
Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//创建一个手动复位的事件,事件的初始状态为无信号状态。
DWORD code;
if (DeviceIoControl(hWdm1,IOCTL_WDM1_ASYN,
NULL, 0, // Input
NULL, 0, // Output
&BytesReturned,&Overlapped)){
code= 0;
}else{
code = GetLastError();
printf("return device pending:%d\n",code);
}
………………………………//进行一些其它的工作。
WaitForSingleObject(Overlapped.hEvent,INFINITE); //等待事件变成有信号状态。
ResetEvent(Overlapped.hEvent ); //手动复位事件。
if (code == ERROR_IO_PENDING){
if (GetOverlappedResult(hWdm1, &Overlapped, &junk, TRUE)){ //重叠I/O操作。
code = 0;
}
else
code = GetLastError();
}
if (code != 0)
printf("Error!\n");
else
printf("Ansynchronic I/O ok!\n");
设备驱动程序部分:
// Get access to the shared buffer
KIRQL irql;
KeAcquireSpinLock(&BufferLock,&irql);
switch( ControlCode){
………………………………
case IOCTL_WDM1_ASYN:
IoMarkIrpPending(Irp); //将IRP标志为挂起状态。
IoStartPacket(fdo,Irp,1,CancelIrp);
//如果当前设备驱动程序忙,则将IRP放入队列中,否则马上调用StartIo例程。
KeReleaseSpinLock(&BufferLock,irql);
status = STATUS_PENDING;
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 = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return;
}
NTSTATUS CompleteIrp( PIRP Irp, NTSTATUS status, ULONG info)
//在适当的时候调用它,完成IRP。
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
}
VOID StartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) //StartIo例程
{
ULONG i,j,k;
ULONG z;
…………………………//进行一些其它的处理。
CompleteIrp(Irp,STATUS_SUCCESS,0); //完成IRP。
return;
}
HANDLE hEvent;
DWORD junk;
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //创建一个事件
if(!DeviceIoControl(hWdm1,IOCTL_WDM1_EVENT,&hEvent,sizeof(hEvent),NULL,0,&junk,NULL)){ //将事件句柄传送给设备驱动程序
printf("Error %d in IOCTL_REGISTER_EVENT call\n", GetLastError());
CloseHandle(hEvent);
CloseHandle(hWdm1);
return 1;
}
HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &junk);
//创建辅助线程
辅助线程部分:
DWORD WINAPI ThreadProc(LPVOID junkola)
{ // ThreadProc
WaitForSingleObject(hEvent, INFINITE); //等待事件变成有信号状态。
puts("\nEvent happened\n");
return 0;
} //ThreadProc
设备驱动程序部分:
case IOCTL_WDM1_EVENT:
if( InputLength != sizeof(HANDLE))
status = STATUS_INVALID_PARAMETER;
else{
HANDLE EventMsg = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
//获取事件的句柄。
status = ObReferenceObjectByHandle(EventMsg,
EVENT_MODIFY_STATE,
*ExEventObjectType,
Irp->RequestorMode,
(PVOID*)(&dx->pEvent),
NULL); //得到事件的参考地址。
}
…………………………………………………………
KeSetEvent(dx->pEvent,0,FALSE); //当条件具备时,将事件置为有信号状态。
NTSTATUS Wdm1Close(IN PDEVICE_OBJECT fdo,IN PIRP Irp){
PWDM1_DEVICE_EXTENSION
dx = (PWDM1_DEVICE_EXTENSION)fdo->DeviceExtension;
if(dx->pEvent){
ObDereferenceObject(dx->pEvent);
dx->pEvent = NULL;
}
………………;
}