ClickOnce部署-文件关联未注册

9
这里是问题的简要概述:
摘要:
我设置了ClickOnce应用程序的fileAssociations,但是当我运行/更新程序时它们没有注册(我的.bvr文件没有图标,我无法双击它们启动我的应用程序)。
额外信息:
我首先尝试通过属性->发布->选项->文件关联来设置关联。在那次失败的尝试之后,我尝试直接在app.manifest中设置它。
<fileAssociation
xmlns="urn:schemas-microsoft-com:clickonce.v1"
extension=".bvr"
description="Behavior File"
progid="GGS.Behavior"
defaultIcon="bvrico.ico"
/>

我已经阅读了很多关于这个问题的文章,开始感到沮丧。以下是一些信息:
  1. 我将其设置为完全信任应用程序(在安全性 -> 启用ClickOnce安全设置 -> 这是完全信任应用程序下)
  2. 我正在使用.NET 4.0和Visual Studio 2010
  3. 启用“离线”模式
我还处理通过AppDomain传递的数据,但我怀疑那真的改变了什么。
我想知道也许文件关联只能在安装时设置。
无论如何,我非常希望对这个问题有一些见解。我真的很想在我的项目中使用文件关联。
提前感谢大家。
PS: 在Windows XP和Windows 7上测试过。
编辑:顺便说一下,我也在微软上发布了这个问题。

http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/d610cd55-f3c7-4775-a417-251261832200

如果有人也想在那里发布答案的话,我真的想不出来这个问题的答案。:D

有没有一些命令行可以注册文件关联?只需在应用程序启动时启动一个小的命令行来重新注册它,你就可以开始了。http://commandwindows.com/assoc.htm - CodingBarfield
似乎文件关联不仅在安装时设置 - 我更新了一个没有关联设置的测试应用程序,添加了新的文件关联设置,当双击相关文件时,应用程序可以正常启动。 - Sascha Hennig
6个回答

6
如果你试图注册的文件类型之前已经被其他程序(如记事本)注册过,或者在记事本中打开过该文件类型,那么我发现唯一的解决方法是从注册表中删除两个位置中的该文件类型,并重新启动计算机。之后发布应用程序的更新,如果是这种问题,你就可以放心了。
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.bvr HKEY_CLASSES_ROOT\.bvr 重新启动计算机
发布应用程序的更新。

它属于另一种类型的什么?答案不完整! - CinCout
我只是在上述注册表键中删除了文件扩展名,卸载了程序,重新安装了程序,然后它就可以工作了。在我的情况下,很可能是另一个程序与该文件扩展名相关联。 - iCode

2
你确定在“打开方式”文件选项中没有出现以下项目 - 带有问号图标的“Clickonce应用程序部署支持库”吗?尝试将其设置为默认选项。
我遇到了与您相同的问题,但我注意到这个奇怪的选项出现在我安装应用程序后。经过多次尝试和搜索,我尝试了一个简单的方法 - 同意将此 Clickonce应用程序部署支持库作为所需文件类型的默认选项。然后,文件的图标变成了我的应用程序图标,并启动了我的应用程序。我想问题是我的所需文件类型已经与记事本相关联,因此ClickOnce拒绝覆盖此设置。

2
只有在ClickOnce部署后添加/更新代码中的多个注册表项才能使其正常工作。请参见下面。
已经过去了8年,即使在最新版本的Visual Studio 2019和Windows 10中,ClickOnce部署中的文件关联设置仍然无法正常工作。我怀疑这是一个Windows版本问题,因为微软似乎会在每个新版本的Windows中更改文件关联存储在注册表中的方式。但不管怎样,Visual Studio和ClickOnce应该为当前的Windows版本提供支持,但事实并非如此。
在完成干净安装我的ClickOnce应用程序后,我发现只有一个与我的文件扩展名相关的注册表项。
Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xxxxxx

它为ProgID添加了这个注册表项:

Computer\HKEY_CLASSES_ROOT\xxxxxxxxxxx

但是它并没有添加文件扩展名到ProgID的引用。
在Windows 10中,这两个条目都没有作用。它不显示图标,不会在使用该扩展名打开文件时打开ClickOnce应用程序,并且不会在“打开方式”列表中显示任何ClickOnce选项(如评论者所建议的)。请注意,上述注册表条目由部署创建,但不包含对设置在ClickOnce属性中的ClickOnce应用程序或ProgID的任何引用。实际上,在该文件扩展名注册表条目中唯一被引用的应用程序是“OpenWith.exe”。
解决方法
经过2天的研究和整合各种想法后,下面的解决方法是我找到的唯一一个有效的。每次你的应用程序启动时(或至少在安装/升级后立即执行SetAssociation()),它都可以解决所有版本Windows中的文件关联问题。
using Microsoft.Win32;
using System;
using System.Collections.Generic;

namespace MyLibrary
{
    public class FileAssociations
    {
        [System.Runtime.InteropServices.DllImport("Shell32.dll")]
        private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

        private const int SHCNE_ASSOCCHANGED = 0x8000000;
        private const int SHCNF_FLUSH = 0x1000;

