跨越进程边界共享内核对象【命名对象】

跨越进程边界共享内核对象有三种方法:

  1. 对象句柄的继承性
  2. 命名对象
  3. 复制对象句柄

命名对象

共享跨越进程边界的内核对象的第二种方法是给对象命名,注意有些内核对象是不可以命名的,但多数内核对象可以命名。

下面的所有函数都可以创建命名的内核对象:

HANDLE CreateMutex(
   PSLCURITY_ATTRIBUTES psa,
   BOOL bInitialOwner,
   PCTSTR pszName);

HANDLE CreateEvent(
   PSECURITY_ATTRIBUTES psa,
   BOOL bManualReset,
   BOOL bInitialState,
   PCTSTR pszName);

HANDLE CreateSemaphore(
   PSECURITY_ATTRIBUTES psa,
   LONG lInitialCount,
   LONG lMaximumCount,
   PCTSTR pszName);

HANDLE CreateWaitableTimer(
   PSLCURITY_ATTRIBUTES psa,
   BOOL bManualReset,
   PCTSTR pszName);

HANDLE CreateFileMapping(
   HANDLE hFile,
   PSECURITY_ATTRIBUTES psa,
   DWORD flProtect,
   DWORD dwMaximumSizeHigh,
   DWORD dwMaximumSizeLow,
   PCTSTR pszName);

HANDLE CreateJobObject(
   PSECURITY_ATTRIBUTES psa,
   PCTSTR pszName);

使用命名对象要注意的问题

所有这些对象都共享单个名空间。因此下面的用法是错的。

HANDLE hMutex = CreateMutex(NULL. FALSE, "JeffObj");
HANDLE hSem = CreateSemaphore(NULL, 1, 1, "JeffObj");
DWORD dwErrorCode = GetLastError();

所以为了防止名字的冲突,建议创建一个GUID ,并将GUID的字符串表达式用作对象名。

如何用命名对象来共享对象

Process A 启动运行,并调用下面的函数:

HANDLE hMutexPronessA = CreateMutex(NULL, FALSE, "JeffMutex");

另一进程ProcessB(不一定是Process A 的子进程)启动运行时,执行下面的代码:

HANDLE hMutexProcessB = CreateMutex(NULL, FALSE, "JeffMutex");

当Process B调用CreateMutex时,系统首先要查看是否已经存在一个名字为“JeffMutex ”的内核对象。

由于确实存在一个带有该名字的对象,因此内核要检查对象的类型。由于试图创建一个互斥对象,而名字为“JeffMutex ”的对象也是个互斥对象,

因此系统会执行一次安全检查,以确定调用者是否拥有对该对象的完整的访问权。

如果拥有这种访问权,系统就在ProcessB的句柄表中找出一个空项目,并对该项目进行初始化,使该项目指向现有的内核对象。

如果该对象类型不匹配,或者调用者被拒绝访问,那么CreateMutex 将运行失败(返回NULL)。

当Process B 对CreateMutex的调用取得成功时,它并不实际创建一个互斥对象。相反,Process B 只是被赋予一个与进程相关的句柄值,用于标识内核中现有的互斥对象。当然,由于Process B 的句柄表中的一个新项目要引用该对象,互斥对象的使用计数就会递增。在Process A和Process
B 同时关闭它们的对象句柄之前,该对象是不会被撤消的。请注意,这两个进程中的句柄值很可能是不同的值。这是可以的。Process A 将使用它的句柄值,而Process B 则使用它自己的句柄值来操作一个互斥内核对象。

  注意当你的多个内核对象拥有相同的名字时,有一个非常重要的细节必须知道。当Process B 调用CreateMutex 时,它将安全属性信息和第二个参数传递给该函数。如果已经存在带有指定名字的对象,那么这些参数将被忽略。

确定它是否确实创建了一个新内核对象,而不是打开了一个现有的对象

HANDLE hMutex = CreateMutex(&sa, FALSE, "JeffObj");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
   //Opened a handle to an existing object.
   //sa.lpSecurityDescriptor and the second parameter
   //(FALSE) are ignored
}
else
{
   //Created a brand new object.
   //sa.lpSecurityDescriptor and the second parameter
   //(FALSE) are used to construct the object.
}

按名字共享对象的另一种方法

不调用Create*函数,而是调用Open*函数:

HANDLE OpenMutex(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);

HANDLE OpenEvent(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);

HANDLE OpenSemaphore(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName),

HANDLE OpenWaitableTimer(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);

HANDLE OpenFileMapping(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);

HANDLE Openjob0bject(
   DWORD dwDesiredAccess,
   BOOL bInheritHandle,
   PCTSTR pszName);

