本文介绍了从shell_execute启动后,Clickonce程序将无法启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常老的程序,无法控制。它使用默认应用程序启动文件类型,如下所示(我无法修改此代码):

I have a very old program that I have no control over. It launches a filetype with its default application like this(I cannot modify this code):

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

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

^^The above code works, so long as that filetype isn't associated with a ClickOnce program.

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

The old program is 32 bit, the OS is Windows 7 64 bit. I can compile my clickonce program as anything, but none seem to work. (I've tried x86, x64 and anyCPU)

如何使用shell执行程序来使32位程序在64位OS上启动ClickOnce程序?

How can I make a 32 bit program use shell execute to launch a ClickOnce program on a 64bit OS?

更多详细信息:
这是可重现的错误。生成2个程序。程序1是一个Clickonce程序。将其与任何文件类型关联。程序2将执行shell执行命令以打开与clickonce程序关联的任何文件类型。如果将程序2编译为x86,它会给您成功的响应,但什么都不做。

More details:This is a reproducible error. Build 2 programs. Program 1 is a Clickonce program. Associate it with any filetype. Program 2 will do a shell execute command to open whatever filetype the clickonce program is associated with. If you compile program 2 as x86, it will give you a success response, but do nothing.

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

Test code for console shell execute program:

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);


推荐答案

这是一个非常普遍的问题,很多Google命中但解决方案很少。您的代码段存在缺陷,无法诊断问题,当然也无法诊断该应用程序中的问题。它将很好地启动文件关联,问题在于它随后无法完成该工作。您的代码段无法诊断出这一点,您必须改用Process类,并在过程完成时获取ExitCode。不会是0。

This is a pretty common problem, lots of google hits but few solutions. Your code snippet is flawed and cannot diagnose the issue, surely also the problem in that app you have to interop with. It will start the file association just fine, the issue is that it then fails to do the job. Your code snippet cannot diagnose this, you must use the Process class instead and obtain the ExitCode when the process completes. It will not be 0.

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

Let's talk about what goes wrong. ClickOnce creates the file association for you and will write the "open" verb for the file extension like this:

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

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

And also writes another registry key for the {guid}, written to HKCU\Software\Classes\CLSID\{guid}. Where dfshim.dll's ShOpenVerbExtension() function will look for the {guid}. This key is special on a 64-bit operating system, there are two versions of it. The registry redirector will remap the request to open the key for a 32-bit app, it goes to Software\Wow6432Node instead. This is a basic mechanism in the 64-bit version of Windows that prevents trouble when 32-bit apps accidentally load 64-bit components. Particularly important for COM.

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

There are also two versions of rundll32.exe. One in c:\windows\system32, the 64-bit version and another in c:\windows\syswow64, the 32-bit version. That 32-bit version will see the redirected view of the registry keys. Which one is used is determined by another redirection, implemented by the File Redirector. Which automatically remaps requests that 32-bit apps make to files in c:\windows\system32 to c:\windows\syswow64. Yet another important counter-measure to stop 32-bit apps from failing when they accidentally load a 64-bit Windows DLL.

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

Perhaps you see the trouble here, at issue is that this app you need to interop with is a 32-bit app. It will therefore always end up running the 32-bit version of rundll32.exe from c:\windows\syswow64. dfshim.dll now is going to end up looking in the System\Wow6432Node part of the registry and will not find the {guid} there. Major fail whale, it doesn't display any kind of error message and if the app doesn't check the ExitCode either then there's no diagnostic at all.

值得注意的是您可以轻松地使您的测试程序成功。在项目+属性的构建选项卡上,将平台目标设置更改为AnyCPU。在VS2012及更高版本上,关闭首选32位选项。现在,您的ShellExecute()调用将使用c:\windows\system32\rundll32.exe程序,并且dfshim可以轻松检索到{guid}。

Notable is that you can easily make your test program succeed. Project + Properties, Build tab, change the Platform Target setting to AnyCPU. Turn off the "Prefer 32-bit" option off on VS2012 and up. Your ShellExecute() call will now use c:\windows\system32\rundll32.exe program and dfshim has no trouble retrieving the {guid}.

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

You can also easily fix the 32-bit version of it. Just use Regedit.exe to edit the open verb of the file association and change it to %windir%\sysnative\rundll32.exe. The "sysnative" part of the name is a special name that the file redirector understands, mapping the request to system32 so you'll always get the 64-bit version of program.

ClickOnce团队也可以修复它,并且根据连接文章完成了此操作,他们可能最终都写了 CLSID\ {guid} 键。该修补程序不包含在.NET 4.0中,不确定是否将其纳入4.5。

The ClickOnce team can fix it too, and has done so according to the connect article, they probably ended up writing both CLSID\{guid} keys. That fix is not included with .NET 4.0, not sure if it made it into 4.5. it did.

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

Plenty of possible fixes, the core problem is that you just don't have enough control over it. You of course can't get that app to run in 64-bit mode, you cannot typically make sure that the target machine has the updated version of .NET, you cannot change what the ClickOnce installer writes to the registry keys.

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

Just two alternatives left: don't use ClickOnce or ask the customer to edit the registry key himself. You can craft a .reg file to minimize the odds for mistakes.

这篇关于从shell_execute启动后,Clickonce程序将无法启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-27 23:32