views:

3031

answers:

3

Once upon a time, a young, naive engineer thought it would be a good idea to separate out some of the functionality for his app into a COM component, written in C#. Visual studio had all the tools to do that, right? .NET was practically made for this, right? HA! He said, this will be easy. I'll have decent separation of components, keeping business logic away from the front end, and with COM, I'll be able to use it from anywhere! He merrily checked the register for COM interop checkbox in the project properties, exposed the classses he wanted, and went on his way.

Oh, the trials such a choice made. The young engineer now, more experienced, would not now wish this upon anyone. However, the burden had been placed upon his shoulders, and the burden remained heavy. He looked to lighten the load.

Along came WiX, a tool for generating Windows Installer files from XML. This intrigued him - it could replicate, quite simply, most of the code needed for a proper windows installer file simply from a handful of configuration files. His sights were looking up.

With WiX 2.0, he could generate quite easily the files needed to register a C# COM object. This involved using the tool tallow. He'd do something like the following:

tallow -c -nologo MyComExposedLibrary.dll > MyComExposedLibrary.wxs

which would then be fixed up (at first this was done manually, but eventually I recorded the steps into a small tool set the final directory ref id, component ID, fileID, GUID and codebase).

Then, the ensuing installer would install, and there would be joyous celebration, if the app worked.

Which it did not.

For days the young engineer poured over the differences on his development PC and that of the test install PC. "All the registry keys are the same!" He would exclaim. "Everything for MyComExposedLibrary is registerd, I swear!"

Except, it wasn't.

On the dawn of third day, after many a mountain dew, he realized there was one more object that Visual Studio was registering that his installer was not: the MyComExposedLibrary.tlb file.

Visual Studio, apparently, had been registering this file all along, creating additional subkeys in the HKLM\Software\Classes\Interface registry key, and registering the typelib in HKLM\SOFTWARE\Classes\TypeLib.

Tallow gave no help, complaining that a .tlb wasn't a file it groked. Nor the WiX 3.0 beta - this seemed to have even more issues getting things working.

I also gave Heat a try. This generated registry elements and class elements. I cleaned up heat's output, and then went to compile it, but got a different error: error LGHT0130 : The primary key <uuid here> is duplicated in table 'Registry'. Problem is, as far as I can tell, that uuid doesn't actually exist in any of my wxs source files. If I change around the component ref order in my feature element, a different dll component gives that error. Since I have been unsuccessful at getting a WiX 3.0 version of the project to compile, I haven't been able to confirm whether or not heat gives the right output.

I removed everything from the installer except for one of the assembly that cause this error to appear and tried compiling again. I got the same same error. Arrugh!

So, my good fellows, Windows enthusiasts, and WiX users, there falls two questions:

  • Is a typelib something that WiX can register natively? If so, how?
  • If not, what's the proper way of registering a typelib with a windows installer?

