為解決這一問題,在實際設計中可采用的方法有兩種:第一種是仍采用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的編程起到十分重要的作用。希望本文能給大家帶來一些幫助。

