为解决这一问题,在实际设计中可采用的方法有两种:第一种是仍采用PostMessage,但在应用程序和VxD中需设置标志位,判断消息是否被处理并作了相应的工作(如重传数据);第二种是使用Win32事件机制,将一个线程专用于等待响应Win32事件,而另一些线程用于其它处理。下面给出VxD利用Win32事件机制激活Win32应用程序线程的部分例程(见程序2)。当生成或消除(destroy)一个VM,VxD便通知注册的应用程序,并显示出相应的信息。
在VxD中,
DWORD OnW32Deviceiocontrol ( PDIOCPARAMETERS p ) //VxD与Win32应用程序的接口函数 { DWORD rc; swirch ( p-$#@62;dwIoControlCode ) { case DIOC_OPEN: //系统定义功能号:设备打开 rc = 0; break; case DIOC_CLOSEHANDLE: //设备关闭 bClientRegistered = FALSE; rc = 0; break; case EVENTVXD_REGISTER: //自定义功能号 hWin32Event = p-$#@62;lpvInBuffer; *( (DWORD *) (p-$#@62;lpvOutBuffer) ) = (DWORD) & GlobalVMInfo; *( (DWORD *) (p-$#@62;lpcbBytesReturned) ) = sizeof (DWORD); bClientRegistered = TRUE; rc = 0; break; default: rc = 0xffffffff; } return rc; //若返回0表示成功 } BOOL OnVmInit ( VMHANDLE hVM ) //一旦有VM被初始化便执行 { if ( bClientRegistered ) { GlobalVMInfo.hVM = hVM; GlobalVMInfo.bVmCreated = TRUE; Call_Priority_VM_Event (LOW_PRI_DEVICE_BOOST , Get_Sys_VM_Handle() , PEF_WAIT_FOR_STI+PEF_WAIT_NOT_CRIT , hWin32Event , PriorityEventThunk , 0 ); //使System VM为当前运行状态,将Ring0级事件句柄作为回调过程的参数 } return TRUE; } VOID OnVmTerminate ( VMHANDLE hVM ) //一旦有VM被终结便执行 { if ( bClientRegistered ) { GlobalVMInfo.hVM = hVM; GlobalVMInfo.bVmCreated = FALSE; Call_Priority_VM_Event (LOW_PRI_DEVICE_BOOST , Get_Sys_VM_Handle() , PEF_WAIT_FOR_STI+PEF_WAIT_NOT_CRIT , hWin32Event , PriorityEventThunk , 0 ); } } VOID _stdcall PriorityEventHandler ( VMHANDLE hVM , PVOID Refdata , CRS * pRegs ) { HANDLE hWin32Event = Refdata; _VWIN32_SetWin32Event ( hWin32Event ); //激活事件对象 } |
在Win32应用程序中;
VOID main ( int ac , char *av[ ] ) { hEventRing3 = CreateEvent ( 0 , FALSE , FALSE , NULL ); //生成Ring3级事件句柄 if ( !hEventRing3 ) { printf ( "Cannot create Ring3 event\n" ); exit ( 1 ); } hKernel32Dll = LoadLibrary ( "kernel32.dll" ); if ( !hKernel32Dll ) { printf ( "Cannot load KERNEL32.DLL\n" ); exit ( 1 ); } pfOpenVxDHandle = ( HANDLE ( WINAPI * ) ( HANDLE ) ) GetProcAddress ( Kernel32Dll , "OpenVxDHandle" ); If ( !pfOpenVxDHandle ) { printf ( "Cannot get addr of OpenVxDHandle\n" ); exit ( 1 ); } hEventRing0 = (*pfOpenVxDHandle ) ( hEventRing3 ); //将Ring3级事件句柄转换为Ring0级事件句柄 if ( !hEventRing0 ) { printf ( "Cannot create Ring0 event\n" ); exit ( 1 ); } hDevice = CreateFile ( VxDName , 0 , 0 , 0 , CREATE_NEW , FILE_FLAG_DELETE_ON_CLOSE , 0 ); //动态加载VxD if ( !hDevice ) { printf ( "Cannot load VxD error = %x\n" , GetLastError ( ) ); exit ( 1 ); } if ( !DeviceIoControl ( hDevice , EVENTVXD_REGISTER , hEventRing0 , sizeof ( hEventRing0 ) , &pVMInfo , sizeof ( pVMInfo ) , &cbBytestReturned , 0 ) ) //Win32程序与VxD的接口函数,将Ring0级事件句柄传入VxD,从VxD传出GlobalVMInfo结构的指针 { printf ( "DeviceIoControl REGISTER failed\n" ); exit ( 1 ); } CreateThread ( 0 , 0x1000 , SecondThread , hEventRing3 , 0 , &tid ); //创建线程 printf ( "Press any key to exit..." ); getch ( ); CloseHandle ( hDevice ); } DWORD WINAPI SecondThread ( PVOID hEventRing3 ) { while ( TRUE ) { WaitForSingleObject ( ( HANDLE ) hEventRing3 , INFINITE ); //等待相应事件 printf ( "VM %081x was %x" , pVMInfo-$#@62;hVM , pVMInfo-$#@62;bCreated ? "created": "destroyed" ); //显示被created或destroyed的VM } return 0; } (程序2) |
三、结束语
虽然VxD的设计还涉及到其它许多方面,但掌握解决以上关键问题的细节将对VxD的编程起到十分重要的作用。希望本文能给大家带来一些帮助。