38

I found an example on registering DLLs, Registering an Assembly for COM Interop in a MSI file with the Windows Installer XML toolset., and WiX complains about the "AssemblyRegisterComInterop" attribute.

I removed that and changed the "Assembly" attribute to win32, and it says I need to specify the AssemblyManifest attribute, but what should I put there?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Davy8
  • 30,868
  • 25
  • 115
  • 173

3 Answers3

44

The easiest way (and Rob M will rant and rave about how this is wrong) is just to use SelfRegCost=1 on the File tag for the DLL.

This is wrong, because we should be explicitly controlling the registration of the DLL, not allowing it just to run arbitrary code via DllRegisterServer. The theory being that a DLL should do nothing beyond putting the appropriate entries in the registry when DllRegisterServer is called. Unfortunately, a lot of of them do more than that, so self-registration might be the only way to get your install to work.

It's also wrong, because that means the Windows installation system doesn't know anything about those registry keys, and what should and shouldn't be there. That means repairing won't work, and possibly un-installation won't clean up properly, etc.

Otherwise, you can generate the appropriate WiX code by pointing heat.exe at your DLL, and integrating its output into your current WiX project. You'll get a variety of Class, ProgID, TypeLib, and Registry tags. You may need to manually edit that output to get it to compile.

I hope that helps.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Troy Howard
  • 2,612
  • 21
  • 25
  • So basically copy/paste the output from heat.exe and change the appropriate paths etc? – Davy8 Dec 12 '08 at 21:52
  • I like to put the wxs that heat created into a fragment that the main wxs references to. What was the options you passed to heat, that didn't register the dll. – CheGueVerra Dec 12 '08 at 23:42
  • I usually have to move the class and progid tags into the file tag, and possibly edit some of the registry keys. Specifically, if the DLL is a .NET DLL, you'll need to provide unique ids for the registry keys that reference mscoree.dll or you will get collisions with the auto-generated ones. – Troy Howard Dec 13 '08 at 00:24
  • 4
    i usually run heat like this: heat file -gg -sfrag "C:\path\to\file.dll" -o myfile.wxs ... then include the generated wxs file in a votive project, modify it, and reference the root component from the "main" wxs for the msi/merge module via componentref, or componentgroupref. – Troy Howard Dec 13 '08 at 00:26
  • For my build process I've automated the hand editing with customized scripts. I suggest you do the same... ;) – Troy Howard Dec 13 '08 at 00:29
  • I used heat to generate COM registration, but I got an issue when uninstalling my product - it removes COM registration despite other products still use that DLL. As a result other products gets broken. – Sasha Jan 03 '13 at 14:46
  • Just a question, *if* this is bad (which I myself have preached to others), then why is the meaning of `SelfRegCost=1` not changed to be "extract the stuff via heat.exe, then include the created fragment"? Essentially making it almost a preprocessing step. – 0xC0000022L Apr 08 '16 at 16:15
  • But the heat command is sometimes buggy and doesn't even generate the wxs for a COM component. – Ven Jan 24 '18 at 08:53
  • When I used this on Windows 11, it failed without explanation. But using the heat fragment works flawlessly. So could you maybe start off by saying heat is less prone to error? – carlin.scott Aug 26 '22 at 15:35
26

It isn't just me that will rant and rave about how SelfReg is evil. The MSI SDK gives you a list of seven reasons why not to use SelfReg.

Example:

<Component Id="Component" Guid="*">
    <File Source="ComServer.dll">
        <Class Id="PUT-CLSID-HERE" Context="InprocServer32" ThreadingModel="apartment" Description="Your server description">
            <ProgId Id="Your.Server.1" Description="Your ProgId description">
                <ProgId Id="Your.Server" Description="Your ProgId description" />
            </ProgId>
        </Class>

        <Class Id="PUT-PROXY-CLSID-HERE" Context="InprocServer32" ThreadingModel="both" Description="Your server Proxies, assuming you have them">
            <Interface Id="PUT-INTERFACEID-HERE" Name="IInterface1" />
            <Interface Id="PUT-INTERFACEID-HERE" Name="IInterface2" />
            <Interface Id="PUT-INTERFACEID-HERE" Name="IInterface3" />
            <Interface Id="PUT-INTERFACEID-HERE" Name="IInterface4" />
        </Class>
    </File>
</Component>

Ultimately, Troy's answer is all correct.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob Mensching
  • 33,834
  • 5
  • 90
  • 130
  • 1
    [**Self-registration Considered Harmful**](http://stackoverflow.com/questions/6129816/msi-register-dll-self-registration-considered-harmful/6141538#6141538) (pardon the Dijkstra-allusion). – Stein Åsmul May 06 '15 at 19:50
14

Use the heat.exe program that comes with the WiX toolset, to generate the wxs registration fragment:

 heat.exe file <filename> -out <output wxs file>

eg.

 heat.exe file my.dll -out my.wxs

Copy the contents of the <Component> tag from that new wxs file and paste it into the <Component> of your existing wxs file that references your dll using a <File> tag. Delete the <File> tag you pasted and replace all references to that file Id with the one that was already there; if the existing one didn't have an Id attribute, add it and set it to whatever you want.

carlin.scott
  • 6,214
  • 3
  • 30
  • 35
Adam Tegen
  • 25,378
  • 33
  • 125
  • 153