        public static bool SetAssociation(string extension, string progId, string fileTypeDescription, string applicationFilePath)
        {
            bool madeChanges = false;
            madeChanges |= SetKeyDefaultValue(@"Software\Classes\" + extension, progId);
            madeChanges |= SetKeyDefaultValue(@"Software\Classes\" + progId, fileTypeDescription);
            madeChanges |= SetKeyDefaultValue($@"Software\Classes\{progId}\shell\open\command", "\"" + applicationFilePath + "\" \"%1\"");
            return madeChanges;
        }

        private static bool SetKeyDefaultValue(string keyPath, string value)
        {
            using (var key = Registry.CurrentUser.CreateSubKey(keyPath))
            {
                if (key.GetValue(null) as string != value)
                {
                    key.SetValue(null, value);
                    return true;
                }
            }

            return false;
        }
    }
}

在程序启动时执行此操作。Environment.GetCommandLineArgs() 中的第一项包含您的 exe 的完整路径:

string[] args = Environment.GetCommandLineArgs();
FileAssociations.SetAssociation(FileExtension, ProgID, FileExtensionDescription, args[0]);

这种方法的唯一问题是,如果您的文件关联直接执行您的 .exe 文件,则 ClickOnce 自动更新将无法工作,因为更新信息存储在“开始”菜单快捷方式中,而不是安装的应用程序文件中。
这是一个与您所问的问题不同的问题,但为了解决这个问题,如果应用程序使用 .exe 直接启动,我会以编程方式定位到 ClickOnce 应用程序的“开始”菜单快捷方式(.appref-ms 扩展名),然后使用该路径重新启动应用程序(而不是 .exe),传递原始命令行参数发送到您的 .exe,然后当它重新启动时,我使用 AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData 检索那些参数。

有没有想法如何添加一个图标关联呢? - Tronald

1
当我们增加版本号并将应用程序发布到不同的子文件夹下时,就会发生这种情况。例如:
  • 版本1.0发布到\\server\product\version 1.0\
  • 版本2.0发布到\\server\product\version 2.0\
我按照@EvAlex的答案操作,弹出了一个对话框,然后点击“详细信息”按钮,打开了一个日志文件。在日志文件中,我发现程序试图从旧版本的路径下载,它正在搜索的路径仍然是\\server\product\version 1.0\
然后我意识到问题可能出现在注册表中。
我打开了regedit,并搜索了一下product(我的产品名称),在以下几个键下找到了日志错误所抱怨的路径:
  • HKEY_CURRENT_USER\Software\Classes.myext
  • HKEY_CURRENT_USER\Software\Classes\MyProgId
  • HKEY_CLASSES_ROOT\MyProgId
我删除了那些键,然后重复执行 "打开方式" 操作,图标出现了,然后它就可以正常工作了。
所以看起来这个应用程序没有被完全卸载或者ClickOnce更新这些键时出现了一些未知的错误。

0

ClickOnce不是通过通常的方式传递命令行参数,而是通过

AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData

因此,在您的应用程序启动时,您需要检查它是否包含任何字符串,并相应地修改启动行为。

这是因为ClickOnce应用程序是通过服务器上的部署清单启动的,而不是通过.exe文件启动。顺便说一下:通过属性 -> 发布 -> 选项 -> 文件关联设置您的文件关联应该可以正常工作。

编辑:(我如何创建我的示例应用程序)

  • 创建Windows窗体应用程序
  • 激活ClickOnce安全设置,选择完全信任的应用程序
  • 在ClickOnce选项 -> 描述中,设置发布者、套件和产品名称
  • 在ClickOnce选项 -> 文件关联中添加一个新扩展名
  • 发布应用程序,安装应用程序,测试是否在打开文件时启动(它会)

所有未提及的设置都没有被触及...这就是我所做的一切!

看起来这正是您所做的——也许尝试创建一个简单的测试应用程序,看看是否适用于您。由于这个答案并没有真正回答您的问题,请告诉我何时完成,以便我可以删除它。


1
我不明白这如何有帮助。我感谢你的回答,但正如我所说,属性 -> 发布 -> 选项 -> 文件关联并不能解决问题。我也确实处理了通过AppDomain传递的数据,这不应该(也没有)改变任何东西。 - Kevin Wang
好的,我在发布这篇文章之前创建了一个测试应用程序。只是一个Windows窗体应用程序,应用了您选择的ClickOnce设置(脱机、受信任的应用程序,并通过选项设置文件关联),然后添加了上面的代码。对我来说它很有效。你说得对,不需要获取命令行——我混淆了这个,因为我过去的项目确实需要它。尽管如此,我的简单测试项目(按照描述)及其文件关联确实有效。我会再试一次并创建一个项目,稍后让您知道我到底做了什么。 - Sascha Hennig
我的应用程序按照这些步骤进行,但是对我来说它不起作用。这非常奇怪,不是吗? - Kevin Wang

0

我发现Alan上面的帖子非常有帮助。它在我的一台电脑上按照原样运行得很好,但是在另一台电脑上并没有完全解决我的问题。我希望添加一个评论到他的帖子中,但是Stack Overflow说我没有足够的声望点数。

如果你需要的话,希望你仍然可以在这里找到它。

我还不得不删除每个扩展映射的以下关键字:

HKEY_CLASSES_ROOT\AppName.FileType.0

在Adam删除了其他.ext键后,将此代码添加到我的另一台机器上解决了问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接