通过.NET中的Process.Start生成的进程挂起了该线程

时间:2010-08-17 17:42:44

标签: .net multithreading shell browser process

我们的应用程序有一个后台线程,它通过System.Diagnostics.Process生成一个进程:

Process.Start(
    new ProcessStartInfo
    {
        FileName = url,
        UseShellExecute = true
    }
);

这曾经没有任何问题。但现在,后台线程正在悄无声息地死去;它永远不会从通话Process.Start返回。处理System.Exception的此代码的catch块也未到达。即使我在Visual Studio调试器中抛出时启用了处理异常,我也看不到异常。奇怪的是,这个过程很快就会产生;使用预期的URL启动用户的默认浏览器。

我们的流程的入口点标有[STAThread]的推荐值。

什么可能导致我们的线程无声终止?是否有任何技术可用于调试线程终止期间发生的事情?

更新

看起来线程毕竟是活着的;它只是没有从通话中返回。这是它的堆栈跟踪:

  • [在睡眠中等待或加入]
  • System.dll!System.Diagnostics.ShellExecuteHelper.ShellExecuteOnSTAThread()+ 0x63 bytes
  • System.dll!System.Diagnostics.Process.StartWithShellExecuteEx(System.Diagnostics.ProcessStartInfo startInfo)+ 0x19d bytes
  • System.dll!System.Diagnostics.Process.Start()+ 0x39 bytes
  • System.dll!System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo startInfo)+ 0x32 bytes
  • 我的方法

更新2:

在不使用shell执行的情况下启动cmd.exe可以解决此问题。谢谢你!但是,我仍然想知道为什么呼叫没有返回。

更新3:

Shell钩子听起来像是一个逻辑解释,可能导致调用不返回。我找不到流氓模块,但在最后一次尝试通过shell执行后,调用确实返回。

在任何情况下,用户都可能加载了shell扩展,这可能会导致进程启动并导致我的代码无法返回。我们无法对 做任何事情,所以正确的答案是使用启动cmd.exe进程的解决方法。

2 个答案:

答案 0 :(得分:5)

不,线程没有默默地终止,它们发出响亮的kaboom声音。至少你会在Output窗口中看到线程退出通知。 Process.Start()方法阻塞将是另一种解释,尽管没有解释。你的片段太短,无法提供合适的诊断。也许是环境问题。


你的堆栈跟踪有帮助,ShellExecuteOnSTAThread()实际上在一个小帮助线程上执行阻塞Thread.Join()。该线程是调用本机ShellExecuteEx()API函数所必需的,它只能从STA线程调用。它有一个缺点,STA线程也必须泵出一个消息循环。这个小帮手没有。

这会导致您的计算机出现问题仍然指向环境问题,某种系统加载项会劫持ShellExecuteEx()调用。并依靠运行真正的STA线程。您应该能够在Debug + Windows + Threads窗口中找到该帮助程序线程。它应该在堆栈中包含“ShellExecuteFunction”。例如,那种吸引像这样的特技的“系统附加组件”就是病毒扫描程序。在项目的“调试”选项卡中选中“启用非托管调试”后,您应该能够在Debug + Windows + Modules窗口中找到该alienware。

使用UseShellExecute = false的解决方法在这里完全可以接受。事实上,你的机器看起来有点混乱,当然不是。

答案 1 :(得分:5)

正如Hans Passant所提到的那样,挂起Process.Start电话可能就是原因。在Process.Start设置为UseShellExecute的情况下使用true时,会在引擎盖下调用Windows API函数ShellExecuteEx,在某些情况下可能无法返回。

您可以通过向代码中添加跟踪消息来检查是否是这种情况:

System.Diagnostics.Trace.WriteLine("About to start process.");
Process.Start(
   new ProcessStartInfo
   {
       FileName = url,
       UseShellExecute = true
   }
);
System.Diagnostics.Trace.WriteLine("Process started.");

要收听跟踪消息,您可以使用TraceListener,检查Visual Studio的输出窗口或使用DebugView等工具。

作为解决方法,您可以使用start命令。以下代码启动一个隐藏的shell窗口,它“启动”url:

Process.Start(
    new ProcessStartInfo()
    {
        FileName = "cmd.exe",
        Arguments = "/c start http://www.google.com",
        WindowStyle = ProcessWindowStyle.Hidden,
        UseShellExecute = false
    });