В VS2008 и .NET Framework 3.5 вы не можете создать манифест, необходимый для изменения app.config, если приложение установлено в подпапке% ProgramFiles% или% ProgramFiles (x86)%, поскольку они специально защищены ОС, и вы не можете записать в HKLM-узел реестра, не будучи повышенным процессом.
Я думаю, что я бы закодировал значение по умолчанию и логическое значение, указывающее, работает ли приложение в переносном режиме, в app.config. Считайте значение по умолчанию из app.config, перезаписайте переменную значением из user.config (если оно существует) и запишите значение в user.config, если в переносном режиме, и в app.config, если в непереносимом режиме.
В пользовательских классах, независимо от того, какая плохая поддержка исходит от фреймворка (нет доступа на запись в app.config, нет гибридного режима) ...
app.config:
<? Xml version = "1.0" encoding = "utf-8"?>
<добавить
key = "PortableMode" value = "Off" />
<добавить
key = "SomethingPath" value = "Программное обеспечение \ Cragin \ FooApp \ SomethingPath" />
Я думаю, что это больше, чем 250 строк кода, а не 2, но это помогает (извините, это на C #, но вы, вероятно, знаете, как адаптировать его к C ++).
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Linq;
namespace DesktopApp1 {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Config myConfig = new Config();
myConfig.Load();
//Change settings during the livetime of the application
myConfig.SomethingPath = @"C:\Temp\Foo\TestUser.dat";
myConfig.PortableMode = false;
//Write it when closing the application
myConfig.Save();
}
}
internal class Config {
//Private Fields
private AppOrUserConfig _Config;
private Boolean _IsUserConfig;
private String _AppConfigPath;
private String _UserConfigPath;
public void Load() {
AppOrUserConfig myDefaultConfig = new AppOrUserConfig();
AppOrUserConfig myAppConfig = new AppOrUserConfig(AppConfigPath, myDefaultConfig);
if (myAppConfig.PortableMode) {
_Config = myAppConfig;
_IsUserConfig = false;
} else {
_Config = new AppOrUserConfig(UserConfigPath, myAppConfig);
_IsUserConfig = true;
}
}
public Boolean Save() {
CheckLoad();
String myFilePath = IsUserConfig ? UserConfigPath : AppConfigPath;
try {
String myContent = _Config.XmlContent;
String myFolder = Path.GetDirectoryName(myFilePath);
Directory.CreateDirectory(myFolder);
File.Delete(myFilePath);
File.WriteAllText(myFilePath, myContent, new UTF8Encoding(true));
return true;
} catch {
}
return false;
}
public Boolean PortableMode {
get {
CheckLoad();
return _Config.PortableMode;
}
set {
CheckLoad();
if (PortableMode == value) return;
if (value) {
_Config.PortableMode = true;
_IsUserConfig = false;
Save();
} else {
String myPath = SomethingPath;
_Config.PortableMode = false;
Save();
Load();
SomethingPath = myPath;
}
}
}
public String SomethingPath {
get {
CheckLoad();
return _Config.SomethingPath;
}
set {
CheckLoad();
_Config.SomethingPath = value;
}
}
private String AppConfigPath {
get {
String myResult = _AppConfigPath;
if (myResult == null) {
myResult = Assembly.GetEntryAssembly().EntryPoint.DeclaringType.Module.FullyQualifiedName + ".config";
_AppConfigPath = myResult;
}
return myResult;
}
}
private String UserConfigPath {
get {
String myResult = _UserConfigPath;
if (myResult == null) {
myResult = Path.Combine(Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Cragin\FooApp"), Path.GetFileName(AppConfigPath));
_UserConfigPath = myResult;
}
return myResult;
}
}
private Boolean IsUserConfig {
get {
return _IsUserConfig;
}
}
private void CheckLoad() {
if (_Config == null) throw new InvalidOperationException(@"Call method ""Load()"" first.");
}
}
internal class AppOrUserConfig {
//Private Fields
private XDocument _Xml;
//Constructors
public AppOrUserConfig() {
_Xml = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
<startup>
<supportedRuntime version=""v2.0.50727""/>
</startup>
<appSettings>
<add key=""PortableMode"" value=""Off""/>
<add key=""SomethingPath"" value=""C:\ProgramData\Cragin\SomeLibrary""/>
</appSettings>
</configuration>");
}
public AppOrUserConfig(String filePath, AppOrUserConfig defaultValue) : this() {
XDocument myXml = null;
try {
myXml = XDocument.Parse(File.ReadAllText(filePath));
} catch {
return;
}
AppOrUserConfig myDummy = new AppOrUserConfig(myXml, defaultValue);
PortableMode = myDummy.PortableMode;
SomethingPath = myDummy.SomethingPath;
}
public AppOrUserConfig(XDocument xml, AppOrUserConfig defaultValue) : this() {
if (defaultValue == null) defaultValue = new AppOrUserConfig();
if (xml == null) {
PortableMode = defaultValue.PortableMode;
SomethingPath = defaultValue.SomethingPath;
return;
}
AppOrUserConfig myDummy = new AppOrUserConfig();
myDummy._Xml = xml;
PortableMode = myDummy.GetPortableMode(defaultValue.PortableMode);
SomethingPath = myDummy.GetSomethingPath(defaultValue.SomethingPath);
}
public Boolean PortableMode {
get {
return GetPortableMode(false);
}
set {
(from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "PortableMode" select e).Last().Attribute("value").Value = value ? "on" : "off";
}
}
public String SomethingPath {
get {
return GetSomethingPath(@"C:\ProgramData\Cragin\SomeLibrary");
}
set {
(from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "SomethingPath" select e).Last().Attribute("value").Value = value ?? "";
}
}
public String XmlContent {
get {
return _Xml.ToString(SaveOptions.None);
}
}
private Boolean GetPortableMode(Boolean defaultValue) {
try {
String myString = (from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "PortableMode" select e).Last().Attribute("value").Value;
return ToBoolean(myString);
} catch {
PortableMode = defaultValue;
return defaultValue;
}
}
private String GetSomethingPath(String defaultValue) {
try {
return (from e in _Xml.Element("configuration").Element("appSettings").Elements("add") where (string)e.Attribute("key") == "SomethingPath" select e).Last().Attribute("value").Value;
} catch {
SomethingPath = defaultValue;
return defaultValue;
}
}
private static Boolean ToBoolean(String value) {
value = value.Trim();
switch (value.Length) {
case 1:
if (value[0] == '0') return false;
if (value[0] == '1') return true;
break;
case 5:
if (value.ToLowerInvariant() == "false") return false;
break;
case 4:
if (value.ToLowerInvariant() == "true") return true;
break;
case 3:
if (value.ToLowerInvariant() == "off") return false;
break;
case 2:
if (value.ToLowerInvariant() == "on") return true;
break;
}
throw new FormatException();
}
}
}
Надеюсь, это пригодится вам или кому-то еще.