我在系统级Windows服务中运行以下代码。如果我将CreateEnvironmentBlock()和CreateProcessAsUser()添加到代码中,则可以正常工作。但是我使用“ LoadUserProfile()”,它失败,并出现错误5,该错误应表示“访问被拒绝”。请帮助检查缺少的内容。我想要的是从此系统服务中检索用户级别的注册表值。代码中的注释是另一种方式,但是也无法检索用户级注册表值。
void GetUserRegistry()
{
#ifdef Q_OS_WIN
DWORD lastError = 0;
DWORD sessionId = WTSGetActiveConsoleSessionId();
qInfo() << "Session ID = " << sessionId;
wchar_t* ppUserName[100];
DWORD sizeOfUserName;
WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, ppUserName, &sizeOfUserName);
qInfo() << "Windows User Name = " << QString::fromWCharArray(*ppUserName);
std::wstring strValueOfBinDir = L"Unknown Value";
// LONG regOpenResult = ERROR_SUCCESS;
HANDLE hUserToken = NULL;
HANDLE hFakeToken = NULL;
if (WTSQueryUserToken(sessionId, &hUserToken))
{
if (DuplicateTokenEx(hUserToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hFakeToken) == TRUE)
{
qInfo() << "Before ImpersonateLoggedOnUser()......";
if (ImpersonateLoggedOnUser(hFakeToken))
{
HKEY hKey;
// regOpenResult = RegOpenCurrentUser(KEY_READ, &hKey);
PROFILEINFO profileInfo;
ZeroMemory( &profileInfo, sizeof( PROFILEINFO ) );
profileInfo.dwSize = sizeof( PROFILEINFO );
profileInfo.lpUserName = *ppUserName;
// wchar_t roamingPath[] = L"C:\\Users\\Finix"; // L"C:\\Users\\Finix\\AppData\\Roaming";
// profileInfo.lpProfilePath = roamingPath;
if (LoadUserProfile(hFakeToken, &profileInfo))
{
HANDLE hProfile = profileInfo.hProfile;
RegOpenKeyEx(HKEY_CURRENT_USER,
TEXT("Software\\Baidu\\BaiduYunGuanjia"),
0,
KEY_READ,
&hKey);
GetStringRegKey(hKey, TEXT("installDir"), strValueOfBinDir, TEXT("Unknown"));
UnloadUserProfile(hFakeToken, hProfile);
}
else
{
lastError = GetLastError();
}
RevertToSelf();
}
else
{
qCritical() << "Failed to ImpersonateLoggedOnUser...";
}
CloseHandle(hFakeToken);
}
else
{
qCritical() << "Failed to call DuplicateTokenEx...";
}
CloseHandle(hUserToken);
}
else
{
qCritical() << "Failed to get the user token of session " << sessionId;
}
if (lastError)
{
qCritical() << "Failed to LoadUserProfile(), The ERROR is " << lastError;
}
// if (regOpenResult != ERROR_SUCCESS)
// {
// qCritical() << "Failed to call RegOpenCurrentUser(), Error is " << regOpenResult;
// }
qInfo() << "The value of Registry is " << QString::fromWCharArray( strValueOfBinDir.c_str() );
#endif
}
最佳答案
您无法呼叫LoadUserProfile
的原因是您正在冒充用户。 LoadUserProfile
需要管理员权限,即您应该在自己的上下文中而不是在模拟的上下文中调用它。用户无法加载自己的配置文件,通常系统会代表用户调用它。
您不应调用LoadUserProfile
的原因是该用户已经登录,因此该配置文件已被加载。我们知道有问题的用户已登录,因为WTSQueryUserToken
不能用于为未登录的用户获取令牌。
(好吧,在某些情况下,用户当前正在登录或注销。但是在登录/注销过程中调用LoadUserProfile
函数在任何情况下都是不明智的。)
如果只想打开已登录用户的注册表配置单元,请使用RegOpenCurrentUser
。 (请注意,正如您所记录的,您确实希望对此功能使用模拟功能。)