1
votes

I am currently working on a CustomAction library for reading and writing INI (outside C:\Windows) and XML files. I already looked at this SO question but the suggested answers did not help with my issue. The CustomAction (for reading a value from an INI file) I am trying to execute is defined as

<CustomAction Id="MyCustomAction" 
              Execute="deferred"
              Impersonate="no"
              Return="ignore"
              BinaryKey="MyCALibrary.CA.dll"
              DllEntry="MyCustomActionEntry" />

and scheduled as

<InstallExecuteSequence>
   <Custom Action="MyCustomAction" After="InstallFiles">
     <![CDATA[NOT Installed AND NOT PATCH]]>
   </Custom>
</InstallExecuteSequence>

As it is a deferred action, it receives data through a property:

   <Property Id="MyCustomAction"
              Value="File=[INSTALLDIR]cfg\MyConfig.ini;Section=MyConfig;Key=MyKey"/>

The (C#) implementation of my CustomAction looks like this:

    [CustomAction]
    public static ActionResult MyCustomActionEntry(Session session)
    {
      try
      {
        session.Log("Begin MyCustomActionEntry");
        CustomActionData data = session.CustomActionData;

        session.Log($"Data: '{data}'.");

        string fileName = data["File"];
        string sectionName = data["Section"];
        string keyName = data["Key"];

        // ... check if all properties are set
        // ... removed for brevity

        session.Log($"- Parametrization: (File={fileName}; Section={sectionName}; Key={keyName}.");

        if(File.Exists(fileName))
        {
          session.Log("File found on disk.");
        }
        else
        {
          session.Log("File NOT found on disk.");
        }

        // ... actual INI Access - F A I L S

      } 
      catch(Exception ex)
      {
        //... handle any errors
      }
    }

Using Orca, I see that the CustomAction is most likely scheduled correctly - the table InstallExecuteSequence shows:

...
InstallFiles   4000
...
MyCustomAction 4001
...

Of course, I now looked at the install log for hints. The log shows: (In what I guess is the immediate phase):

Action ended <time>: InstallFiles. Return value 1.
MSI (s) (F8:98) <time>: Doing action: MyCustomAction
Action start <time>: MyCustomAction.
Action ended <time>: MyCustomAction. Return value 1.

For what I think would be the deferred phase (further down in the log):

MSI (s) (F8:98) <time>: Executing op: FileCopy(SourceName=qjlzmwkb.ini|MyConfig.ini,SourceCabKey=<key>,DestName=MyConfig.ini,...,InstallMode=58982400,...)
MSI (s) (F8:98) <time>: File: C:\tmp\MyApp\cfg\MyConfig.ini;    To be installed;    Won't patch;    No existing file
MSI (s) (F8:98) <time>: Source for file '<key>' is compressed
...
Begin MyCustomActionEntry
...
Data: 'File=C:\tmp\MyApp\cfg\MyConfig.ini;Section=MyConfig;Key=MyKey'.
...
- Parametrization: (File=C:\tmp\MyApp\cfg\MyConfig.ini; Section=MyConfig; Key=MyKey).
...
File NOT found on disk.

After the installer finishes, the file is at exactly where I expepct it - the location referenced in the custom action.

I assume that the installed files should be available on disk after InstallFiles in the deferred stage of the execute phase for any CustomActions to access. Has anyone else observed similar behavior and can give me hints on what else to do?

1
I couldn't help but notice that the file you are passing is an INI file. Could it be that this file located in the IniFile table as opposed to the File table? And as such, you would need to schedule your Custom Action to execute after WriteIniValues instead of InstallFiles....Captain_Planet
The INI file is located in the file table; the files to be installed are also all collected with heat - using the HeatDirectory element. Using Orca, I do not even see an IniFile table.vonludi
Are you sure that custom action runs deferred? Can you add your WiX markup for that so we can have a look?Stein Åsmul
I am not sure I quite understand. Is there any more to WiX markup than the three snippets at the top of my question?vonludi

1 Answers

0
votes

Summary: You can read values from an INI file using an immediate mode custom action and set properties that are used by Windows Installer to write values to actual INI files the built-in way during regular installation (no custom action to write anything, just to read). Advanced Installer Sample Video (similar approach).


Custom Actions: A few things about custom actions:


INI: A quick summary (to the best of my rusty knowledge):

  • INI Write: INI files can be fully written by MSI itself anywhere on disk
    • You can use properties to inject custom values: [MYPROPERTY]
    • The IniFile table takes care of all of this, and it is working OK
    • Don't install INI files as separate files, use the IniFile table. More here
  • INI Read: Windows Installer INI value searches support only files in %SystemDrive%\Windows folder (C:\Windows).
    • In other words: it is just reading values from anywhere that is hard (unless this has changed unbeknownst to me - I see different hacks here and there)
    • You can read values from an INI file using an immediate mode custom action and set properties that are used by Windows Installer to write values to actual INI files.
    • There is sample code here to read INI files with VBScript (just to remember that it is there, not a recommendation to use as such).
  • Video Sample Advanced Installer: See this video for how to do things with regards to INI files in Advanced Installer (one of the major MSI tools available)

XML: XML writing and reading was never a part of MSI at all (unlike INI writing which was). All major tools have support for XML writing and reading, and each tool does something slightly different by the looks of things.

It is NOT advisable to roll your own features here if you can get by with what is already out there.