通过内核对象在服务程序和桌面程序之间通信

来源:互联网 发布:开淘宝代理 编辑:程序博客网 时间:2024/06/15 17:16

 

关于在通过 事件对象 在服务程序和普通桌面应用程序相互之间通信的问题,分类情况进行讨论:
1、普通桌面应用程序中创建事件,服务程序中打开事件
 XP的情况
普通桌面应用程序中创建:

  1. m_hEvent = ::CreateEvent(NULL, FALSE, FALSE, TEXT("{67BDE5D7-C2FC-49f5-9096-C255AB791B75}"));

服务程序中打开并置其为有信号:

  1. HANDLE hEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("{67BDE5D7-C2FC-49f5-9096-C255AB791B75}"));
  2. DWORD dwErr = ::GetLastError();
  3. ::SetEvent(m_hEvent);

 vista下情况
vista下有点问题是,如果像上面那样写的话,服务程序在打开该事件对象时报错“系统找不到指定的文件。”,原因是XP下服务程序和应用程序创建的内核对象的命名空间默认是全局的,而vista下则不是,服务创建的内核对象默认在session0下,而用户创建的内核对象默认在各自的session下(session1,session2……),解决此问题的方法很简单,就是在创建命名时间对象时指定名字是全局的,也就是将CreateEvent和OpenEvent的最后一个参数设置为TEXT("Global//{67BDE5D7-C2FC-49f5-9096-C255AB791B75}")。

2、服务程序中创建事件,普通桌面应用程序中打开事件
下面就不分系统说明,只说说根本的问题。

服务程序中创建:

  1. m_hEvent = ::CreateEvent(NULL, FALSE, FALSE, TEXT("{67BDE5D7-C2FC-49f5-9096-C255AB791B75}"));

普通桌面应用程序中打开:

  1. HANDLE hEvent = ::OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("{67BDE5D7-C2FC-49f5-9096-C255AB791B75}"));
  2. ::SetEvent(hEvent);

上面的代码不能正常工作,在普通桌面应用程序中打开事件对象时,报错“拒绝访问。”,并且获得的事件句柄是NULL,原因是这样的,在服务程序中创建的内核对象,默认情况下桌面程序无法打开这个对象,每个内核对象都是有访问控制的,而服务中创建的内核对象权限比较高,当LPSECURITY_ATTRIBUTES这个参数传NULL的时候,将使用默认访问控制。普通桌面应用程序自然没有权限访问了,解决方法如下,在服务程序创建事件对象时,指定确定的安全描述符。

  1.  // set SECURITY_DESCRIPTOR
  2.  SECURITY_DESCRIPTOR secutityDese;
  3.  ::InitializeSecurityDescriptor(&secutityDese, SECURITY_DESCRIPTOR_REVISION);
  4.  ::SetSecurityDescriptorDacl(&secutityDese,TRUE,NULL,FALSE);
  5.  SECURITY_ATTRIBUTES securityAttr;
  6.  // set SECURITY_ATTRIBUTES
  7.  securityAttr.nLength = sizeof SECURITY_ATTRIBUTES;
  8.  securityAttr.bInheritHandle = FALSE;
  9.  securityAttr.lpSecurityDescriptor = &secutityDese;
  10.  m_hEvent = ::CreateEvent(&securityAttr, FALSE, FALSE, TEXT("{67BDE5D7-C2FC-49f5-9096-C255AB791B75}"));

这样普通桌面应用程序再去打开该事件对象就没有问题了。(注:vista下事件对象的名字仍然要指定全局空间)

 

另外再谈谈Windows编程中的session,最近遇到一些很郁闷的问题。一直在折腾Vista下的服务程序启动进程的问题,有了点小小的体会,记下来,希望能帮到跟我遇到一样问题的朋友。Windows xp、Vista中,服务程序都是运行在session0中,而后面的第1、2、...、N个用户则分别运行在session1、session2、...、sessionN中。不同的session有不同的namespace,但是由于目前主流的用户windows平台WinXP支持快速用户切换,所以我们感觉不到这些差异。

在XP中,用Sevice启动的进程跟我们用当前用户启动的进程在编程上似乎没什么区别,用起来都一样。  可是到了vista下,情况就不一样了。vista新的安全机制对不同的session之间的限制做了加强。一些命名内核对象,如Event的使用,为了进行进程通信,在进程1(处在session1中)中,我创建了一个命名的事件对象,然后在进程2(由我的服务启动,所以运行在session0中)中检测该Event,发现始终检查不到,而且错误信息是“系统找不到指定的文件。”另外专门写了个小程序去检测(直接运行,也是运行在session1中),却能检测到。

后来仔细读了MSDN中关于“ Kernel Object Name Spaces”的资料,才明白:一些命名的内核对象,比如: events, semaphores, mutexes, waitable timers, file-mapping objects, job objects,都只是在自己的namespace里唯一存在,不同的session因为namespace不同,所以会导致上面的现象。详细的信息可以参考MSDN中的CreateEvent资料中对参数lpName的说明。

 

 以上内容摘录来自  http://blog.csdn.net/magictong/archive/2009/01/07/3726827.aspx

 

 

按照上面的方法应该可以解决通信问题,下面是我写的代码,可以实现通信 

HANDLE  hThread;
 unsigned dwThreadID;
 
 SECURITY_DESCRIPTOR secutityDese;
 ::InitializeSecurityDescriptor(&secutityDese, SECURITY_DESCRIPTOR_REVISION);
 ::SetSecurityDescriptorDacl(&secutityDese,TRUE,NULL,FALSE);
 SECURITY_ATTRIBUTES securityAttr;
 
 // set SECURITY_ATTRIBUTES
 securityAttr.nLength = sizeof SECURITY_ATTRIBUTES; 

 //参数为true 的时候,才可以和应用程序通信,false 则不行

 securityAttr.bInheritHandle = TRUE;              

 securityAttr.lpSecurityDescriptor = &secutityDese;
 
 g_hMutex = CreateMutex(&securityAttr,TRUE,TEXT("Global//CSAPP"));
 hThread = (HANDLE)_beginthreadex( NULL, 0, &Read, NULL, 0, &dwThreadID);

 while(m_bIsRunning)
 {    
   WaitForSingleObject(g_Semaphore,INFINITE); 
   ReleaseMutex(g_hMutex);  
 }
 CloseHandle(hThread);

 

 

客户端代码


    HANDLE hThread[2];
    unsigned dwThreadID;
    CString str;
    g_hMutex = OpenMutex(MUTEX_MODIFY_STATE|MUTEX_ALL_ACCESS,FALSE,TEXT("Global//CSAPP"));
    hThread[0] = (HANDLE)_beginthreadex( NULL, 0, &Read, NULL, 0, &dwThreadID);

 
    cout<<"打开成功"<<endl;
    WaitForSingleObject(g_hMutex,INFINITE);
    cout<<"运行正常"<<endl;
    ReleaseMutex(g_hMutex);


   ReleaseMutex(g_hMutex);  
   ReleaseSemaphore(g_hSemaphore,1,NULL);

 

 

 

 


   CloseHandle(hThread[0]);

   CloseHandle(g_hMutex);
   CloseHandle(g_hSemaphore);
   Sleep(60000);