如何避免不同用户的多个实例但在单个用户会话上允许多个实例

时间:2015-01-30 16:30:49

标签: .net c windows winapi windows-applications

我有一个Windows应用程序。我想为单个用户会话允许多个实例,但我不希望来自不同用户的多个实例。简单来说,如果A登录到Windows,那么他可以运行应用程序尽可能多的实例,但稍后,B登录,他应该等到A的所有应用程序都关闭。

这可能吗?

2 个答案:

答案 0 :(得分:1)

此要求可以使用全局Mutex Object中的命名Kernel Object Namespace来完成。使用CreateMutex function创建互斥对象。这是一个小程序来说明它的用法:

int _tmain(int argc, _TCHAR* argv[]) {
    if ( ::CreateMutexW( NULL,
                         FALSE,
                         L"Global\\5BDC0675-2318-404A-96CA-DBDE9BC2F71D" ) != NULL ) {
        auto const err{ GetLastError() };
        std::wcout << L"Mutex acquired. GLE = " << err << std::endl;
        // Continue execution
    } else {
        auto const err{ GetLastError() };
        std::wcout << L"Mutex not acquired. GLE = " << err << std::endl;
        // Exit application
    }
    _getch();
    return 0;
}

第一个应用程序实例将创建互斥对象,GetLastError将返回ERROR_SUCCESS(0)。后续实例将获取对现有互斥对象的引用,GetLastError将返回ERROR_ALREADY_EXISTS(183)。从另一个客户端会话启动的实例将不会获取对互斥锁对象的引用,并且GetLastError将返回ERROR_ACCESS_DENIED(5)。

关于实施的一些注释:

  • 通过添加“Global \”前缀,在全局内核对象命名空间中创建互斥对象。
  • 互斥对象必须具有唯一的名称才能从任何地方引用它。创建唯一名称的最简单方法是使用GUID的字符串表示形式(可以使用Visual Studio的guidgen.exe工具部分生成GUID)。 请勿使用示例代码中的GUID,因为其他人也会这样做。
  • 没有调用CloseHandle来释放互斥锁对象。这是故意的。 (参见CreateMutex系统在进程终止时自动关闭句柄。当最后一个句柄关闭时,互斥对象将被销毁。
  • 使用默认安全描述符创建互斥对象。默认安全描述符中的ACL来自创建者的主要或模拟令牌。如果不同客户端会话中的进程使用相同的主/模拟令牌运行,则仍可从两个会话中获取互斥锁。在这种情况下,提出的解决方案可能不符合要求。如果用户运行模拟不同客户会话的用户的应用程序,则不清楚会发生什么。
  • 互斥对象仅用作哨兵,不参与同步。

答案 1 :(得分:-1)

我在win10 / VS 2017/64位下使用了以前的代码

针对if(:: CreateMutex ..

我们必须检查错误,所以使用:

BOOL checkUniqueInstance()
{
    if (::CreateMutexW(NULL,
        FALSE,
        L"Global\\27828F4B-5FC9-40C3-9E81-6C485020538F") != NULL) {
        auto err = GetLastError();
        if (err == 0) {
            return TRUE;
        }
    }
    CString msg;
    msg.Format(_T("err: %d -  Mutex NOT acquired"), GetLastError());
    OutputDebugString(msg);
    // Exit application
    return FALSE;
}