CreateEvent 和OpenEvent时事件全局名称问题 Global

今天看别人的代码,注意到在操作事件对象时如下:
sprintf(cTemp,"Global\\EVENT_%s",lpFileName);
m_hMapEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,cTemp);


注意到了没有,事件对象名称前面加了个Global,开始以为这个Global是任意加的,可以随便改成其他字符,后来经过查阅msdn和google,才发现这个Global大有来头!


Global\\xxxEvent 可以保证:在创建命名时间对象时指定名字是全局的。
这样做的好处如下:
这样创建的内核对象无论出于服务,还是内核中,应用层都可以打开并使用这个内核对象。
CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" ); 这是一个内核对象。
==========
关于在通过 事件对象 在服务程序和普通桌面应用程序相互之间通信的问题,分类情况进行讨论:
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的说明。
大家可以参考MSDN中的“ Kernel Object Name Spaces”(没事贴点MSDN中的东东,MSDN才是王道啊):

Kernel Object Name Spaces


A Remote Desktop Services server has multiple namespaces for the following named kernel objects: events, semaphores, mutexes, waitable timers, file-mapping objects, and job objects. There is a global namespace used primarily by services in client/server applications. In addition, each client session has a separate namespace for these objects, such as in Windows Vista.


The separate client session namespaces enable multiple clients to run the same applications without interfering with each other. For processes started under a client session, the system uses the session namespace by default. However, these processes can use the global namespace by prepending the "Global\" prefix to the object name. For example, the following code calls CreateEvent and creates an event object named CSAPP in the global namespace: 


CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" );


Service applications in a Remote Desktop Services environment use the global namespace by default. 


Session zero is only used for hosting services, and there is no console session, unlike previous versions of Windows.


The global namespace enables processes on multiple client sessions to communicate with a service application. For example, a client/server application might use a mutex object for synchronization. The server component can create the mutex object in the global namespace. Then a client session can use the "Global\" prefix to open the mutex object.


Another use of the global namespace is for applications that use named objects to detect that there is already an instance of the application running in the system across all sessions. This named object must be created or opened in the global namespace instead of the per-session namespace. The more common case of running the application once per session is supported by default because the named object is created in a per session namespace.


In addition to the "Global\" prefix, client processes can use the "Local\" prefix to explicitly create an object in their session namespace. These keywords are case sensitive.


The "Session\" prefix is reserved for system use and you should not use it in names of kernel objects. 


Fast user switching is implemented by using Remote Desktop Services sessions. The first user to log on uses session one, the next user to log on uses session two, and so on. Kernel object names must follow the guidelines outlined for Remote Desktop Services so that applications can support multiple users.


The creation of a file-mapping object in the global namespace, by using CreateFileMapping, from a session other than session zero is a privileged operation. Because of this, an application running in an arbitrary Remote Desktop Session Host (RD Session Host) server session must have SeCreateGlobalPrivilege enabled in order to create a file-mapping object in the global namespace successfully. The privilege check is limited to the creation of file-mapping objects, and does not apply to opening existing ones. For example, if a service or the system creates a file-mapping object, any process running in any session can access that file-mapping object provided that the user has the necessary access. 

