虚拟设备驱动程序关键问题之消息队列

2010-08-28 10:45:15来源:西部e网作者:

    因为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) & 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的编程起到十分重要的作用。希望本文能给大家带来一些帮助。
关键词:虚拟设备驱动