您的位置:首页 > 其它

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

2012-12-05 11:47 399 查看
转自:http://www.cppblog.com/lapcca/archive/2010/09/06/126024.html

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

1、普通桌面应用程序中创建事件,服务程序中打开事件

XP的情况

普通桌面应用程序中创建:

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

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

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

vista下情况

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

2、服务程序中创建事件,普通桌面应用程序中打开事件

下面就不分系统说明,只说说根本的问题。

服务程序中创建:

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

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

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

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

// set SECURITY_DESCRIPTOR
SECURITY_DESCRIPTOR secutityDese;
::InitializeSecurityDescriptor(&secutityDese, SECURITY_DESCRIPTOR_REVISION);
::SetSecurityDescriptorDacl(&secutityDese,TRUE,NULL,FALSE);

SECURITY_ATTRIBUTES securityAttr;

// set SECURITY_ATTRIBUTES
securityAttr.nLength = sizeof SECURITY_ATTRIBUTES;
securityAttr.bInheritHandle = FALSE;
securityAttr.lpSecurityDescriptor = &secutityDese;

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的说明。

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

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