zoukankan      html  css  js  c++  java
  • windows笔记跨越进程边界共享内核对象【命名对象】

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

    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

  • 相关阅读:
    sqlsever中生成GUID的方法
    部署项目到服务器
    读后感
    第二次作业
    课堂作业
    第一次作业 开发环境配置介绍
    第二次结对作业
    代码审查
    最大连续子数组和
    单元测试
  • 原文地址:https://www.cnblogs.com/fangyukuan/p/1813733.html
Copyright © 2011-2022 走看看