2015-08-03 43 views
1

我正在编写32位服务应用程序,我希望能够为登录用户启动开始菜单项。我还是设法通过模拟用户使用启动CreateProcessAsUser使用命令行选择的.lnk文件来完成这项任务:%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "。它适用于除了一堆系统的快捷键几乎每一个快捷键,配件文件夹(如粘Notes.lnk,剪断Tool.lnk)。在此次推出的截图工具的我与这个错误CMD接收到消息框:某些系统默认的.lnk文件在模拟用户下启动的问题

Windows无法找到“C:\ ProgramData \微软\的Windows \开始菜单\程序\附件\剪断Tool.lnk ”。确保你输入了正确的名字,然后再试一次。

但.lnk文件存在于这个目录中!

摘要:

  • 服务是32位
  • 的Windows 8专业版64位
  • 启动快捷方式由用户模拟和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; 
    } 
    

我怎么会错过吗?

+0

[CreateProcessAsUser](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682429.aspx):*“lpCommandLine:此函数的Unicode版本,** CreateProcessAsUserW **,可以修改该字符串的内容,因此该参数不能是指向只读内存的指针(如const变量或**文字字符串**),如果该参数是一个常量字符串,则该函数可能会导致访问违反。“* – IInspectable

+0

@IInspectable,我知道,指定的代码有点简化。 –

+0

简化和引入错误是有区别的。简化版本将使用'WCHAR params [] = L“/ c [...]”;'。同样简单,但正确。 – IInspectable

回答

3

这并不是说缺少LNK文件,但它的目标。

好像是WOW64问题 - 对于您的32位服务,%WINDIR%\System32实际上重定向到SysWOW64,并且这些可执行文件在那里不存在。

嗯,其实您的32位服务是找到32位cmd.exe它确实在SysWOW64存在,然后32位的cmd.exe有上述问题,查找在快捷找到的路径%windir%\system32\SnippingTool.exe时。

我可以使用32位命令提示符重现该问题。试图使用这些快捷方式的32位进程只是失败。

尝试产卵cmd.exe(64位系统上)的原生版本,使用%WINDIR%\SysNative\cmd.exe

另外,你引用的问题。您试图嵌套引号,但实际发生的情况是第二个引号与第一个引号匹配并退出引号,而不是嵌套。

将来,如果某个服务中的某些部件发生故障,从普通的控制台应用程序运行相同的调用会很有帮助。在这种情况下,您会立即发现问题与假冒完全无关。第二步,如果它从控制台应用程序运行,那么应用程序在配置文件中运行时,将使用控制台应用程序的“运行方式”来测试模拟逻辑,而不会增加服务环境的复杂性。

0

CreateProcessAsUser不会将指定的用户配置文件加载到HKEY_USERS注册表项中。因此,要访问HKEY_CURRENT_USER注册表项中的信息,必须在调用CreateProcessAsUser之前使用LoadUserProfile函数将用户的配置文件信息加载到HKEY_USERS中。确保在新进程退出后调用UnloadUserProfile。

According to the msdn page

MSDN建议使用CreateProcessWithLogonW或CreateProcessWithTokenW,或手动加载用户的简档信息。

而且也:

CreateProcessAsUser允许您访问指定的目录和可执行映像中呼叫方或目标用户的安全上下文。默认情况下,CreateProcessAsUser在调用者的安全上下文中访问目录和可执行映像。在这种情况下,如果调用者无法访问目录和可执行映像,则该功能失败。访问使用目标用户的安全上下文中的目录和可执行图像,调用CreateProcessAsUser之前到ImpersonateLoggedOnUser函数的调用指定hToken。

+0

根据问题,用户登录(因此,他们的配置文件已经加载)。 –

+0

啊,是的,好点。 –