6

I've started to learn Innosetup scripting by myself. For this i have created a simple C# console application, which reads an element from a configuration file and outputs onto the console.

<configuration>
  <appSettings>
    <add key ="Name" value="Brad Pitt"/> 
  </appSettings>
</configuration>

For ex: It shall read the value by querying the key attribute "Name".

I want the value in the .config to be written from the Innosetup setup script.

i.e During the installation process i shall gather the name (i.e "Brad Pitt" in this case) and write it to the value of the config file

<add key ="Name" value="Brad Pitt"/> 

Question is how do i achieve this, using a Pascal script or a standard script.

Any guidance is deeply appreciated

Regards

VATSA

this-Me
  • 2,139
  • 6
  • 43
  • 70
  • possible duplicate of [Inno Setup modify XML file based on custom input](http://stackoverflow.com/questions/8141886/inno-setup-modify-xml-file-based-on-custom-input) – Deanna Mar 07 '12 at 13:49
  • Also see [Edit installed file according to user preferences in Inno Setup](https://stackoverflow.com/q/39467048/850848). – Martin Prikryl Jun 14 '20 at 07:28

3 Answers3

7

To achieve this I created a simple procedure, which takes the xml file name as input. The procedure shall parse each line and write the contents to a temp file. The code checks each line looking for the string 'key="Name"':

   if (Pos('key="Name"', strTest) <> 0 ) 

If it finds a match then I replace that particular line by my desired tag, of which the value is gotten from my custom page.

   strTest := '  <add key="Name" value="' + strName + '"/> ';

This gets written into a temp file. I then delete the original exe.config file and rename the temp config file to the exe.config file (thus reflecting the changes I need). Below is the entire code snippet for the procedure, and don't forget to call the procedure from [Files] i.e.

[Files]
Source: "HUS.exe.config"; DestDir: "{app}"; AfterInstall: ConvertConfig('HUS.exe.config')

Code Snippet

procedure ConvertConfig(xmlFileName: String);
var
  xmlFile: String;
  xmlInhalt: TArrayOfString;
  strName: String;
  strTest: String;
  tmpConfigFile: String;
  k: Integer;
begin
  xmlFile := ExpandConstant('{app}') + '\' + xmlFileName;
  tmpConfigFile:= ExpandConstant('{app}') + '\config.tmp';
  strName :=  UserPage.Values[0] +' '+ UserPage.Values[1];

  if (FileExists(xmlFile)) then begin
    // Load the file to a String array
    LoadStringsFromFile(xmlFile, xmlInhalt);

    for k:=0 to GetArrayLength(xmlInhalt)-1 do begin
      strTest := xmlInhalt[k];
      if (Pos('key="Name"', strTest) <> 0 ) then  begin
        strTest := '  <add key="Name" value="' + strName + '"/> ';
      end;
      SaveStringToFile(tmpConfigFile, strTest + #13#10,  True);
    end;

    DeleteFile(xmlFile); //delete the old exe.config
    RenameFile(tmpConfigFile,xmlFile);
  end;
end;
Overleaf
  • 710
  • 6
  • 10
this-Me
  • 2,139
  • 6
  • 43
  • 70
5

I know it's a bit old now but here's another approach; use MSXML

procedure UpdateConfig();
var
  XMLDoc, NewNode, RootNode, Nodes, Node: Variant;
  ConfigFilename, Key: String;
  i: integer;

begin
  ConfigFilename := ExpandConstant('{app}') + '\your-app-name.exe.config';

  try
      XMLDoc := CreateOleObject('MSXML2.DOMDocument');
  except
    RaiseException('MSXML is required to complete the post-installation process.'#13#13'(Error ''' + GetExceptionMessage + ''' occurred)');
  end;  

  XMLDoc.async := False;
  XMLDoc.resolveExternals := False;
  XMLDoc.load(ConfigFilename);
  if XMLDoc.parseError.errorCode <> 0 then
    RaiseException('Error on line ' + IntToStr(XMLDoc.parseError.line) + ', position ' + IntToStr(XMLDoc.parseError.linepos) + ': ' + XMLDoc.parseError.reason);

  RootNode := XMLDoc.documentElement;
  Nodes := RootNode.selectNodes('//configuration/appSettings/add');
  for i := 0 to Nodes.length - 1 do
  begin
    Node := Nodes.Item[i];
    if Node.NodeType = 1 then
    begin
      key := Node.getAttribute('key');
      Case key of
        'MyValue1' : Node.setAttribute('value', ConfigPage.Values[0]);
        'MyValue2' : Node.setAttribute('value', ConfigPage.Values[1]);
        'MyValue3' : Node.setAttribute('value', ConfigPage.Values[2]);
      end;
    end;
  end;

  XMLDoc.Save(ConfigFilename); 

end;

Cheers, Matt

Matt
  • 526
  • 6
  • 19
  • Using Nodes.Item[i] in my code gives me a "Cannot import VARARRAYGET" error when starting the actual setup. – Nyerguds May 08 '13 at 12:52
  • Sorry, nevermind that. The error was caused by NOT using .Item in another iteration. Thanks for that, my code works now :) – Nyerguds May 08 '13 at 12:58
1

Just contributing, here follows an update of the above procedure, now receiving parameters, to be used with any attribute:

procedure UpdateConfigKeyValue(ConfigFilename,NodeName,KeyName,Value:String);
var
  XMLDoc, NewNode, RootNode, Nodes, Node: Variant;
  Key: String;
  i: integer;
begin
  try
      XMLDoc := CreateOleObject('MSXML2.DOMDocument');
  except
    RaiseException('MSXML is required to complete the post-installation process.'#13#13'(Error ''' + GetExceptionMessage + ''' occurred)');
  end;  

  XMLDoc.async := False;
  XMLDoc.resolveExternals := False;
  XMLDoc.load(ConfigFilename);
  if XMLDoc.parseError.errorCode <> 0 then
    RaiseException('Error on line ' + IntToStr(XMLDoc.parseError.line) + ', position ' + IntToStr(XMLDoc.parseError.linepos) + ': ' + XMLDoc.parseError.reason);

  RootNode := XMLDoc.documentElement;
  Nodes := RootNode.selectNodes(NodeName);
  for i := 0 to Nodes.length - 1 do
  begin
    Node := Nodes.Item[i];
    if Node.NodeType = 1 then
    begin
      key := Node.getAttribute('key');
      Case key of
        KeyName : Node.setAttribute('value', Value);
      end;
    end;
  end;

  XMLDoc.Save(ConfigFilename); 

end;

Usage Sample:

UpdateConfigKeyValue(ConfigPath,'//configuration/appSettings/add','hibernate.connection.data_source',SQLServer);