Also, I guess as another part of this, how does Visual Studio determine how to register the typelib? (Edit: looks the MSDN library article on typelib registration has the names of the keys needed, but I still need to figure out how to get the uuid's. (This is from this blog post on typelib and COM registration by Larry Osterman.) ) Reading a bit more, It may fall to me to register these bits manually, but I hope not...

I evaluated the output from regasm /regfile:MyDll.dll MyDll.dll. It looks like these are the same keys that wix generates for the dll. Regasm's other mode, regasm /tlb:<filename> generates and registers the typelib for the assembly, but,

/regfile[:FileName] Generate a reg file with the specified name instead of registering the types. This option cannot be used with the /u or /tlb options

seems the /regfile switch is incompatible with the /tlb switch. Khaaaaaaaan!

Further update: It looks like you don't actually need to include the .tlb file. According to this post on wix's typelib element, an MSI can create/register this as part of the setup process. It all comes down to configuring the WiX document to actually install it by getting the right attributes.

I found out later that you can get the right attributes using heat on the .tlb directly! See this SO question for more information.

+1  A: 

To extract the COM information, tallow will use the regasm.exe tool included with the .NET framework. It is likely that visual studio uses the same tool to register assemblies when you enable "register for COM interop".

The difference is that tallow will use the regasm /regfile switch to send the information to a .reg file instead of actually registering the assembly. Unfortunately the .reg file generated by regasm.exe is not complete. It skips the typelib entries which it does write to the registry during a real registration. This may be a bug in regasm.

To get your installer working you have three options:

  1. Add the missing registry keys to the tallow output manually. The tallow output is intended to be edited manually and saved along with your other wxs files anyway. You seem to be trying to fully automatically generate a working wxs file but I believe that was never a design goal of tallow.

  2. Use a custom action to invoke regasm from your installer. This is slightly evil because you may lose some of the strong transactional guarantees provided by the windows installer engine. I'm thinking of rollbacks triggered by a failure halfway during the install here.

  3. Avoid the registration altogether by making use of registration-free COM. This will require the creation of manifest files for both the application and the COM library.

Wim Coenen
Thanks for the info. I used regasm in the past to register the libraries, and was hoping that wouldn't be needed any more, but I'll give it a try. I'll update what I'm doing with the tallow output in my question - it's more like massaging the tallow output, fixing the keys and uuids as needed.
Robert P
It looks like regasm can make and register the typelib or spit out the registry entries for the assembly, but not both. regasm /regfile:mylib.dll mylib.dll generates the registry same entries found in the generated wix file, but not the typelib parts.
Robert P
Something else I thought of regarding regasm : I don't think regasm is redistributable.
Robert P
1) Yes, that's exactly what I'm saying. tallow uses regasm /regfile, and regasm /regfile generates an incomplete .reg file, explaining the missing entries in the tallow output.
Wim Coenen
2) regasm doesn't need to be redistributed. It is part of the .NET framework, so you can just invoke the one already present on the target machine. E.g. use "[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\regasm.exe" as the customaction ExeCommand.
Wim Coenen
Sorry if I was unclear in the first part, I was just confirming what you mentioned. If it's part of the .NET framework, then it most certainly can be used. That's fantastic news! I'll give it a go.
Robert P
Further reading done. Looks like it *IS* possible for a wix based installer to generate the typelib (note: I don't mean tallow generating the keys).
Robert P
+4  A: 

You should use Heat (WIX 3.0) located in the bin directory of the version you are using. Have a look at this blog, we use it here to register all our COM objects, by creating a wix fragment...

something like

heat file MyComExposedLibrary.dll -out MyComExposedLibrary.wxs

After, reading your edit, I would create a basic msi with wix that installs the com object only, see if that works ... then you'll know which battlefield to attack ...

CheGueVerra
I gave heat a try, but I suspect something is odd; I'm getting an odd issue. I'll add it to the question.
Robert P
I know that I use the -template:product flag as well ...
CheGueVerra
Okay, I've updated the question with information about the strange 'primary key' duplicate registry.
Robert P
What was the arguments you used for the heat command for your dll ?
CheGueVerra
almost exactly what you had: heat -nologo file MyLib.dll -out MyLib.wxs. I do this for 5 different assemblies, one at a time.
Robert P
I also noticed another interesting point - heat generated a ProgId element, all with the Id "Record"...I'm going to mess with that. Maybe that's the problem...
Robert P
Also, seeing your edit, the msi right now is only the com objects...I'll cut that down to just one of the objects and see what that can do. :)
Robert P
A good way to check if the generated wxs is ok, is to compare it with the registry element of the com object.
CheGueVerra
Okay, it looks like even just the output from even just one of the DLLs will not compile. It seems to be conflicting with itself, somehow...
Robert P
Edit in your generated wxs ... You did compare the generated wxs [typelib; class; ProgID; AppId; Interface] against the entry on your machine for that COM object?
CheGueVerra
Yup. It seems all the keys for the just the DLL are being generated. Those that it makes seem right. It's the typelib registry entries that I can't seem to find a way to generate, apart from ripping them right out of the registry.
Robert P
Add them by hand, an dput it under the File element of the fragment
CheGueVerra
Sweet, figured out my problem with the RegistryValue elements; I had completely forgotten about setting Id's for them. Now I need to figure out how to configure the Typelib element. Garrugh.
Robert P
A: 

I recently ran into this issue, and the simplest workaround I could find follows these steps on the development machine:

  1. Run: Regasm MyDLL.dll /tlb:MyDLL.tlb
  2. Run: Heat file MyDLL.dll -out MyDll-1.wxs
  3. Run: Heat file MyDll.tlb -out MyDll-2.wxs

MyDll-2.wxs contains a <Typelib> element that you will want to copy and nest inside the <File> element that was generated in MyDll-1.wxs. This will give you a complete <Component> element that you can use in the installer project.

hurcane
There should be no need to Regasm it first.
Sander Rijken