【发布时间】:2015-10-25 14:07:00
【问题描述】:
我正在编写 32 位服务应用程序,希望能够为 登录的用户 启动开始菜单项。我确实设法通过模拟用户并使用 CreateProcessAsUser 和命令行启动选定的 .lnk 文件来完成此任务:%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "。它几乎适用于所有快捷方式,除了 Accessories 文件夹中的一堆系统快捷方式(例如 Sticky Notes.lnk、Snipping Tool.lnk)。在启动截图工具期间,我从 cmd 收到带有此错误的消息框:
Windows 找不到“C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Snipping Tool.lnk”。请确保您输入的名称正确,然后重试。
但是 .lnk 文件就存在于这个目录中!
总结:
- 服务是 32 位的
- Windows 8 Pro x64
- 通过用户模拟和 CreateProcessAsUser 使用命令行启动快捷方式
%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" " - 该方法几乎适用于“开始”菜单中的所有快捷方式,但“开始/附件”文件夹中的一些快捷方式除外(并非所有快捷方式,例如 Paint.lnk 可以正常打开)
-
示例代码:
int launchAppForCurrentLoggedUser() { HANDLE userToken = WTSApiHelper::currentLoggedUserToken(); if (userToken == INVALID_HANDLE_VALUE) { return -1; } //Duplicating token with access TOKEN_DUPLICATE | TOKEN_ALL_ACCESS, //impersonation level SecurityImpersonation and token type TokenPrimary. //Also closing original userToken HANDLE dup = WTSApiHelper::duplicateToken(userToken); if (dup == INVALID_HANDLE_VALUE) { return -1; } int res = -1; uint8 *env = NULL; BOOL succeeded = CreateEnvironmentBlock((LPVOID *)&env, dup, FALSE); if (!succeeded) { Log("failed to get environment variables for user (error 0x%x).", GetLastError()); } PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); STARTUPINFOW si; memset(&si, 0, sizeof(STARTUPINFOW)); si.cb = sizeof(STARTUPINFOW); si.lpDesktop = L"winsta0\\Default"; WCHAR params[] = L"/c \" start /b /i \"\" \"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Accessories\\Snipping Tool.lnk\" \" "; WCHAR cmd[] = L"C:\\Windows\\system32\\cmd.exe"; DWORD flags = env ? CREATE_UNICODE_ENVIRONMENT : 0; succeeded = CreateProcessAsUserW(dup, cmd, params, NULL, NULL, FALSE, flags | CREATE_NO_WINDOW, env, NULL, &si, &pi); if (!succeeded) { Log("cannot launch process for user with error 0x%x.", GetLastError()); } else { nres = 0; } DestroyEnvironmentBlock(env); CloseHandle(dup); return nres; }
我错过了什么?
【问题讨论】:
-
CreateProcessAsUser: "lpCommandLine: 这个函数的Unicode版本,CreateProcessAsUserW,可以修改这个字符串的内容,所以这个参数不能是指针到只读内存(例如const变量或文字字符串)。如果此参数是常量字符串,则该函数可能会导致访问冲突。”
-
@IInspectable,我知道,指定的代码有点简化。
-
简化和引入错误是有区别的。简化版本将使用
WCHAR params[] = L"/c [...] ";。同样简单,但正确。 -
@IInspectable 是的,你是对的,我的错。我会马上解决这个问题。
标签: c++ windows winapi impersonation lnk