0

The MSI installation would call my (native/C++) custom action functions. Since the DLL is freshly loaded, and the MSIEXEC.EXE process is launched separately for each function (the callable actions, as specified in MSI/WiX script), I cannot use any global data in C/C++ program.

How (or Where) can I store some information about the installation going on? I cannot use named objects (like shared-memory) as the "process" that launches the DLL to call the "action" function would exit, and OS will not keep the named-object.

I may use an external file to store, but then how would I know (in the DLL's function):

  • When to delete the external file.
  • When to find that this function call is the first call (Action/function call Before="LaunchConditions" may help, not very sure).

If I cannot delete the file, I cannot know if "information" is current or stale (i.e. belonging to earlier failed/succeeded MSI run).

"Temporary MSI tables" I have heard of, but not sure how to utilize it.

Ajay
  • 16,823
  • 9
  • 50
  • 94
  • Maybe you can describe briefly what your custom actions do? Often we find they can be replaced by standard constructs and / or application launch sequence tweaking. – Stein Åsmul Sep 18 '18 at 18:17
  • The ones I'm concerned, do handle existing complex setup (non-MSI), and it needs to hold back the information about existing setup (files/registry/some state, etc.). This is needed so that when MSI fails, the custom action can go back to old setup/installation. There is no way (trust on this) to keep that in MSI, and must be done manually. – Ajay Sep 19 '18 at 06:50

1 Answers1

1

Preserve Settings: I am a little confused what your custom actions do, to be honest. However, it sounds like they preserve settings from an older application and setup version and put them back in place if the MSI fails to install properly?

Migration Suggestion (please seriously consider this option): Could you install your new MSI package and delete all shortcuts and access to the old application whilst leaving it installed instead? Your new application version installs to a new path and a new registry hive, and then you migrate all settings on first launch of the new application and then kick off the uninstall of the old application - somehow - or just leave it installed if that is acceptable? Are there COM servers in your old install? Other things that have global registration?

Custom Action Abstinence: The above is just a suggestion to avoid custom actions. There are many reasons to avoid custom actions (propaganda piece against custom actions). If you migrate settings on application launch you avoid all sequencing, conditioning, impersonation issues along with the technical issues you have already faced (there are many more) associated with custom action use. And crucially you are in a familiar debugging context (application launch code) as opposed to the unfamiliar world of setups and their poor debugability.


Preserving Settings & Data: With regards to saving data and settings in a running MSI instance, the built in mechanism is basically to set properties using Session.Property (COM / VBScript) or MsiSetProperty (Win32) calls. This allows you to preserve strings inside the MSI's Session object. Sort of global data.

Note that properties can only be set in immediate mode (custom actions that don't change the system), and sending the data to deferred mode custom actions (that can make system changes) is quite involved centering around the CustomActionData concept (more on deferred mode & CustomActionData).

Essentially you send a string to the deferred mode custom action by means of a SetProperty custom action in immediate mode. Typically a "home grown" delimited string that you construct in immediate mode and chew up into information pieces when receiving it in deferred mode. You could try to use JSON-strings and similar to make transfer easier and more reliable by serializing and de-serializing objects via JSON strings.

Alternatives?: This set property approach is involved. Some people write to and from the registry during installation, or to a temp file (in the temp folder) and then they clean up during the commit phase of MSI, but I don't like this approach for several reasons. For one thing commit custom actions might not run based on policies on target systems (when rollback is disabled, no commit script is created - see "Commit Execution" section), and it isn't best practice. Adding temporary rows is an interesting option that I have never spent much time on. I doubt you would be able to easily use this to achieve what you need, although I don't really know what you need in detail. I haven't used it properly. Quick sample. This RemoveFile example from WiX might be better.

Stein Åsmul
  • 34,628
  • 23
  • 78
  • 140