我希望能够在C#.NET 4.0项目中的某个位置更改值。为此,我使用内置的Properties/Settings.settings
文件,该文件本质上是一个XML文件。
由于我们正在使用InnoSetup(这是很常见的)我们的软件,并且settings.settings
文件是存储C#.NET应用程序值的默认方式,我想知道是否有 InnoSetup脚本从设置文件中提取值的方法,或者如果您可以指向一个可以执行此操作的脚本来设置安装脚本的变量。
修改
我运行了XML示例,但现在我无法使用XPath查询来获取正确的节点。这是我的剧本:
[Code]
{--- MSXML ---}
const
XMLFileName = '..\CCFinderWPF\Properties\Settings.settings';
XMLFileName2 = '..\CCFinderWPF\Properties\Settings.xml';
function Settings(Default: String): String;
var
XMLDoc, SeekedTopNode, SeekedNode, iNode, Sel: Variant;
Path, XPath: String;
begin
{ Load the XML File }
try
XMLDoc := CreateOleObject('MSXML2.DOMDocument.4.0');
except
RaiseException('Please install MSXML first.'#13#13'(Error ''' + GetExceptionMessage + ''' occurred)');
end;
XMLDoc.async := False;
XMLDoc.resolveExternals := false;
XMLDoc.preserveWhiteSpace := true;
XMLDoc.setProperty('SelectionLanguage', 'XPath');
XMLDoc.load(XMLFileName);
if XMLDoc.parseError.errorCode <> 0 then
RaiseException('Error on line ' + IntToStr(XMLDoc.parseError.line) + ', position ' + IntToStr(XMLDoc.parseError.linepos) + ': ' + XMLDoc.parseError.reason);
MsgBox('XML-File: ' + XMLFileName, mbInformation, MB_OK);
{ Modify the XML document }
iNode := XMLDoc.documentElement;
iNode := iNode.selectSingleNode('Setting[@Name="' + Default + '"]');
// **selectSingleNode returns null, seems that selectSingleNode with XPath doesn't work?**
MsgBox('The Node is: ' + iNode.nodeName, mbInformation, MB_OK);
SeekedNode := iNode.firstChild;
Result := SeekedNode.lastChild.text;
MsgBox('The XPath is: ' + XPath, mbInformation, MB_OK);
end;
我使用Inno Setup预编译器调用此函数,如下所示:
#define ABAppName "{code:Settings|AppName}"
XML文件如下所示:
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="CCFinder.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="AppName" Type="System.String" Scope="Application">
<Value Profile="(Default)">CCFinder</Value>
</Setting>
...
所有这一切的目标是我可以在我的应用程序中设置我的C#项目中的Settings.settings文件中的值,让我的hudson实例检查我的代码并更改此XML文件以用于不同版本的应用程序,例如更改我在设计时不必知道的一些价值观。我希望能够从这个XML文件中提取变量。我刚刚在这里使用MSXML2。任何帮助将不胜感激。
答案 0 :(得分:0)
没人知道解决方案,所以我用while循环解决了这个问题。请注意,这是我的第一个Delphi代码,因此它可能不优雅和/或100%正确。这就是我定义所需常量的方法:
#define ABAppName "{code:Settings|AppName}"
#define ABAppVersion "{code:Settings|AppVersion}"
#define ABCompany "{code:Settings|CompanyName}"
#define ABAppTitle "{code:Settings|ApplicationTitle}"
#define ABAppTitlePro "{code:Settings|ApplicationTitle)}"+" "+"{code:Settings|ProVersionAppender}"
#define ABCompanyUrl "{code:Settings|CompanyUrl_de}"
#define ABContactEmailDe "{code:Settings|ContactEmail_de}"
#define ABYear "{code:Settings|Year}"
这些是在constants.iss文件中作为纯文本,我在开始时使用#include "constants.iss"
包含在我的安装脚本中。这是代码调用调用的delphi代码:
const
XMLFileName = '..\CCFinder\Properties\Settings.settings';
function Settings(Default: String): String;
var
XMLDoc, iNode: Variant;
Path: String;
i : Integer;
Loop : Boolean;
begin
{ Load the XML File }
try
XMLDoc := CreateOleObject('MSXML2.DOMDocument.6.0');
except
RaiseException('Please install MSXML first.'#13#13'(Error ''' + GetExceptionMessage + ''' occurred)');
end;
try
XMLDoc.async := False;
XMLDoc.resolveExternals := false;
XMLDoc.load(XMLFileName);
if XMLDoc.parseError.errorCode <> 0 then
RaiseException('Error on line ' + IntToStr(XMLDoc.parseError.line) + ', position ' + IntToStr(XMLDoc.parseError.linepos) + ': ' + XMLDoc.parseError.reason);
iNode := XMLDoc.DocumentElement;
iNode := iNode.LastChild;
Loop := True;
i := 0;
while Loop do
begin
Try
if iNode.ChildNodes[i].attributes[0].nodeValue = Default
then
begin
Result := iNode.ChildNodes[i].text;
// MsgBox('Result for Default: ' + Result + Default, mbInformation, MB_OK);
i := i+1;
Loop := False;
Break;
end
else
begin
i := i+1;
if i = 100 then Loop := false;
end;
except
Result := '';
end;
end;
except
end;
end;
对于其他人,我编写了一个.NET命令行应用程序,它与delphi代码基本相同,在Hudson上编译安装程序之前在Hudson中执行它。这将代码调用替换为所需的实际值(仅限于此,但您应该得到这一点):
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(pathToSettingsFile);
XmlNodeList list = xmldoc.GetElementsByTagName("Setting");
foreach (XmlNode node in list)
{
string keystring = node.Attributes["Name"].InnerText;
string valuestring = node.FirstChild.InnerText;
settingValues.Add(keystring,valuestring);
}
var t = File.OpenText(constantsfilename);
string text;
using (t)
{
text = t.ReadToEnd();
}
string sample = "{code:Settings|";
char endsign = '}';
while (text.Contains(sample))
{
int startindex = text.IndexOf(sample);
int endindex = text.IndexOf(endsign, startindex);
int variableIndex = startindex + sample.Length;
string variable = text.Substring(variableIndex, endindex - variableIndex);
text = text.Replace(sample + variable + endsign, newVal(variable));
}
var w = new StreamWriter(constantsfilename);
using (w)
{
w.Write(text);
w.Flush();
}
}
public static string newVal(string variable)
{
if (settingValues.ContainsKey(variable))
return settingValues[variable];
else
{
return "";
}
}
这意味着我现在可以在我的Settings-File中设置值,可以使用hudson中的另一个命令行应用程序更改特殊构建,并自动写入安装脚本。
编辑:刚才意识到Visual Studio Designer会将设置从settings-file手动传输到app.config,在构建时会在输出中更改为ProgramName.exe.config文件。因此,您需要更改其中的值以使其具有效果,如果您为文件指定正确的路径,则coe应该起作用。
EDIT2:这个app.config在编译到YourAppName.exe.config期间被重命名...当你没有把它放在设置中时,值没有正确初始化。我扩展了我的代码,以便使用XML中的值调整Settings.designer.cs文件的设计器代码,并猜测这样做。一个配置文件来统治它们: - )