Использовать значения Project / Properties / Settings.settings в скрипте InnoSetup? - PullRequest
1 голос
/ 24 ноября 2011

Я хочу иметь возможность изменить значение в одном месте в моем C # .NET 4.0 Project. Для этого я использую встроенный файл Properties/Settings.settings, который по сути является файлом XML.

Поскольку мы используем InnoSetup (что довольно распространено) для нашего программного обеспечения, а файл settings.settings является способом хранения значений по умолчанию для приложения C # .NET, я подумал, существует ли способ для сценария InnoSetup, чтобы получить значения из файла настроек , или если вы могли бы указать мне сценарий, который мог бы сделать это для установки переменных сценария установки.

EDIT:

Я запустил пример 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>
    ...

Цель всего этого заключается в том, чтобы я мог устанавливать значения в своем приложении из файла Settings.settings в моих проектах на C #, иметь мой экземпляр hudson, проверять мой код и изменять этот XML-файл для различных версий приложения и, например, изменять некоторые значения, которые мне не нужны, во время разработки. Я хочу быть в состоянии извлечь мои переменные из этого файла XML. Я просто застрял с использованием MSXML2 здесь. Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 08 декабря 2011

Никто не знал решения, поэтому я решил это с помощью цикла 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;
  • Цикл ограничен 100 запусками, потому что я слишком неуклюж, чтобы считать узлы XML в Delphi.
  • Необходимо установить препроцессор InnoSetup.
  • Inno, похоже, не принимает константы в именах путей, поэтому некоторые значения просто не могут быть извлечены из файла Properties / Settings.settings.
  • Я не знал, что препроцессор на самом деле не использует код Delphi для извлечения правильных значений для включения их в сценарий, вместо этого он включает полный вызов кода Delphi во всех местах, где используется константа. Конечно, это не то, что я хотел сделать, так как он даже не работает, когда код встроен, например, в пути. Поэтому я изменил сценарий установки так, чтобы он включал только одну константу, которую мне нужно было заменить поиском и заменой, и которая используется, например, для имен путей и исполняемого имени файла.
  • В остальном я написал приложение командной строки .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 "";
        }
    }
    

Это означает, что теперь я могу устанавливать значения в своем файле настроек, которые можно изменить с помощью еще одного приложения командной строки в hudson для специальных сборок, и автоматически записывается в сценарий установки.

РЕДАКТИРОВАТЬ: только что понял, что это Visual Studio Designer, который вручную передает настройки из файла настроек в app.config, который изменяется в файле ProgramName.exe.config в выводе при сборке. Поэтому вам нужно изменить значения там, чтобы это имело эффект, коэффициент должен работать, если вы дадите ему правильный путь к файлу.

EDIT2: этот app.config переименовывается во время компиляции в YourAppName.exe.config ... когда вы не помещаете его в настройку, значения не инициализируются правильно. Я расширил свой код, чтобы также адаптировать код конструктора файла Settings.designer.cs к значениям из XML и предположить, что это будет сделано. Один файл конфигурации для управления ими всеми: -)

...