Предположим, что я хочу перенести приложение из c:\myapp.exe в d:\myapp.exe. Он отключит все настройки. Как это предотвратить?
Как настроить приложение независимо от пути .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();
}
}
}
Если у вас есть предложения по улучшению этого класса. Затем прокомментируйте.