最后一个参数pszName用于指明内核对象的名字。不能为该参数传递NULL ,必须传递以0 结尾的地址。这些函数要搜索内核对象的单个名空间,以便找出匹配的空间。如果不存在带有指定名字的内核对象,该函数返回NULL 。

如果存在带有指定名字的内核对象,并且它是相同类型的对象,那么系统就要查看是否允许执行所需的访问(通过dwDesiredAccess参数进行访问)。如果拥有该访问权,调用进程的句柄表就被更新,对象的使用计数被递增。如果为bInheritHandle 参数传递TRUE,那么返回的句柄将是可继承的。

调用Create *函数与调用Open*函数之间的主要差别

如果对象并不存在,那么Create*函数将创建该对象,而Open*函数则运行失败。

一个小应用

命名对象常常用来防止运行一个应用程序的多个实例。若要做到这一点,只需要调用main或WinMain函数中Create*函数,以便创建一个命名对象(创建的是什么对象则是无所谓的)。当Create*函数返回时,调用GetLastError函数。如果GetLastError 函数返回ERROR_ALREADY_EXISTS ,那么你的应用程序的另一个实例正在运行,新实例可以退出。下面是说明这种情况的部分代码:

intWINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PSTR pszCmdLine, int nCmdShow)
{
   HANDLE h = CreateMutex(NULL, FALSE, "{FA531CC1-0497-11d3-A180-00105A276C3E}");
   lf (GetLastError() == ERROR_ALREADY_EXISTS)
   {
      //There is already an instance
      //of the application running
      return(0);
   }

   //This is the first instance of thisapplication running.
   //Before exiting ,close the object.
   CloseHandle(h);
   return(0);
}

终端服务器的名字空间

终端服务器能够稍稍改变上面所说的情况。终端服务器拥有内核对象的多个名字空间。

以上转载于http://www.cnblogs.com/fangyukuan/archive/2010/08/31/1813733.html

自己测试的代码

建立2个console程序

First Process

#include<windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>

#define GRS_USEPRINTF() TCHAR pBuf[1024] = {}
#define GRS_PRINTF(...) 	StringCchPrintf(pBuf,1024,__VA_ARGS__);	WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),pBuf,lstrlen(pBuf),NULL,NULL);

int main()
{
	GRS_USEPRINTF();
	/*HANDLE hMutex = CreateMutex(NULL,FALSE, _T("JeffObj"));
	HANDLE hSem = CreateSemaphore(NULL, 1, 1, _T("JeffObj"));
	GRS_PRINTF(_T("管道创建失败,Error Code:0x%08x\n"), GetLastError());*/
	HANDLE hMutex = CreateMutex(NULL, FALSE, _T("MyMutex"));
//	CloseHandle(hMutex);
	GRS_PRINTF(_T("Error Code:0x%08x\n"), GetLastError());
	HANDLE hMutex1 = CreateSemaphore(NULL, 1,1, _T("MyMutex"));
	GRS_PRINTF(_T("Error Code:0x%08x\n"), GetLastError());
	_tsystem(_T("PAUSE"));
}
<h4>Second Process</h4>
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

#define GRS_USEPRINTF() TCHAR pBuf[1024] = {}
#define GRS_PRINTF(...) 	StringCchPrintf(pBuf,1024,__VA_ARGS__);	WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),pBuf,lstrlen(pBuf),NULL,NULL);

int main()
{
	GRS_USEPRINTF();
	HANDLE h = CreateMutex(NULL, FALSE, _T("MyMutex"));
	if(GetLastError() == ERROR_ALREADY_EXISTS)
	{
		//There is already an instance
		//of the application running
		_tprintf_s(_T("There is already an instanceof the application running"));
		CloseHandle(h);
		return(0);
	}

	//This is the first instance of thisapplication running.
	//Before exiting ,close the object.
	CloseHandle(h);
	return(0);
}

Second Process

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>

int main()
{
	HANDLE hMutex;
	hMutex = OpenMutex(
		MUTEX_ALL_ACCESS,
		FALSE,
		_T("MyMutex"));
	if (hMutex == NULL)
		printf("OpenMutex error: %d\n", GetLastError());
	else printf("OpenMutex successfully opened the mutex.\n");

}

使用Open* Create* 参考MSDN 的dome

作者:locojyw

email:[email protected]

欢迎大家交流,有什么错误请指出

转载注明出处

时间: 2024-10-18 00:30:16

跨越进程边界共享内核对象【命名对象】的相关文章

跨进程边界共享内核对象

