cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
nshustov
Level 3

Multiple merge modules with managed custom actions merged incorrectly

Hi,

I have two merge modules, say A and B.
Both reference the same .NET assembly and expose several custom actions based on its functionality.
A exposes custom actions A1 and A2.
B exposes cusom actions B1, B2 and B3.

I created the MSI Basic project (say, P) that included A and B.
P makes use of managed custom actions declared in A and B.

The problem is that at runtime the installation of P invokes wrong custom actions - for example if I had in the execution sequence A1, B1, B2, A2, B3 then instead of calling B1 it may call A1 or vice versa, instead of A1 it may call B1 (depending on the order I added the merge modules, their actual names etc).

After comparing the MSI tables of project P and merge modules A and B, I found the following (some info proved, some guessed):

- CustomAction table for A contains records for A1 and A2. For A1 record "Target" column field contains value "m1". For A2 record "Target" column field contains value "m2".

- ISClrWrap table for merge module A contains two sets of records describing the A1/A2 entry points and its arguments.

- The same for merge modeule B: CustomAction table contains records for B1 and B2. For B1 record "Target" column field contains value "m1". For B2 record "Target" column field contains value "m2"; for B3 it contains "m3". ISClrWrap contains sets of records for B1, B2 and B3.

Note that Windows Installer documentation says that for custom action type 1 (which it is) "Target" column defines the entry point in the custom action DLL.

My [educated]:rolleyes: guess is that this "m#" value references the recordsets in ISClrWrap table: m1 is for the first, m2 is for the second etc.

- CustomActions table in the resulting project P contains records from both CustomAction tables of A and B. However, "Target" column for these records still contains original values: A1/m1, A2/m2, B1/m1, B2/m2, B3/m3.

I would like to repeat here that all mentioned custom actions reference the same .NET assembly.

The resulting MSI file for P does not contain ISClrWrap table. After a bit of digging I found that the binary stream for the custom actions (from Binary table, referenced by the value in "Source" column) has all the assemblies AND the entry points descriptions for the custom actions.
So, my another [educated] 😉 guess is that "m#" value becomes an index for the entry point for the merged custom actions.

Due to the fact that m# values were not merged (I mean, they keep initial data from merge module), the entry points for different merged custom actions now actually point to the same info in binary stream.

As a result the incorrrect .NET assembly functionality is called while invoking the custom actions.

Hope I am totally wrong and I miss some obvious thing and everything works fine... But could anybody please comment on that and give me a hint how to handle the situation (without hacking into resulting msi projects and the like stuff)?

I can try redesigning my projects and merge modules so all the managed custom actions from the same assembly would sit in the only merge module (thus eliminating need to merge custom actions based on the same assembly), but this would be, frankly, an overkill.:eek:
Labels (1)
0 Kudos
(1) Reply
MichaelU
Level 12 Flexeran
Level 12 Flexeran

It looks like it is a bug in how we generate the data in the merge module. In each case we collect a bunch of method entry points and turn them into a single binary table entry. However we try to generate the same binary table entry in both the merge module and the basic msi case, so they overwrite each other, and you only get one set of entry points.

The simple workarounds I can think of are one of the following. We'll try to get this fixed in a future release so the workarounds are no longer necessary.

  • Post-edit the merge module to add a trailing guid to the Binary table name; update referential integrity in the CustomAction table
  • Change the name of the assembly used in the merge module such that it is different from the one in the basic msi
  • As you surmised, move all actions involving that assembly to the merge module
0 Kudos