【发布时间】:2016-05-30 15:06:24
【问题描述】:
我有一个使用 FOLDERID_RoamingAppData 调用 SHGetKnownFolderPath 的程序。
如果我通过双击启动程序,它可以正常工作。
如果程序由 Windows 服务启动(在当前用户上下文中),该函数将失败并出现错误 E_ACCESSDENIED (-2147024891)。
这是我的代码的样子:
Tstring EasyGetFolderPath(REFKNOWNFOLDERID folderid)
{
Tstring sPath = _T("");
PWSTR pszPath = NULL;
HRESULT hr = SHGetKnownFolderPath(folderid, 0, NULL, &pszPath);
if (hr == S_OK && pszPath)
{
sPath = WStringToTCHAR(pszPath);
CoTaskMemFree(pszPath);
return sPath;
}
else
{
throw HResultException(hr, _T("SHGetKnownFolderPath failed"));
}
}
Tstring EasyGetUsrAppDataPath()
{
return EasyGetFolderPath(FOLDERID_RoamingAppData);
}
static TCHAR* WStringToTCHAR(const std::wstring &s)
{
#ifdef UNICODE
TCHAR *sT = new TCHAR[s.length() + 1];
_tcscpy_s(sT, s.length() + 1, s.c_str());
return sT;
#else
std::string str = WStringToString(s);
TCHAR *sT = new TCHAR[str.length()+1];
_tcscpy_s(sT, str.length() + 1, str.c_str());
return sT;
#endif // UNICODE
}
static std::string WStringToString(const std::wstring& s, bool method = true)
{
std::string temp;
temp.assign(s.begin(), s.end());
return temp;
}
这是在当前用户上下文中启动进程的代码: (为了减少冗长,我删除了错误处理)
void StartProcessInCurrentUserContext(const Tstring &sExeName, const Tstringarr &lstParams, const Tstring &sWorkingDir)
{
...
EnableDebugPrivilege();
errCode = GetProcessByName(_T("explorer.exe"), hProcess);
if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
{
...
}
if (hProcess)
CloseHandle(hProcess);
Tstring sCmdLine = ...;
...
// Create the child process.
bSuccess = CreateProcessAsUser(hToken, NULL,
(LPTSTR)sCmdLine.c_str(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
sWorkingDir.length() > 0 ? (LPCTSTR)sWorkingDir.c_str() : NULL,
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
CloseHandle(hToken);
...
}
有人知道问题出在哪里吗?
【问题讨论】:
-
@conectionist 如果您使用
std::vector<TCHAR>而不是new TCHAR[],则可以避免内存泄漏。 -
您说您“作为当前用户”从服务启动可执行文件。您究竟是如何做到这一点的(最好显示相关的
CreateProcess(WithLogon)代码)。 IOW 可能启动的进程没有像您认为的那样运行(例如,没有LOGON_WITH_PROFILE- 我可以想象这是一个潜在的问题)。 -
"CreateProcessAsUser 不会将指定用户的配置文件加载到 HKEY_USERS 注册表项中。"您需要加载配置文件才能访问用户配置文件状态。
-
@conectionist -- 这一行是高度可疑的:
(LPTSTR)sCmdLine.c_str(),。如果你去掉(LPTSTR) 演员表,你会得到编译器错误吗?如果是这样,那么您的代码不正确。您不会通过投射将窄弦变成宽弦,反之亦然。这可以追溯到 Ulrich 提到的和TCHAR问题。 -
您应该使用
WTSQueryUserToken()而不是GetProcessByName()/OpenProcessToken()。并且lpEnvironment参数也要使用CreateEnvironmentBlock(),不要继承服务的环境。
标签: c++ winapi known-folders