【转载】http://hi.baidu.com/mikenoodle/item/06b069869bec6ccdee083d71

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: createevent、setevent和waitforsingleobject是操作系统中用来实现线程同步和通信的函数/方法。 createevent函数用于创建一个事件对象。一个事件对象可以是自动重置的或者手动重置的。自动重置的事件对象一旦被signal(即触发)后,会自动将其状态重新设置为非信号状态;而手动重置的事件对象需要手动将其状态重置为非信号状态。createevent函数会返回一个事件对象的句柄。 setevent函数用于将一个事件对象设置为信号状态。当某个线程调用setevent函数后,事件对象的状态将变为信号状态。如果多个线程在等待该事件对象,则所有等待的线程将被唤醒。 waitforsingleobject函数用于等待一个对象的信号状态。如果对象的状态是非信号状态,则调用线程进入等待状态,直到该对象状态变为信号状态。在等待期间,线程可能会被操作系统挂起,以减少系统资源的占用。 这三个函数/方法的组合可以用来实现线程之间的同步和通信。例如,在多个线程中,可以使用createevent创建一个事件对象,并且设置为非信号状态。然后,某个线程可以调用setevent函数将该事件对象设置为信号状态。其他线程可以调用waitforsingleobject函数等待该事件对象的信号状态。当该事件对象的状态变为信号状态,被等待的线程将被唤醒,从而实现线程间的同步和通信。 总而言之,createevent、setevent和waitforsingleobject是操作系统中用来实现线程同步和通信的函数/方法,可以帮助开发人员实现多线程程序中的同步和通信需求。 ### 回答2: createevent、setevent和waitforsingleobject是Windows操作系统中的三个同步机制函数。 createevent函数用于创建一个事件对象。一个事件对象是一个用来通知其他线程或者进程某个事件已经发生的同步对象。该函数返回一个事件对象的句柄,可以用来引用这个事件对象。 setevent函数用于将一个事件对象设置为信号状态。这意味着事件对象的状态被置位,其他等待该事件对象的线程将会被唤醒。setevent函数将事件对象的信号状态从非信号状态切换到信号状态。 waitforsingleobject函数用于等待一个对象的信号状态。当一个线程调用此函数,它会进入等待状态,直到被等待的对象发出信号。对于一个事件对象来说,如果它的信号状态为非信号状态,waitforsingleobject函数将使线程进入等待状态;而如果它的信号状态为信号状态,则线程将跳过等待,并继续执行后续的代码。 通过这三个函数的配合使用,我们可以实现线程间的同步。例如,一个线程可以通过createevent函数创建一个事件对象,并将其传递给其他线程。其他线程可以通过waitforsingleobject函数等待该事件对象的信号状态。当需要,一个线程可以通过setevent函数将该事件对象的信号状态置位,从而唤醒等待该事件对象的线程。 总结而言,createevent函数用于创建一个事件对象,setevent函数用于将事件对象设置为信号状态,waitforsingleobject函数用于等待一个对象的信号状态。这三个函数的结合使用可以实现线程间的同步机制,以便有效地管理多个线程的执行顺序和资源访问。 ### 回答3: createevent、setevent和waitforsingleobject都是操作系统中与进程间通信和同步机制相关的函数。 createevent函数用于创建一个事件对象。事件对象有两种状态,分别是有信号和无信号。通过createevent函数创建的事件对象默认是无信号状态。可以根据需要通过设置参数来创建手动重置或自动重置的事件对象。 setevent函数用于设置事件对象的状态为有信号。当事件对象被设置为有信号状态,其他进程可以通过waitforsingleobject函数等待该事件的发生。 waitforsingleobject函数用于等待一个可等待对象的发生。在这里,我们可以将事件对象作为可等待对象来使用。当事件对象被设置为有信号状态,调用waitforsingleobject函数的进程将会被唤醒并继续执行后续代码。如果事件对象处于无信号状态,调用waitforsingleobject函数的进程将会被挂起,直到事件对象状态变为有信号。 这些函数通常用于进程间的同步和通信。例如,一个进程可以创建一个事件对象,并将其设置为无信号状态。另一个进程可以通过waitforsingleobject函数等待该事件的发生。当第一个进程完成某个任务后,可以通过setevent函数将该事件设置为有信号状态,以通知第二个进程可以继续执行。 这些函数在多线程环境中也非常有用。通过使用事件对象和这些函数,可以实现线程之间的同步和协调,控制线程的执行顺序和相互通知。 总之,createevent、setevent和waitforsingleobject是操作系统中用于进程间通信和同步的重要函数,可以提供有效的线程和进程管理机制,确保程序正确、有序地执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值