要实现单一实例有三种 一种是对象句柄继承 一种是专有命名 另外一种是复制对象句柄今天来看看专有命名空间
void CheckInstances() { // 创建边界描述符 g_hBoundary = CreateBoundaryDescriptor(g_szBoundary,0); //g_szboundary是一个自定义字符串 // 创建一个对应于本地管理员组的安全描述符SID BYTE localAdminSID[SECURITY_MAX_SID_SIZE]; PSID pLocalAdminSID = &localAdminSID; DWORD cbSID = sizeof(localAdminSID); /* The CreateWellKnownSid function creates a SID for predefined aliases. BOOL WINAPI CreateWellKnownSid( __in WELL_KNOWN_SID_TYPE WellKnownSidType,__in_opt PSID DomainSid,__out_opt PSID pSid,__inout DWORD* cbSid ); Parameters WellKnownSidType Member of the WELL_KNOWN_SID_TYPE enumeration that specifies what the SID will identify. DomainSid A pointer to a SID that identifies the domain control to use when creating the SID. Pass NULL to use the local computer. pSid A pointer to memory where CreateWellKnownSid will store the new SID. cbSid A pointer to a DWORD that contains the number of bytes available at pSid. The CreateWellKnownSid function stores the number of bytes actually used at this location. */ if (!CreateWellKnownSid(WinBuiltinAdministratoRSSid,NULL,pLocalAdminSID,&cbSID)) //第二个参数<span style="color: rgb(51,51,51); font-family: arial,宋体,sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">指向创建了SID的域的</span><a target=_blank target="_blank" href="http://baike.baidu.com/view/159417.htm" style="text-decoration: none; color: rgb(19,110,194); font-family: arial,sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">指针</a><span style="color: rgb(51,sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">,为NULL时表示使用本地计算机 这个函数创建一个sid返回给pLocalAdminSID </span> { AddText(TEXT("添加安全描述符到边界描述符失败: %u\r\n"),GetLastError()); return; } // 将本地管理员组的安全描述符与边界描述符关联起来 // 只有管理员身份运行的应用程序能获得该命名空间下的内核对象 if (!AddSIDToBoundaryDescriptor(&g_hBoundary,pLocalAdminSID)) //把创建的sid添加到边界描述符 他其实就是制定了私有命名空间 { AddText(TEXT("添加安全描述符到边界描述符失败: %u\r\n"),GetLastError()); return; } // 为本地管理员创建命名空间 SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.bInheritHandle = FALSE; if (!ConvertStringSecurityDescriptorToSecurityDescriptor(TEXT("D:(A;;GA;;;BA)"),// 创建安全描述符 SDDL_REVISION_1,&sa.lpSecurityDescriptor,NULL)) { AddText(TEXT("安全描述符创建失败: %u\r\n"),GetLastError()); return; } g_hNamespace = CreatePrivateNamespace(&sa,g_hBoundary,g_szNamespace); //更具边界描述符中的sid这个键值找到那个对应的安全描述符 完后给他的内核对象添加了一个命名空间 类似于create内核对象的时候 第二个参数就是命名 LocalFree(sa.lpSecurityDescriptor); //记住释放 // 检查私有命名空间创建是否成功 DWORD dwLastError = GetLastError(); // 创建失败 if (g_hNamespace == NULL) { // 如果被拒绝访问,则直接返回 // 这段代码必须在本地管理员账户运行 if (dwLastError == ERROR_ACCESS_DENIED) { AddText(TEXT("创建命名空间时访问被拒绝.\r\n")); AddText(TEXT(" 必须以管理员身份运行。\r\n\r\n")); return; } else { // 如果在该命名空间另一个实例已经被创建 if (dwLastError == ERROR_ALREADY_EXISTS) { AddText(TEXT("创建私有命名空间失败: %u\r\n"),dwLastError); g_hNamespace = OpenPrivateNamespace(g_hBoundary,g_szNamespace); if (g_hNamespace == NULL) { AddText(TEXT(" 并且打开私有命名空间失败: %u\r\n"),dwLastError); return; } else { g_bNamespaceOpened = TRUE; AddText(TEXT(" 但是打开私有命名空间成功\r\n\r\n")); } } else { AddText(TEXT("发生了未知的错误: %u\r\n\r\n"),dwLastError); return; } } } // 尝试创建命名互斥量对象 TCHAR szMutexName[64]; StringCchPrintf(szMutexName,_countof(szMutexName),TEXT("%s\\%s"),//命名空间类似于文件路径 单一实例就是程序名字 父路径就是专有命名空间 只要在他底下运行 就不会被别的进程 先创建一个同名的内核对象而劫持 g_szNamespace,TEXT("单一实例")); g_hSingleton = CreateMutex(NULL,FALSE,szMutexName); if (GetLastError() == ERROR_ALREADY_EXISTS) { AddText(TEXT("单一实例应用程序另一个实例已经运行:\r\n")); AddText(TEXT("--> 不能访问应用程序功能.\r\n")); } else { AddText(TEXT("单一实例应用程序的第一个实例\r\n")); AddText(TEXT("--> 现在访问应用程序功能\r\n")); } }