Открытый тип файла (xml) с помощью приложения clickonce

У меня есть приложение clickonce, которое доступно в автономном режиме и в Интернете. Он используется для открытия и редактирования файлов .xml. Он может открывать файлы .xml, если их путь указан в качестве аргумента запуска, например

"c:Path\Name.appref-ms" "Xmlpath\name.xml"

с помощью окна консоли.

Теперь я хочу добавить запись в реестр, поэтому я могу щелкнуть правой кнопкой мыши любой .xml и найти свое приложение в разделе открыть с помощью. Я добавил ключ в HKCR\.xml\OpenWithProgids и ключ HKCR\myapp.xml\shell\open\command, но не могу понять, как сделать эту команду . Насколько я понимаю, команда должна быть такой же, как та, которую я могу использовать в окне консоли, поэтому я попытался

"c:Path\Name.appref-ms" "%1"

Это, похоже, не работает, я также пробовал много разных способов использования кавычек, но всегда получаю

name.xml is not a valid win 32 application

как сообщение об ошибке. Кто-нибудь знает, возможно ли то, что я хочу сделать, и как это сделать?


Дополнительная информация:
- если я использую исполняемый файл, он работает, просто не могу сделать это с помощью кнопки clickonce.

- приложение использует такой аргумент:

if(AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData!=null)
{ 
    //Do something 
}

person Pasoe    schedule 19.05.2014    source источник
comment
Я решил эту проблему в одном из моих частных приложений. Если вы не хотите терять время и можете подождать, пока я вернусь домой - примерно через 90 минут - я опубликую для вас рабочий ответ :)   -  person Herdo    schedule 19.05.2014
comment
@Herdo, спасибо, не торопитесь, ваша помощь очень ценна :)   -  person Pasoe    schedule 19.05.2014
comment
Без проблем. Только один вопрос: "executable file it works" — вы имеете в виду зарегистрированный тип файла, связанный с приложением ClickOnce?   -  person Herdo    schedule 19.05.2014
comment
исполняемый файл, как в myapp.exe   -  person Pasoe    schedule 19.05.2014


Ответы (1)


Прежде всего, это результат, как может выглядеть расширение оболочки (другие расширения выделены серым цветом): enter image  описание здесь

Вам нужно добавить несколько записей в реестр. Я написал для него вспомогательный класс реестра. Вы можете либо использовать это, либо просто применить ключи. Вам нужно только настроить имена и вызвать метод EnsureRegistryKeyIntegrity(). Примечание. Я добавил переключатель конфигурации, чтобы включить или отключить функцию расширения оболочки. Это может быть полезно, если вы не хотите сильно взрывать свою оболочку.

Одна важная вещь: вам нужно запустить метод с правами администратора, иначе вы получите исключение.

internal static class RegistryHelper
{
    ////////////////////////////////////////////////
    #region Statics

    /// <summary>
    /// A dictionary of registry roots and their subkeys to handle.
    /// </summary>
    private static readonly Dictionary<RegistryHive, string[]> RegistryKeys = new Dictionary<RegistryHive, string[]>
    {
        {
            RegistryHive.ClassesRoot,
            new []
            {
                @"*\shell\QuickHash",
                @"*\shell\QuickHash\command",
                @"Directory\shell\QuickHash",
                @"Directory\shell\QuickHash\command"
            }
        }
    };

    /// <summary>
    /// The registry default value for the command keys.
    /// </summary>
    private static readonly string RegistryCommandValue;

    #endregion

    ////////////////////////////////////////////////
    #region Constructors

    static RegistryHelper()
    {
        RegistryCommandValue = String.Format("\"{0}\" /file \"%1\"", Assembly.GetExecutingAssembly().Location);
    }

    #endregion

    ////////////////////////////////////////////////
    #region Public Methods

    /// <summary>
    /// Ensures that all required registry keys exist and adjusts their values if required.
    /// </summary>
    public static void EnsureRegistryKeyIntegrity()
    {
        foreach (var registryRoot in RegistryKeys.Keys)
        {
            foreach (var registryKeyName in RegistryKeys[registryRoot])
            {
                if (((App)Application.Current).Config.EnableExplorerContextMenu)
                {
                    var regKey = GetOrAddKey(registryRoot, registryKeyName);
                    AdjustKey(regKey);
                    regKey.Close();
                }
                else
                {
                    DeleteKey(registryRoot, registryKeyName);
                }
            }
        }
    }

    #endregion

    ////////////////////////////////////////////////
    #region Private Methods

