アプリを c:\myapp.exe から d:\myapp.exe に移動するとします。すべての設定が失われます。それを防ぐ方法は?
5 に答える
LocalFileSettingsProvider クラスの実装の詳細です。これには、ユーザー スコープの設定を一意であることが保証されたファイルに保存するという、うらやましい仕事があり、異なるアプリが誤って互いの設定を上書きすることはありません。
これは、ハッシュされた名前を持つ AppData ディレクトリにファイルを保存することによって行われます。ハッシュは、アプリケーションのいくつかのプロパティから計算されます。AssemblyInfo.cs ファイルの属性から始めて、可能な限り取得します。特に [AssemblyVersion] は重要です。これは、アプリの新しいバージョンが user.config ファイルの古いバージョンと互換性がない可能性があることを検出する方法です。
ただし、属性は一意にするのに十分ではなく、ハッシュで .exe のフル パス名も使用します。これは、適切な .config ファイルの非常に強力なセレクターです。
したがって、必然的に、.exe を別の場所に移動すると、ハッシュが変更され、すべての設定がデフォルト設定に戻された空の user.config ファイルが作成されます。
これをいじるのは少し疑問です。アプリにはインストール ディレクトリが 1 つしかないはずです。c:\program files\companyname\appname が標準です。ただし、独自の SettingsProvider クラスを実装することで可能です。それを行うのは簡単ではありません.System.Configurationはかなり厄介な名前空間です。しかし、適切な出発点は、おそらくそのまま使用できるRegistrySettingsProvider sampleです。
-
-
個人的にはレジストリを使用して設定を保存およびロードするため、アプリケーションの場所は影響を受けませんが、User.Config などを使用していて場所を修正したい場合は、これが役立つ場合があります: Can I control the location ofアプリケーションのアップグレード時に設定が失われないようにするための.NETユーザー設定?
独自の設定クラスを作成できます。これはオリジナルと同じように機能します。以下に、設定クラスの実装を投稿しています。改善点は大歓迎です。
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 "";
}
}
}
アプリケーションでこれを使用するには、上記のように設定のプロパティとバッキング フィールドを追加するだけです。プロパティの get アクセサーの GetSetting メソッドで、バッキング フィールドの名前を文字列引数として使用していることを確認してください。設定フィールドには必ずデフォルト値を割り当ててください。
設定を保存するには、以下のコードを参照してください。
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();
}
}
}
このクラスを改善するための提案があれば。それからコメント。
これは、アプリケーションに 100% 依存します。
アプリケーション自体は、その依存関係、または実行に必要な DLL のリストを見つけるだけで済みます。ほとんどの場合、これらは現在のディレクトリで検索されるため、通常は問題になりません。
最大の問題はレジストリにあります。アプリケーションがインストールされた場所をレジストリに書き込んでいる場合、実行時に古いディレクトリで特定のファイルを探すことがあります。
アプリケーションをインストールした場合、これもレジストリに保存され、[プログラムの追加と削除] からのアンインストールは機能しなくなります。
ただし、アプリケーションがレジストリを使用しない場合は、問題なく移動できます。フラッシュ ドライブで実行される多くのポータブル アプリはこのアプローチを採用しており、その結果、必要に応じて移動または削除できます...
それがあなたの大義に役立つことを願っています.. :)
別のdllを作成して、レジストリまたはxmlの読み取りなど、任意の方法で設定を読み取り、システムパスに配置します。次に、exeファイルがどこにあってもdllを呼び出すことができます。
しかし、どのような状況でこの要件が必要ですか?ただ疑問に思います。