【问题标题】:Problem launching a System.Diagnostics.Process under Windows 7在 Windows 7 下启动 System.Diagnostics.Process 时出现问题
【发布时间】:2011-05-02 08:54:26
【问题描述】:

我正在尝试从 .NET 3.51 启动一个应用程序(操作系统、我的应用程序和我要启动的应用程序都是 32 位)。

启动进程的代码用于其他应用程序,但有一个让我们头疼。如果我们“双击”应用程序的图标,它会按预期工作,这意味着它可以作为计算机中的应用程序正常工作。直接双击.exe也可以。

操作系统是 Windows 7 32Bits(家庭版和/或专业版)。

我们的 .NET 应用程序是用 x86 编译的,以避免出现问题。

启动“进程”的代码位于我们制作的 DLL(也是 32 位)中,基本上它是一个简单的 DLL,包含一些“通用代码”、通用方法、函数和我们在整个过程中使用的东西代码。其中一种方法如下所示:

public static bool FireUpProcess( Process process, string path, bool enableRaisingEvents,
        ProcessWindowStyle windowStyle, string arguments )
    {
        if ( process != null )
        {
            try
            {
                process.StartInfo.FileName = @path;
                if ( arguments != null )
                {
                    if ( arguments != String.Empty )
                    {
                        process.StartInfo.Arguments = arguments;
                    }
                }
                process.StartInfo.WindowStyle = windowStyle;
                process.EnableRaisingEvents = enableRaisingEvents;
                process.Start();
            }
            catch
            {
                try
                {
                    process.Kill();
                }
                catch ( InvalidOperationException )
                {
                } // The process is not even created

                return false;
            }
        }
        else
        {
            return false;
        }
        return true;
    }

我不知道这个方法是谁写的,但它已经在不同的应用程序上工作了大约六年,因此我认为它“没问题”。但是,我们有一个客户的软件在通过该参数时无法启动。

参数是

  1. process 是使用简单的“new Process();”创建的 System.Diagnostics.Process;
  2. path 是 .exe “c:/path/to/my.exe” 的完整路径。
  3. enableRaisingEvents 为假
  4. windowStyle 已最大化(但已尝试其他)。

它给出了一个糟糕的消息框……我很高兴地让它永垂不朽。它是西班牙语,但翻译应该很容易:

上面写着:

应用程序错误 程序 (0x0eedfade) 发生意外异常...

谷歌搜索 0x0eedfade 给出的奇怪结果看起来很吓人,但事实是,如果我转到我尝试启动的 .exe 并双击它,它会完美运行。

记录:如果我尝试启动其他东西(例如:Notepad.exe、Adobe Acrobat Reader),它可以工作,但是 Firefox 无法打开并且不会'不显示错误。

这种“有些有效,有些无效”的行为让我相信 Windows 7 安全机制或类似的问题可能存在我不知道的问题。

我错过了什么或做错了什么?

更新:好的;我得到了软件的副本。这是一个凌乱的软件,但它可以工作。现在我可以调试了,我看到程序在使用我的FireUpProcess 方法启动时出现错误。