    /// <summary>
    /// Gets or adds a specific key for a specific registry root.
    /// </summary>
    /// <param name="registryRoot">The registry root.</param>
    /// <param name="registryKeyName">The registry key.</param>
    /// <returns>Returns the gotten or added registry key.</returns>
    private static RegistryKey GetOrAddKey(RegistryHive registryRoot, string registryKeyName)
    {
        switch (registryRoot)
        {
            case RegistryHive.ClassesRoot:
                return Registry.ClassesRoot.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.ClassesRoot.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            case RegistryHive.CurrentUser:
                return Registry.CurrentUser.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.CurrentUser.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            case RegistryHive.LocalMachine:
                return Registry.LocalMachine.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.LocalMachine.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            case RegistryHive.Users:
                return Registry.Users.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.Users.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            case RegistryHive.PerformanceData:
                return Registry.PerformanceData.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.PerformanceData.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            case RegistryHive.CurrentConfig:
                return Registry.CurrentConfig.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.CurrentConfig.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            case RegistryHive.DynData:
                // DynData is obsolete
                return Registry.PerformanceData.OpenSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue) ??
                       Registry.PerformanceData.CreateSubKey(registryKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree);
            default:
                throw new ArgumentOutOfRangeException("registryRoot");
        }
    }

    /// <summary>
    /// Deletes an unused registry key.
    /// </summary>
    /// <param name="registryRoot">The registry root.</param>
    /// <param name="registryKeyName">The registry key.</param>
    private static void DeleteKey(RegistryHive registryRoot, string registryKeyName)
    {
        const string missingRightsText = "You don't have the permissions to perform this action.";
        const string missingRightsCaption = "Error";
        try
        {
            switch (registryRoot)
            {
                case RegistryHive.ClassesRoot:
                    Registry.ClassesRoot.DeleteSubKeyTree(registryKeyName, false);
                    break;
                case RegistryHive.CurrentUser:
                    Registry.CurrentUser.DeleteSubKeyTree(registryKeyName, false);
                    break;
                case RegistryHive.LocalMachine:
                    Registry.LocalMachine.DeleteSubKeyTree(registryKeyName, false);
                    break;
                case RegistryHive.Users:
                    Registry.Users.DeleteSubKeyTree(registryKeyName, false);
                    break;
                case RegistryHive.PerformanceData:
                    Registry.PerformanceData.DeleteSubKeyTree(registryKeyName, false);
                    break;
                case RegistryHive.CurrentConfig:
                    Registry.CurrentConfig.DeleteSubKeyTree(registryKeyName, false);
                    break;
                case RegistryHive.DynData:
                    // DynData is obsolete
                    Registry.PerformanceData.DeleteSubKeyTree(registryKeyName, false);
                    break;
                default:
                    throw new ArgumentOutOfRangeException("registryRoot");
            }
        }
        catch (SecurityException)
        {
            MessageBox.Show(missingRightsText, missingRightsCaption, MessageBoxButton.OK, MessageBoxImage.Error);
        }
        catch (UnauthorizedAccessException)
        {
            MessageBox.Show(missingRightsText, missingRightsCaption, MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    /// <summary>
    /// Adjusts the registry keys value.
    /// </summary>
    /// <param name="regKey">The registry key to adjust.</param>
    private static void AdjustKey(RegistryKey regKey)
    {
        if (regKey.Name.EndsWith("QuickHash"))
        {
            SetExplorerShellName(regKey);
            SetExplorerShellIcon(regKey);
            return;
        }
        if (regKey.Name.EndsWith("command"))
        {
            var keyDefaultValue = regKey.GetValue("") as String;
            if (String.IsNullOrEmpty(keyDefaultValue)
             || keyDefaultValue != RegistryCommandValue)
            {
                regKey.SetValue(null, RegistryCommandValue, RegistryValueKind.String);
            }
            return;
        }

        throw new NotSupportedException("Given registry key is not supported.");
    }

    private static void SetExplorerShellName(RegistryKey regKey)
    {
        const string quickHashDisplayName = "Quick Hash";
        var keyDefaultValue = regKey.GetValue("") as String;
        if (String.IsNullOrEmpty(keyDefaultValue)
            || keyDefaultValue != quickHashDisplayName)
        {
            regKey.SetValue(null, quickHashDisplayName, RegistryValueKind.String);
        }
    }

    private static void SetExplorerShellIcon(RegistryKey regKey)
    {
        var executingAssembly = (new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath;
        regKey.SetValue("Icon", String.Format("{0},0", executingAssembly));
    }

    #endregion
}
person Herdo    schedule 19.05.2014
comment
Я попробовал ваше решение, но, к сожалению, оно не сработало. Я все еще получаю ту же ошибку. Я думаю, что попробую некоторые варианты вашего подхода, может быть, я смогу что-то понять. Тем не менее, спасибо за ответ. - person Pasoe; 20.05.2014
comment
@Pasoe Не могли бы вы опубликовать запись / записи реестра, сгенерированные кодом? - person Herdo; 20.05.2014
comment
упс, я облажался. Ваше решение сработало, я все еще использовал ActivationData вместо аргументов string[] - person Pasoe; 20.05.2014
comment
Это даже лучше, чем я ожидал :) - person Pasoe; 20.05.2014
comment
@Pasoe Хорошо. Я думаю, что часть /file предназначалась для внутренней обработки. Таким образом, я мог различать запуск файла через ассоциацию файлов ClickOnce и открытие файла через оболочку Windows. Я рад, что это работает :) - person Herdo; 20.05.2014