正在拜读<windows核心编程>,稍后总结.---------XiaoF 先说说为何要实现此功能   1,利用文件映射对象,可以在同一电脑的不同进程之间共享数据块.   2,借助邮件槽和命名管道,在网络中的不同计算机上运行的进程相互发送消息.   3,互斥量.信号量.事件,允许不同进程中的线程做同步.如何实现,方法3种:使用对象句柄继承(父子进程):为对象命名:复制对象句柄.使用对象句柄继承    只有在父子进程关系,才可以用对象句柄继承方法.    步骤如下:    1,当父进程创建一个内

.NET 中使用 Mutex 进行跨越进程边界的同步

原文:.NET 中使用 Mutex 进行跨越进程边界的同步 Mutex 是 Mutual Exclusion 的缩写,是互斥锁,用于防止两个线程同时对计算机上的同一个资源进行访问.不过相比于其他互斥的方式,Mutex 能够跨越线程边界. 本文内容 Mutex 是什么? 简单的 Mutex(不能跨进程互斥) 创建跨进程互斥的 Mutex 处理异常情况 ApplicationException AbandonedMutexException 参考资料 Mutex 是什么? 与其他线程同步的方式一样,

跨越DLL边界传递CRT对象潜在的错误

翻译:magictong(童磊)2013年5月 版权:microsoft 原文地址:http://msdn.microsoft.com/en-us/library/ms235460(v=vs.80).aspx 简介 当你把C运行时(CRT)对象(譬如文件句柄.语言环境和环境变量等等)传入传出DLL时(通过调用DLL里面暴露的一些函数),如果这个DLL加载了一份(与可执行文件)不同的CRT库,可能发现意向不到的事情. 有一个大家可能遇到过,相似的问题是,如果可执行程序在外面分配一块内存(显示的通过

多个进程获取同一个内核对象,他们的句柄是一样的

// temp10.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <Windows.h> #include <string> #include <iostream> #include <time.h> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { HANDLE handle=::CreateEventA(n

《CLR via C#》 第22章 CLR寄宿和AppDomain 跨越AppDomain边界访问对象

跨越AppDomain边界访问对象 将书中的代码(3处)将“MarshalByRefType”修改为“typeof(MarshalByRefType).FullName”,即可得到书中的输出结果: 将:MarshalByRefType mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly,“MarshalByRefType”); 修改为:MarshalByRefType mbrt = (MarshalByRefType)

进程间同步---system v ipc 对象信号灯集

一.信号灯简介 Linux支持System V的信号灯(semaphore),是一种进程间通信的方式,只不过它和管道.FIFO或者共享内存不一样,信号灯主要用于同步或者互斥对共享资源的访问,它的发明来源于火车运行系统中的"信号灯",利用信号灯可以实现"PV"操作这种进程间同步进制.P操作时获得资源,将信号灯的值减1,如果结果不为负则执行完毕,进程获得资源,否则进程睡眠以等待的进程释放;V操作则是释放资源,给信号灯的值加1, 唤醒一个因执行P操作而等待的进程. 二.信

数据库对象命名参考

引言 编码规范是一个优秀程序员的必备素质,然而,有很多人非常注重程序中变量.方法.类的命名,却忽视了同样重要的数据库对象命名.这篇文章结合许多技术文章和资料,以及我自己的开发经验,对数据库对象的命名规则提出了一点建议,希望能为大家提供一些参考. NOTE:虽然这篇文章名为"数据库对象命名参考",实际上,在这篇文章中不仅介绍了数据库命名的规则,还讲述了在数据库设计与开发时所需要注意的几个问题. 基本命名规则 表1. 基本数据库对象命名 数据库对象 前缀 举例 表(Table)字段(Col

进程-IPC 共享内存和消息队列 (三)

详见:https://github.com/ZhangzheBJUT/linux/blob/master/IPC(%E4%B8%89).md 五 共享内存 5.1. 共享内存简介 共享内存指多个进程共享同一块物理内存,它只能用于同一台机器上的两个进程之间的通信.在进程的逻辑地址空间中有一段地址范围是用来进行内存映射使用的,该段逻辑地址空间可以映射到共享的物理内存地址上(进程空间介绍:http://blog.csdn.net/zhangzhebjut/article/details/3906025

clients(PV操作共享内核内存进行输入输出分屏) - server(进程间通信)模型实现

1.拓扑结构 2.PV操作共享内核内存进行输入输出分屏 (1) 1 int semop(int semid,struct sembuf *sops,size_t nsops): 功能描述 操作一个或一组信号. semid: 信号集的识别码,可通过semget获取. sops: 指向存储信号操作结构的数组指针,信号操作结构的原型如下 1 struct sembuf 2 { 3 unsigned short sem_num; /* semaphore number */ 4 short sem_op