5

我正在尝试从 .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是一个 System.Diagnostics.Process 使用简单的“new Process();”创建的</li>
  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。

4

6 回答 6

8

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

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

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

于 2010-10-29T14:07:39.753 回答
5

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

于 2010-10-29T13:51:27.200 回答
3

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

现在,我要补充一点,如果您在配备 UAC 的 Windows(Vista、7、2008,...)上运行,您可能还应该尝试使用runas动词,如此此处所述。

使用 .NET,这将是:

if (System.Environment.OSVersion.Version.Major >= 6)  // UAC's around...
{
   processStartInfo.Verb = "runas";
}
于 2010-12-05T09:39:58.653 回答
1

我过去也遇到过类似的问题。我通过执行 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(); ...}
于 2010-12-01T16:24:51.173 回答
1

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

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

于 2010-12-04T00:03:08.210 回答
0

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

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

于 2010-12-06T22:04:54.370 回答