这是一项系统服务。 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()
。 )
答案 0 :(得分:1)
来自SetDisplayConfig文档
ERROR_ACCESS_DENIED调用者无权访问控制台 会话。如果调用进程没有访问权限,则会发生此错误 到当前桌面或正在远程会话上运行。
你写了
这是一项系统服务。
但系统服务无法访问交互式桌面。所以你需要从交互式会话中调用它