虚拟设备驱动程序两关键问题(下)
发表于:2007-07-01来源:作者:点击数:
标签:
Windows 采用基于消息的事件驱动机制,而VxD并不提供直接发往应用程序线程的消息,所以PostMessage所发消息与其它众多的消息都在主线程的消息循环中处理。这样,当执行一些界面操作时,大量的消息占据了消息队列,VxD所发送的消息就有可能得不到相应的处理。
Windows采用基于消息的事件驱动机制,而VxD并不提供直接发往应用程序线程的消息,所以PostMessage所发消息与其它众多的消息都在主线程的消息循环中处理。这样,当执行一些界面操作时,大量的消息占据了消息队列,VxD所发送的消息就有可能得不到相应的处理。为解决这一问题,在实际设计中可采用的方法有两种:第一种是仍采用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) & GlobalV
MInfo;
*( (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 _s
tdcall 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的编程起到十分重要的作用。希望本文能给大家带来一些帮助。
原文转自:http://www.ltesting.net