从shell_execute启动时,Clickonce程序不会启动

时间:2013-11-08 15:51:08

标签: c# clickonce shellexecute

我有一个很老的程序,我无法控制。它启动一个文件类型及其默认应用程序(我无法修改此代码):

LET Err (SHELL_EXECUTE 'open' (FIX_MESG '"{1}"' File_name) '' '')

^^上述代码有效,只要该文件类型与ClickOnce程序无关。

旧程序是32位,操作系统是Windows 7 64位。我可以将我的clickonce程序编译为任何东西,但似乎都没有。 (我尝试过x86,x64和任何CPU)

如何让32位程序使用shell execute在64位操作系统上启动ClickOnce程序?

更多细节: 这是一个可重现的错误。建立2个程序。程序1是Clickonce程序。将其与任何文件类型相关联。程序2将执行shell执行命令以打开与clickonce程序关联的任何文件类型。如果将程序2编译为x86,它将为您提供成功响应,但不执行任何操作。

控制台shell执行程序的测试代码:

private static void Main()
{
    int value = ShellExecuteA(IntPtr.Zero, "open", @"C:\Users\bsee\Desktop\testfile.ecn2", "", "", 0);
        if (value > 32)
            MessageBox.Show("Clickonce reports success. But did it actually start?");
}

[DllImport("Shell32.dll")]
public static extern int ShellExecuteA(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirecotry, int nShowCmd);

1 个答案:

答案 0 :(得分:10)

这是一个非常常见的问题,很多谷歌点击但很少有解决方案。您的代码段存在缺陷,无法诊断问题,当然还有您需要互操作的应用中的问题。它会启动文件关联就好了,问题是它无法完成这项工作。您的代码段无法诊断此问题,您必须使用Process类,并在该过程完成时获取ExitCode。它不会是0。

让我们谈谈出了什么问题。 ClickOnce为您创建文件关联,并将为文件扩展名编写“open”动词,如下所示:

 rundll32.exe dfshim.dll, ShOpenVerbExtension {guid} %1

还为{guid}写了另一个注册表项,写入HKCU\Software\Classes\CLSID\{guid}。其中dfshim.dll的ShOpenVerbExtension()函数将查找{guid}。这个密钥在64位操作系统上是特殊的,它有两个版本。 registry redirector将重新映射打开32位应用程序密钥的请求,而是转到Software \ Wow6432Node。这是64位版本Windows中的一种基本机制,可以防止32位应用程序意外加载64位组件时出现问题。对COM来说尤其重要。

还有两个版本的rundll32.exe。一个在c:\ windows \ system32,64位版本,另一个在c:\ windows \ syswow64,32位版本。该32位版本将看到注册表项的重定向视图。使用哪一个由另一个重定向确定,由文件重定向器实现。这会自动将32位应用程序对c:\ windows \ system32中文件的请求重新映射到c:\ windows \ syswow64。另一个重要的对策,阻止32位应用程序在意外加载64位Windows DLL时失败。

也许你在这里看到麻烦,问题是你需要互操作的这个应用程序是一个32位的应用程序。因此,它总是最终从c:\ windows \ syswow64运行32位版本的rundll32.exe。 dfshim.dll现在最终会查看注册表的System \ Wow6432Node部分,并且不会在那里找到{guid}。主要的失败鲸鱼,它不显示任何类型的错误消息,如果应用程序没有检查ExitCode,那么根本就没有诊断。

值得注意的是,您可以轻松地使您的测试程序成功。 Project + Properties,Build选项卡,将Platform Target设置更改为AnyCPU。在VS2012及更高版本上关闭“首选32位”选项。你的ShellExecute()调用现在将使用c:\​​ windows \ system32 \ rundll32.exe程序,dfshim在检索{guid}方面没有问题。

您还可以轻松修复32位版本。只需使用Regedit.exe编辑文件关联的 open 动词,并将其更改为%windir%\sysnative\rundll32.exe。名称的“sysnative”部分是文件重定向器可以理解的特殊名称,将请求映射到system32,因此您将始终获得64位版本的程序。

ClickOnce团队也可以修复它,并且根据连接文章这样做,他们可能最终编写两个 CLSID\{guid}键。该修复程序不包含在.NET 4.0中,不确定它是否已成为4.5。编辑:它确实。

许多可能的修复,核心问题是你只是没有足够的控制权。您当然无法使该应用程序以64位模式运行,您通常无法确保目标计算机具有.NET的更新版本,您无法更改ClickOnce安装程序写入注册表项的内容。

还剩下两个选择:不要使用ClickOnce或要求客户自己编辑注册表项。您可以制作.reg文件以最大限度地减少错误的几率。