使用“ CreateProcessAsUser”启动的进程的行为与交互式启动的进程不同

时间:2019-09-19 06:11:13

标签: c# winapi

在通过右键单击并在浏览器控件中的某些链接上选择“目标另存为”时,通过CreateProcessAsUser api启动时,已启动应用程序中的嵌入式Webbrowser控件会引发错误“无法将文件写入缓存”。

作为OnStart()函数的一部分,正在服务中进行CreateProcessAsUser调用。它通过枚举所有会话并检查“ WTS_CONNECTSTATE_CLASS.WTSActive”的状态来检索当前用户会话的句柄

通过双击启动完全相同的可执行文件,我可以下载文件而不会出现问题。

我已经通过任务管理器详细信息以及System.Security.Principal.WindowsIdentity.GetCurrent()。Name验证了启动的进程是否在同一用户帐户下运行。

我尝试使用交互式登录帐户运行该服务;这样做会阻止服务使用CreateProcessAsUser函数启动任何可执行文件。使用System.Diagnostics.Process.Start()启动的进程位于会话0上,并且对交互式桌面隐藏,并且无法访问任何网络资源。

我也尝试过使用通过StartInfo传递用户凭据的System.Diagnostics.Process,但是在调用Start()时出现“访问被拒绝”的情况。

 if (WTSEnumerateSessions(
                (IntPtr)WTS_CURRENT_SERVER_HANDLE,  // Current RD Session Host Server handle would be zero.
                0,                                  // This reserved parameter must be zero.
                1,                                  // The version of the enumeration request must be 1.
                ref ppSessionInfo,                  // This would point to an array of session info.
                ref SessionCount                    // This would indicate the length of the above array.
                ))
            {
                for (int nCount = 0; nCount < SessionCount; nCount++)
                {
                    // Extract each session info and check if it is the 
                    // "Active Session" of the current logged-on user.
                    WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(
                        ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)),
                        typeof(WTS_SESSION_INFO)
                        );

                    if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
                    {
                        IntPtr hToken = IntPtr.Zero;
                        if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
                        {
                            // Launch the child process interactively 
                            // with the token of the logged-on user.
                            PROCESS_INFORMATION tProcessInfo;
                            STARTUPINFO tStartUpInfo = new STARTUPINFO();
                            tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));

                            bool ChildProcStarted = CreateProcessAsUser(
                                hToken,             // Token of the logged-on user.
                                ChildProcName,      // Name of the process to be started.
                                Args,               // Any command line arguments to be passed.
                                IntPtr.Zero,        // Default Process' attributes.
                                IntPtr.Zero,        // Default Thread's attributes.
                                false,              // Does NOT inherit parent's handles.
                                0,                  // No any specific creation flag.
                                null,               // Default environment path.
                                workingDirectory,   // Default current directory.
                                ref tStartUpInfo,   // Process Startup Info. 
                                out tProcessInfo    // Process information to be returned.
                                );

我希望使用上述代码启动的程序的行为与从桌面会话以交互方式启动时的行为相同-除了webbrowser控件和urlmon行为外,它似乎是相同的。

1 个答案:

答案 0 :(得分:0)

根据RbMm的建议,我修改了调用以包括环境指针,lpDesktop规范和CREATE_UNICODE_ENVIRONMENT标志

                            STARTUPINFO tStartUpInfo = new STARTUPINFO();
                            tStartUpInfo.lpDesktop = "winsta0\\default";
                            tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
                            IntPtr environment = IntPtr.Zero;
                            if (!CreateEnvironmentBlock(out environment, hToken, true))
                            {
                                environment = IntPtr.Zero;
                                throw new Exception("No Environment");
                            }

                            bool ChildProcStarted = CreateProcessAsUser(
                                hToken,             // Token of the logged-on user.
                                ChildProcName,      // Name of the process to be started.
                                Args,               // Any command line arguments to be passed.
                                IntPtr.Zero,        // Default Process' attributes.
                                IntPtr.Zero,        // Default Thread's attributes.
                                false,              // Does NOT inherit parent's handles.
                                0x00000400,         // CREATE_UNICODE_ENVIRONMENT creation flag.
                                environment,        // Default environment path.
                                workingDirectory,   // Default current directory.
                                ref tStartUpInfo,   // Process Startup Info. 
                                out tProcessInfo    // Process information to be returned.
                                );