How to make application settings independent of .exe path?
Asked Answered
C

5

4

Suppose I want to move my app from c:\myapp.exe to d:\myapp.exe. It will loose all settings. How to prevent that?

Cleora answered 18/8, 2012 at 7:56 Comment(4)
This ones msdn.microsoft.com/en-us/library/8eyb2ct1%28v=vs.100%29.aspxCleora
It's the ProjectProperties -> SettingsCleora
Why would you loose these settings then if they are persisted in app.exe.config which you move together with your executable?Copyboy
@WiktorZychla because they are marked as user settings to allow editing through GUI.Cleora
W
4

Personally I use the registry to save and load my settings, so the location of my application isn't affected, but if you're using User.Config etc and want to fix the location, this might help: Can I control the location of .NET user settings to avoid losing settings on application upgrade?

Wireman answered 18/8, 2012 at 8:2 Comment(1)
surfbutler is absolutely right. Using registry to save your settings is good idea. You can save settings for current user as well as local machine using this technique.Corroboree
B
4

It is an implementation detail of the LocalFileSettingsProvider class. Which has the unenviable job of storing user-scoped settings in a file that's guaranteed to be unique so that different apps cannot accidentally overwrite each others settings.

It does so by storing the file in an AppData directory that has a hashed name. The hash is computed from several properties of the application. It grabs as much as it can, starting with the attributes in the AssemblyInfo.cs file. Particularly the [AssemblyVersion] matters which is how it can detect that a new version of your app might not be compatible with the old version of the user.config file.

But the attributes are not enough to make it unique, it also uses the full path name of the .exe in the hash. Which is a very strong selector for the appropriate .config file.

So, inevitably, if you move the .exe somewhere else, that's going to change the hash and that's going to get you an empty user.config file with all the settings back to their default setting.

It's a bit questionable to tinker with this, an app should only ever have one install directory. c:\program files\companyname\appname is the standard. But you can by implementing your own SettingsProvider class. That's not exactly easy to do, System.Configuration is a pretty nasty namespace. But a decent starting point is the RegistrySettingsProvider sample, which is probably usable as-is.

    -
Broca answered 18/8, 2012 at 13:2 Comment(0)
L
1

This depends 100% on the application.

An application by itself just needs to find it's dependencies, or the list of DLLs it requires to run. It'll look in the current directory for these most of the time, so this usually isn't an issue.

The largest issue is in the registry. If the application has written where it was installed to the registry, it may look for certain files in the old directory at runtime.

If you installed the application, this is also stored in the registry, and uninstalling from Add/Remove programs will no longer work.

If the application does not use the registry though, it can be moved without consequence. Many portable apps which run off flash drives take this approach, and as a result can be moved or deleted as needed...

Hope It Helps Your Cause..:)

Lacombe answered 18/8, 2012 at 13:51 Comment(0)
C
1

You can create your own Settings class. Which works just like the original. Below I'm posting my implementation of Settings class. Any improvements will be greatly appreciated.

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 "";
        }
    }
}

To use this with your application just add properties and backing field for your settings just like above. Make sure you use backing field's name as string argument in GetSetting method in property's get accessor. Make sure you assign default values to settings fields.

For saving settings see below code.

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

You must call SetDefaults method in your constructor of a main form. See below code.

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

If you have suggestion for improving this class. Then comment.

Corroboree answered 26/8, 2012 at 5:43 Comment(0)
V
0

Make a separate dll to read the settings via whatever method you prefer - registry or xml reading, ... and put it in system path. Then you can call dll anywhere your exe is.

But under what circumstance do you need this requirement? I just wonder.

Voice answered 18/8, 2012 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.