按照建议,我添加了 WorkingDirectory 代码,但代码如下:

    public static bool FireUpProcess(Process process, string path, bool enableRaisingEvents, ProcessWindowStyle windowStyle)
    {
        if (process != null)
        {
            try
            {
                if ( !String.IsNullOrEmpty(@path) )
                {
                    process.StartInfo.FileName = @path;
                    process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(@path);
                    process.StartInfo.WindowStyle = windowStyle;
                    // Suscribe to the exit notification
                    process.EnableRaisingEvents = enableRaisingEvents;
                    // Disable to prevent multiple launchs
                    Framework.Check.LogWarning("LAUNCHING EXTERNAL DEVICE WITH PATH: " + path);
                    process.Start(); // HERE The program reports the following:

这意味着,“程序无法启动,因为 ddip.dll 丢失...尝试重新安装 bla bla”。

问题是,如果我从命令行执行相同的@path,程序会完美打开:

这将打开程序。如果我单击位于“程序”菜单中的“快捷方式”,也会发生同样的情况。该快捷方式中没有任何参数,它是对可执行文件的简单调用。

所以现在的问题是:我的代码和其他方法有什么区别?

一定有一些不同的东西导致我的进程无法启动。

有什么想法吗?

更新和解决方案

我通过使用以下提供的答案之一使其工作。事实证明,没有人直接向我指出解决方案,但他们都在这里和那里给了我很好的想法。

我在 我们的 应用程序中添加了一个应用程序清单(应该在 vista 时代就拥有它,不知道为什么一开始就没有它)。我使用 VStudio 2008 添加文件 -> 应用程序清单添加的应用程序清单。

在里面,我确定我们有这个:

<requestedExecutionLevel level=“asInvoker” uiAccess=“false” />

我们不需要管理员或类似的东西,但显然 Vista/7 需要知道它。

添加后,进程正确启动。

注意:UseShellExecute 默认为 true(如某些人所建议的那样),如果您需要,您必须明确将其设置为 false。

【问题讨论】:

  • 我知道,这不是问题,但您可以将if 简化为if ( !String.IsNullOrEmpty(arguments) )。 SCNR
  • 什么是DBSWIN.EXE?根据许多网站的说法,这可能是 IE 的第 3 方扩展的问题……PC 会被感染吗?
  • @Bobby DBSWIN.EXE 是这些家伙使用的软件的一部分:duerrdental.de/en/home-dd(实际上是这个:duerrdental.de/en/products/imaging/dbswin-imaging-software
  • @Bobby 是的,我刚刚注意到,感谢您指出这一点。这段代码来自 .NET 1.0 或 1.1,并且“多年来”没有受到任何影响,所以上帝知道还有哪些其他“未优化”的东西。
  • 恶意软件/病毒扫描是否带来了什么?

标签: c# .net windows-7 system.diagnostics


【解决方案1】:

如果 exe 具有清单,则应在调用 Start 之前在进程对象上将 UseShellExecute 设置为 true。无论如何,这不是一个坏主意。

【讨论】:

  • @Kate 你能给我指出一个更“扩展”的解释吗?谢谢。
  • UseShellExecute 默认为真。
  • @P.Brian 是的,我也发现了。
  • 将此标记为正确答案,因为清单/链接是引导我找到正确解决方案的起点。谢谢
【解决方案2】:

您没有设置 process.StartInfo.WorkingDirectory 属性。有很多写得不好的软件假设工作目录将是存储 EXE 的目录。至少添加这一行:

 process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(@path);

然而,这个例外相当奇怪。我绝对建议您告诉客户更新他们的反恶意软件工具。

【讨论】:

  • 遗憾的是这并没有改变任何东西(但我还是会把它留在代码中)。我们正在下载该软件的最新版本,看看它是否也存在。
  • Hmya,请关注我回答的最后一段。你已经看到了谷歌的点击率。
【解决方案3】:

我过去也遇到过类似的问题。我通过执行 cmd 应用程序解决了它,如下所示:

public static bool FireUpProcess(Process process, string path, bool enableRaisingEvents, ProcessWindowStyle windowStyle) 
{ 
    //if path contains " ", surround it with quotes.
    //add /c and the path as parameters to the cmd process. 
    //Any other parameters can be added after the path.

    ProcessStartInfo psi = new ProcessStartInfo("cmd", "/c" + path ));            
    psi.WorkingDirectory = System.IO.Path.GetDirectoryName(@path);          
    psi.WindowStyle = windowStyle;          
    // Suscribe to the exit notification          
    process.EnableRaisingEvents = enableRaisingEvents;          
    // Disable to prevent multiple launchs          
    Framework.Check.LogWarning("LAUNCHING EXTERNAL DEVICE WITH PATH: " + path);          
    process.Start(); ...}

【讨论】:

  • 我不确定这如何帮助您排除故障,但您需要在“/c”之后附加一个空格。还需要将 psi 对象分配给 process 对象以使其生效。
【解决方案4】:

如果可能的话,我会尝试使用来自 Sysinternals 的Process Monitor。当您启动它时,您可以取消选择工具栏上的注册表和网络活动(右侧的 5 个图标)。然后您只会看到进程和磁盘活动。由于它看起来像一个文件未找到问题,您应该使用过滤器对话框(左侧的 6. 图标)从下拉列表中选择进程名称(架构是默认设置)并输入您失败的可执行文件名称。这将极大地限制捕获的输出,因此您可以看到发生了什么。然后启动可执行文件并在结果列中检查 NAME NOT FOUND 结果。这是搜索但未找到文件的位置。如果您知道有问题的 dll 名称,您可以像往常一样使用 Ctrl+F 搜索它以将其挖掘出来。然后,您可以比较您的工作应用程序的不同搜索路径以及它从您的应用程序启动的时间。

可能是环境变量 PATH 在您的进程中具有不同的值吗?可能是添加 . (当前目录)有助于修复 dll 搜索路径。还是应用程序是从不同的用户帐户启动的?这也可能是新功能,当应用程序将内容安装到 Programm Files 但没有权限(只有管理员可以这样做)时,Windows 会将写入重定向到用户配置文件中。这是一种安全且透明的方式来获得更安全。但这可能导致例如在第一次应用程序启动期间,例如当他在未经 UAC 对话框同意的情况下运行应用程序时,将配置文件部署到管理员配置文件中。然后其他用户也可能启动应用程序但失败,因为附加配置文件位于管理员配置文件中,而不是像每个人预期的那样位于程序文件中。

【讨论】:

    【解决方案5】:

    正如 Kate Gregory 指出的,如果您想“模拟”用户双击图标,您必须将 UseShellExecute 设置为 true。设置此标志使代码使用完全不同的路径,使用底层窗口 ShellExecute 函数。

    现在,我要补充一点,如果您在配备 UAC 的 Windows(Vista、7、2008,...)上运行,您也许还应该尝试使用 runasherehere 解释的动词。

    如果使用 .NET,那就是:

    if (System.Environment.OSVersion.Version.Major >= 6)  // UAC's around...
    {
       processStartInfo.Verb = "runas";
    }
    

    【讨论】:

    • 感谢您提供的信息,一定会很方便。请注意,根据 MSDN,UseShellExecute 默认为 true。
    【解决方案6】:

    我相信 Hans Passant 是在正确的轨道上。除了他说的,检查确保ddip.dll和exe在同一个目录下。情况并非总是如此,因为有 other ways 来绑定 bin 外的程序集。即 GAC 和 AssemblyResolve 事件。考虑到您的情况,我认为 GAC 没有理由参与其中。检查启动的 exe 代码是否有任何挂钩到 AssemblyResolve 事件。如果它被挂钩,您可能需要更新实现以允许另一个进程启动它。

    因为您收到有关缺少 DLL 的异常,所以我对有关路径分隔符问题的答案没有信心。尽管如此,您拥有应用程序代码,因此请验证它是否引用了 ddip.dll。这将使您确信您实际上引用了正确的 .exe,因此这不仅仅是命令提示符的路径分隔符问题(例如误解的空格)。

    【讨论】:

      猜你喜欢
      • 2011-10-19
      • 2016-04-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 2012-02-26
      相关资源
      最近更新 更多