Reputation: 155
I am a noob in Windows programming, but I have to create a tricky MSI installer that installs a plugin via WiX toolset. The installer should detect upon running all installed versions of specific software and their plug-ins directories via Windows Registry API. After that it should show all of them on a separate page (dialog) with appropriare checkboxes. A user should choose what versions they want the plugin install into.
I've created a custom action (in C++ and put it into a DLL that is in the MSI database) that interacts registry API then loops over the results and adds temporary records to the database tables:
It runs after AppSearch
<InstallUISequence>
<Custom Action="PopulateVersions" After="AppSearch">Not Installed</Custom>
</InstallUISequence>
Then clicking Next button (I know that it's a wrong place to do such things) performs the custom action that filters off active property paths takes the first of them and performs the SetTargetPath action (it works fine). For the rest of them the action inserts appropriate temporary records into:
It installed the plugin only to the first property path refers to (which was passed to the SetTargetPath action).
Fine... I added a few CopyFile elements that refer to my custom properties (I declared a few properies to prevent MSI build error due to unknown properties) to the WiX markup just for testing:
<Property Id="PathProperty0" Value="{}"/>
<Property Id="PathProperty1" Value="{}"/>
<Property Id="PathProperty2" Value="{}"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLLOCATION" Name="MyPluginDir">
<Component Id="PluginExt" Guid="C112184A-307C-5E15-994F-0DFDA9DD427E">
<File Id="MyPlugin" Name="MyPlugin.dll" Source="MyPlugin.dll" Vital="yes" />
<CopyFile Id="MyPlugin_Copy1" FileId="MyPlugin" DestinationProperty="PathProperty1"/>
<CopyFile Id="MyPlugin_Copy2" FileId="MyPlugin" DestinationProperty="PathProperty2"/>
</Component>
</Directory>
</Directory>
</Directory>
Now the ProgressDialog is saying that "{}" is invalid path, but all of the properties were set to valid paths (I've checked this in debug)! Seems like it forgets or ignores all temporary database changes/property changes after showing elevating UAC prompt that asks for access to the same MSI file. The prompt is raised after clicking the Install button (with a shield icon). Probably it reads the database again and does not find any changes as they were in memory or cache, I don't know.
What am I doing wrong or how to make that installer properly? IMHO my implementation is overcomplicated. I do need your assistance.
Upvotes: 0
Views: 1140
Reputation: 55581
I think you are making this over complicated. You could just create an AddIns feature with a bunch of AddInVersionXXXX sub features and use the results of the AppSearch in Feature Conditions then show the Custom Setup dialog.
In my IsWiX I do a similar thing except I always install to every version detected. The trick is CopyFile will gracefully skip over the copy if the directory property doesn't have a value. It's really simple and can be see here:
Upvotes: 2
Reputation: 15905
I see at least two mistakes:
The properties for paths that you want to change at run time should be PUBLIC properties (that is, their names must not include lower case letters. Furthermore they should probably be listed in the SecureCustomProperties
property, which you can ensure by declaring them in your source with or without a value, and specifying the Secure attribute.
The value you are specifying for your directory-related property is literally {}
. This is an unusual value, and is only rarely correct. Typically you want an empty string instead. The exception is when you are in a Formatted
context and need to specify a non-empty string that results in an empty string value, such as a property-setting ControlEvent. The Property element of your wix source is not such a context.
I'm not certain about the full complexity of the approach you described (I haven't been able to fully think it through), but I do want to encourage the general approach you're taking of programmatically creating table data and letting Windows Installer do the rest. This approach is important enough to have been given a name of sorts: semi-custom action.
Per the guidance on semi-custom actions, you will likely want to schedule your PopulateVersions action in both the InstallUISequence and InstallExecuteSequence (especially once it uses RemoveFile to perform cleanup) in order to ensure that installs, maintenance, and silent removals all get the proper table data added.
Upvotes: 2