I developed a .NET assembly (.NET 4.0, strong-named) which exposes two Serviced Components. The assembly (dll) is supposed to be hosted in a COM+ application and it is decorated with the COM+ attributes (assembly & component levels). For example, the assembly level attributes:
//COM+ Attributes
[assembly: ApplicationID("MY_APP_GUID")] //GUID of the COM+ app
[assembly: ApplicationName("MyComPlusAppName")] //Name of the COM+ app
[assembly: ApplicationActivation(ActivationOption.Server)] //The app is hosted in it own dllhost process (out-of-process)
[assembly: ApplicationAccessControl(AccessChecksLevel = AccessChecksLevelOption.ApplicationComponent, Authentication = AuthenticationOption.None, ImpersonationLevel = ImpersonationLevelOption.Delegate, Value = false)]
[assembly: Description("COM+ app description")]
Currently (development reasons), I've been running the following script to create the COM+ application and register the assembly (with all of its components):
%windir%\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exe /appdir:"%CD%" MyComPlusAssembly.dll
The above batch file will create (in a single run) the COM+ application according to the assembly decorating attributes, register the MyComPlusAssembly.dll file in the COM+ app and register all ComVisible components in it, so everything is visible and configured as expected in dcomcnfg. This command will also generate a fresh new TLB file. The assembly is built using AnyCPU, so on x64 versions of Windows the dllhost.exe process will run as 64bit and on a x86 version of Windows it will run as 32bit. Also, my dll file should NOT be placed in the GAC (this is why I'm using the /appdir switch of the RegSvcs.exe command-line utility). All is working as expected when installing the COM+ assembly with the above batch file.
I started writing a Wix (v3.6) deployment project for my app which is supposed to do the same, that is: Create the COM+ application, register the .NET assembly and all ComVisible components. Please note that this time I'm relying on the fact that the TLB file is shipped with the installer (*.msi). The TLB was generated by the build process (VS 2010). To achieve the above I've added the following Wix component (inspired by the Wix COM+ Extension docs - WixComPlusExtension):
<DirectoryRef Id="INSTALLDIR_SERVER">
<Component Id="cmp_MyComPlusAssembly.dll" Guid="COMPONENT_DLL_GUID">
<File Id="MyComPlusAssembly.dll" Name="MyComPlusAssembly.dll" DiskId="1" Source="..\install\$(var.Configuration)\Server\MyComPlusAssembly.dll" KeyPath="yes"/>
<CreateFolder>
<util:PermissionEx GenericAll="yes" User="NT AUTHORITY\LocalService"/>
</CreateFolder>
<complus:ComPlusApplication Id="ComPlusServerApp"
AccessChecksLevel="applicationComponentLevel"
Activation="local"
ApplicationAccessChecksEnabled="no"
ApplicationDirectory="[INSTALLDIR_SERVER]"
ApplicationId="MyComPlusAssembly.dll"
Authentication="none"
Description="MyComPlusAssembly.dll"
Identity="NT AUTHORITY\LocalService"
ImpersonationLevel="delegate"
IsEnabled="yes"
RunForever="yes"
Name="MyComPlusApp"
Deleteable="yes">
<complus:ComPlusAssembly Id="ComPlusServerAssembley"
DllPath="[#MyComPlusAssembly.dll]"
TlbPath="[#MyComPlusAssembly.tlb]"
Type=".net"
DllPathFromGAC="no">
<complus:ComPlusComponent Id="COMObject_1"
CLSID="COM_OBJ_1_GUID"
Description="Object 1"
IsEnabled="yes"/>
<complus:ComPlusComponent Id="COMObject_2"
CLSID="COM_OBJ_2_GUID"
Description="Object 2"
IsEnabled="yes"/>
</complus:ComPlusAssembly>
</complus:ComPlusApplication>
</Component>
</Component>
<Component Id="cmp_MyComPlusAssembly.tlb" Guid="COMPONENT_TLB_GUID">
<File Id="cmp_MyComPlusAssembly.tlb" Name="cmp_MyComPlusAssembly.tlb" DiskId="1" Source="..\install\$(var.Configuration)\Server\cmp_MyComPlusAssembly.tlb" KeyPath="yes"/>
</Component>
</DirectoryRef>
The MSI project builds successfully but the installation process fails and is rolled back immediately after trying to register the dll. The following error can be found in the log (for BOTH x86 & x64 versions):
Action 16:33:37: RegisterComPlusAssemblies. Registering COM+ components
RegisterComPlusAssemblies: DLL: C:\Program Files\MyApp\Server\MyComPlusAssembly.dll
ComPlusInstallExecute: Registering assembly, key: ComPlusServerAssembley
ComPlusInstallExecute: ExceptionInfo: Code='0', Source='System.EnterpriseServices', Description='Failed to load assembly 'c:\program files\myapp\server\MyComPlusAssembly.dll'.', HelpFile='', HelpContext='0'
ComPlusInstallExecute: Error 0x80020009: Failed to invoke RegistrationHelper.InstallAssembly() method
ComPlusInstallExecute: Error 0x80020009: Failed to register .NET assembly
ComPlusInstallExecute: Error 0x80020009: Failed to register assembly, key: ComPlusServerAssembley
ComPlusInstallExecute: Error 0x80020009: Failed to register assemblies
The above error can mean that the dll being registered in the COM+ app is missing, that is, the file is not on the disk. Although the installation process is fast, I've never seen the MyComPlusAssembly.dll file being copied to the disk (to [INSTALLDIR_SERVER]), all other files are on the disk when the installation starts rolling back (including the TLB). Is this a timing issue?
Observations:
- This happens for both versions of the installer (x64 & x86).
- When removing the "
<complus:ComPlusAssembly...>
" tag (including the nested components), the installation succeeds and an (empty) application is created, that is - only the container", without any assembly or COM+ hosted components. - I tried adding a third "
<Component.../>
" which creates a simple registry key and move all of the "<complus:ComPlusApplication.../>
" code to it. This component will be executed after all files are copied. Same result (error) as log above.
What am I missing here?
There seems to be a lot of examples of this but even if you follow them you might not succed.
This is how I did it:
After compile and link, cl *.cs -o foo.dll
Some manually edit of the foodlltlb.wxs file because the genereated wxs from heat will generate warnings/error with candle (3.8) (Basic, TypeLib must be a child of File)
Fix your guid and component id, reference them in you main wxs, voila!