跨越进程边界共享内核对象【命名对象】
来源:互联网 发布:惠天听书传销 知乎 编辑:程序博客网 时间:2024/05/17 16:16
跨越进程边界共享内核对象有三种方法:
- 对象句柄的继承性
- 命名对象
- 复制对象句柄
命名对象
共享跨越进程边界的内核对象的第二种方法是给对象命名,注意有些内核对象是不可以命名的,但多数内核对象可以命名。
下面的所有函数都可以创建命名的内核对象:
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();
如何用命名对象来共享对象
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);
如果存在带有指定名字的内核对象,并且它是相同类型的对象,那么系统就要查看是否允许执行所需的访问(通过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);}
终端服务器的名字空间
终端服务器能够稍稍改变上面所说的情况。终端服务器拥有内核对象的多个名字空间。自己测试的代码
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:locojyw@outlook.com
欢迎大家交流,有什么错误请指出
转载注明出处
- windows笔记-跨越进程边界共享内核对象【命名对象】
- -跨越进程边界共享内核对象【命名对象】
- 跨越进程边界共享内核对象【命名对象】
- 3.3 跨越进程边界共享内核对象
- 3.3 跨越进程边界共享内核对象
- 3.3 跨越进程边界共享内核对象
- 跨越进程边界共享内核对象
- 内核对象(2)之跨越边界进程共享内核对象
- -跨越进程边界共享内核对象【复制对象句柄】
- 跨越进程边界共享内核对象【复制对象句柄】
- 共享跨越进程边界内核对象的方法?
- windows笔记-跨越进程边界共享内核对象【对象句柄的继承性】
- windows笔记-跨越进程边界共享内核对象【复制对象句柄】
- -跨越进程边界共享内核对象【对象句柄的继承性】
- windows笔记-跨越进程边界共享内核对象【对象句柄的继承性】
- windows笔记-跨越进程边界共享内核对象【复制对象句柄】
- windows笔记-跨越进程边界共享内核对象【对象句柄的继承性】
- windows笔记-跨越进程边界共享内核对象【复制对象句柄】
- Android Studio 学习之路
- ubuntu安装anaconda
- 系统架构与任务功能的分解
- CC_SYNTHESIZE_RETAIN和CC_SAFE_RELEASE_NULL
- 开心的往事
- 跨越进程边界共享内核对象【命名对象】
- Python中的函数(一)
- Wordpress 刷新缓存
- 利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)
- Tigase客户端Jaxmpp使用之发布订阅(三)
- linux shell 技巧篇
- C# 与sybase 数据库的连接
- 进度条的界面设计
- 异步操作AsyncTask(二)从网络下载图片(带下载进度数据)