Как настроить приложение независимо от пути .exe?

Предположим, что я хочу перенести приложение из c:\myapp.exe в d:\myapp.exe. Он отключит все настройки. Как это предотвратить?

Ответ 1

Лично я использую реестр для сохранения и загрузки моих настроек, поэтому местоположение моего приложения не затрагивается, но если вы используете User.Config и т.д. и хотите исправить местоположение, это может помочь: Могу ли я контролировать расположение пользовательских настроек .NET, чтобы избежать потери настроек при обновлении приложений?

Ответ 2

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

Он делает это, сохраняя файл в каталоге AppData с хешированным именем. Хэш вычисляется из нескольких свойств приложения. Он захватывает как можно больше, начиная с атрибутов в файле AssemblyInfo.cs. В частности, проблема [AssemblyVersion] заключается в том, как можно обнаружить, что новая версия вашего приложения может быть несовместима со старой версией файла user.config.

Но атрибутов недостаточно, чтобы сделать его уникальным, он также использует полное имя пути .exe в хэше. Это очень сильный селектор для соответствующего файла .config.

Итак, неизбежно, если вы переместите файл .exe где-то в другом месте, это изменит хэш, и это приведет к тому, что вы получите пустой файл user.config со всеми настройками до их значения по умолчанию.

Немного сомневаюсь, что для этого нужно иметь один установочный каталог. c:\program files\companyname\appname является стандартом. Но вы можете реализовать свой собственный класс SettingsProvider. Это не совсем легко сделать, System.Configuration - довольно неприятное пространство имен. Но достойной отправной точкой является образец реестра RegistrySettingsProvider, который, вероятно, можно использовать как есть.

  •  -

Ответ 3

Это зависит от приложения на 100%.

Приложение само по себе просто должно найти его зависимости или список DLL, который он требует для запуска. Он будет выглядеть в текущем каталоге в течение этого времени, поэтому это обычно не проблема.

Самая большая проблема в реестре. Если приложение написало, где оно было установлено в реестр, оно может искать определенные файлы в старом каталоге во время выполнения.

Если вы установили приложение, оно также сохраняется в реестре, и удаление из программы "Установка и удаление программ" больше не будет работать.

Если приложение не использует реестр, его можно перемещать без последствий. Многие портативные приложения, которые запускают флеш-накопители, используют этот подход и, как результат, могут быть перемещены или удалены по мере необходимости...

Надеюсь, что это поможет вашей причине..:)

Ответ 4

Создайте отдельную dll, чтобы прочитать настройки с помощью любого метода, который вы предпочитаете: чтение реестра или xml,... и поместите его в системный путь. Затем вы можете вызвать dll в любом месте вашего exe.

Но при каких обстоятельствах вам нужно это требование? Мне просто интересно.

Ответ 5

Вы можете создать свой собственный класс настроек. Который работает так же, как оригинал. Ниже я отправляю свою реализацию класса Settings. Любые улучшения будут высоко оценены.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using Microsoft.Win32;

namespace MyNamespace
{
    static class Settings
    {
        private static string _connectionString = @"data source=C:\\database.s3db";

        public static string ConnectionString
        {
            get { return GetSetting("_connectionString"); }
            set { _connectionString = value; }
        }

        private static string _archives = "";

        public static string Archives
        {
            get { return GetSetting("_archives"); }
            set { _archives = value; }
        }

        public static bool CheckDuplicates
        {
            get { return bool.Parse(GetSetting("_checkDuplicates")); }
            set { _checkDuplicates = value; }
        }

        private static bool _saveDocks = true;

        public static bool SaveDocks
        {
            get { return bool.Parse(GetSetting("_saveDocks")); }
            set { _saveDocks = value; }
        }

        private static Font _font = new Font("Tahoma", 12, GraphicsUnit.Pixel);

        public static Font Font
        {
            get
            {
                var convert = new FontConverter();
                var value = convert.ConvertFromString(GetSetting("_font"));
                return (Font) value;
            }
            set { _font = value; }
        }

        public static void Save()
        {
            Type type = typeof(Settings);

            var registryKey = Registry.CurrentUser.CreateSubKey(string.Format(@"Software\{0}\{1}\Settings", Application.CompanyName, Application.ProductName));
            if (registryKey != null)
            {
                foreach (var field in type.GetFields(BindingFlags.NonPublic | BindingFlags.Static))
                {
                    var converter = TypeDescriptor.GetConverter(field.FieldType);
                    var value = converter.ConvertToString(field.GetValue(null));
                    registryKey.SetValue(field.Name, value ?? field.GetValue(null));
                }
                registryKey.Close();
            }
        }

        public static void SetDefaults()
        {
            var registryKey = Registry.CurrentUser.OpenSubKey(string.Format(@"Software\{0}\{1}\Settings", Application.CompanyName, Application.ProductName));
            if (registryKey == null)
            {
                Save();
            }
            else
            {
                registryKey = Registry.CurrentUser.CreateSubKey(string.Format(@"Software\{0}\{1}\Settings", Application.CompanyName, Application.ProductName));
                if(registryKey == null) return;
                Type type = typeof(Settings);
                foreach (var field in type.GetFields(BindingFlags.NonPublic | BindingFlags.Static))
                {
                    if (registryKey.GetValue(field.Name) != null)
                    {
                        var converter = TypeDescriptor.GetConverter(field.FieldType);
                        var value = converter.ConvertFrom(registryKey.GetValue(field.Name, field.GetValue(null)));
                        field.SetValue(null, value);
                    }
                }
                registryKey.Close();
            }
        }

        private static string GetSetting(string name)
        {
            var registryKey = Registry.CurrentUser.OpenSubKey(string.Format(@"Software\{0}\{1}\Settings", Application.CompanyName, Application.ProductName));
            if (registryKey != null)
            {
                if (registryKey.GetValue(name) != null)
                {
                    return registryKey.GetValue(name).ToString();
                }
                registryKey.Close();
            }
            return "";
        }
    }
}

Чтобы использовать это приложение, просто добавьте свойства и поля поддержки для своих настроек, как указано выше. Убедитесь, что вы используете имя поля поддержки как строковый аргумент метода GetSetting в свойстве get accessor. Обязательно укажите значения по умолчанию для полей настроек.

Для сохранения настроек см. ниже код.

    Settings.Archives = ".7z,.rar,.zip";
    Settings.CheckDuplicates = true;
    Settings.SaveDocks = false;
    Settings.Font = fontDialog.Font;
    Settings.Save();

Вы должны вызвать метод SetDefaults в своем конструкторе основной формы. См. Ниже код.

namespace MyNamespace
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
            Settings.SetDefaults();
        }
    }
}

Если у вас есть предложения по улучшению этого класса. Затем прокомментируйте.