在ImpersonateLoggedOnUser()之后,为什么无法调用Windows API SetDisplayConfig()?

时间:2016-08-03 12:59:50

标签: c++ windows winapi

这是一项系统服务。 ImpersonateLoggedOnUser()之后,我可以成功拨打CreateProcessAsUser()。但它无法调用一个Windows API SetDisplayConfig()。错误是5(ERROR_ACCESS_DENIED)。请参阅下面的代码。

// This function is called in a System service.  
void SetDisplayToExtendMode()
{
    DWORD dwSessionId = WTSGetActiveConsoleSessionId();
    if (dwSessionId == 0xFFFFFFFF)
    {
        qCritical() << "Failed to get active console session Id when setting extend mode for display!";
    }

    HANDLE hUserToken = NULL;
    if (WTSQueryUserToken(dwSessionId, &hUserToken) == FALSE)
    {
        qCritical() << "Failed to query user token when setting extend mode for display!";
    }

    HANDLE hTheToken = NULL;
    if (DuplicateTokenEx(hUserToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hTheToken) == TRUE)
    {

        if (ImpersonateLoggedOnUser(hTheToken) == TRUE)
        {
            DWORD dwCreationFlags = HIGH_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

            LPVOID pEnv = NULL;
            if (CreateEnvironmentBlock(&pEnv, hTheToken, TRUE) == TRUE)
            {
                dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
            }

            // Way 1: Call Windows API directly. 
            // Fail. Error code is ERROR_ACCESS_DENIED
            LONG errCode = SetDisplayConfig(0, NULL, 0, NULL, SDC_TOPOLOGY_EXTEND | SDC_APPLY);
            if (errCode != ERROR_SUCCESS)
            {
                qCritical() << "Failed to set Windows Display to Extended mode! Error is " << errCode;
                if (errCode == ERROR_ACCESS_DENIED)
                {
                    qCritical() << "ACCESS denied!";
                }
            }

            STARTUPINFO si = { sizeof(si) };
            PROCESS_INFORMATION pi;
            SECURITY_ATTRIBUTES Security1 = { sizeof(Security1) };
            SECURITY_ATTRIBUTES Security2 = { sizeof(Security2) };


            std::wstring command = L"C:\\Users\\SomeUser\\Desktop\\QT_Projects\\build\\release\\TestSetDisplay.exe";
            TCHAR commandLine[MAX_PATH];
            _tcscpy_s(commandLine, MAX_PATH, command.c_str());

            // Way 2: This way can be successful. 
            BOOL bResult = CreateProcessAsUser(
                hTheToken,
                NULL,   // (LPWSTR)(path),
                (LPWSTR)(commandLine),
                &Security1,
                &Security2,
                FALSE,
                dwCreationFlags,
                pEnv,
                NULL,
                &si,
                &pi
                );

            if (!bResult)
            {
                qCritical() << "Failed to CreateProcessAsUser()";
            }

            RevertToSelf();

            if (pEnv)
            {
                DestroyEnvironmentBlock(pEnv);
            }
        }
        CloseHandle(hTheToken);
    }
    CloseHandle(hUserToken);
}

那么,在ImpersonateLoggedOnUser()之后,如何成功调用Windows API SetDisplayConfig()? 或者,在一个系统服务中,如何以用户身份调用一个Windows API? (对于这种情况,调用SetDisplayConfig()的目的是将显示模式设置为扩展模式。此显示模式是按用户设置的。因此,作为系统服务,它可能需要先impersonateLoggedOnUser()。 )

1 个答案:

答案 0 :(得分:1)

来自SetDisplayConfig文档

  

ERROR_ACCESS_DENIED调用者无权访问控制台   会话。如果调用进程没有访问权限,则会发生此错误   到当前桌面或正在远程会话上运行。

你写了

  

这是一项系统服务。

但系统服务无法访问交互式桌面。所以你需要从交互式会话中调用它