1

C#.NET4.0プロジェクトの1か所で値を変更できるようにしたい。このために、Properties/Settings.settings基本的にXMLファイルである組み込みファイルを使用します。

ソフトウェアにInnoSetup(これはかなり一般的です)を使用しており、ファイルはC#.NETアプリケーションの値を格納するデフォルトの方法であるため、InnoSetupスクリプトがから値をプルする方法settings.settingsがあるかどうか疑問に思いました。設定ファイル、またはセットアップスクリプトの変数を設定するためにこれを行うことができるスクリプトを私に指摘できれば。

編集:

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;

この関数は、次のようにInnoSetupPrecompilerを使用して呼び出します。

#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を使用して立ち往生しています。どんな助けでも大歓迎です。

4

1 に答える 1

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

これらは#include "constants.iss"、最初にセットアップスクリプトに含めるプレーンテキストとしてconstants.issファイルにあります。これは、コード呼び出しによって呼び出されるデルファイコードです。

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;
  • DelphiでXMLノードを数えるには不器用なので、ループは100回の実行に制限されています。
  • InnoSetupプリプロセッサをインストールする必要があります。
  • Innoはパス名の定数を受け入れていないようです。そのため、一部の値をProperties/Settings.settingsファイルから取得できませんでした。
  • プリプロセッサが実際にDelphiコードを使用して正しい値をフェッチし、スクリプトに含めるのではなく、定数が使用されるすべての場所に完全なdelphiコード呼び出しが含まれていることを知りませんでした。もちろん、これは私がやりたかったことではありません。たとえば、コードがパスに埋め込まれている場合でも機能しないためです。そのため、セットアップスクリプトを変更して、findとreplaceで置き換える必要のある定数を1つだけ含めるようにしました。これは、パス名や実行可能ファイル名などに使用されます。
  • 残りの部分については、セットアップがハドソンでコンパイルされる前にハドソンで実行するために、基本的にデルファイコードと同じことを行う.NETコマンドラインアプリケーションを作成しました。これにより、コード呼び出しが必要な実際の値に置き換えられます(ただし、要点を理解する必要があります)。

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

これは、設定ファイルで値を設定できることを意味します。この値は、特別なビルド用にhudsonのさらに別のコマンドラインアプリケーションで変更でき、セットアップスクリプトに自動的に書き込まれます。

編集:設定ファイルからapp.configに設定を手動で転送するのはVisual Studio Designerであり、ビルド中に出力でProgramName.exe.configファイルに変更されることに気づきました。したがって、効果を得るには、そこで値を変更する必要があります。ファイルへの正しいパスを指定すると、coeが機能するはずです。

EDIT2:このapp.configは、コンパイル中にYourAppName.exe.configに名前が変更されます...セットアップ内に配置しない場合、値は正しく初期化されません。コードを拡張して、Settings.designer.csファイルのデザイナーコードをXMLの値に適合させましたが、これでうまくいくと思います。それらすべてを支配する1つの構成ファイル:-)

于 2011-12-08T06:06:58.937 に答える