I developed a .NET assembly (.NET 4.0, with a strong name) that provides two Serviced Components. It is assumed that the assembly (dll) is hosted in a COM + application and is decorated with COM + attributes (assembly and component levels). For example, 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 am running the following script to create a COM + application and register the assembly (with all its components):
%windir%\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exe /appdir:"%CD%" MyComPlusAssembly.dll
The above batch file will create (in one run) the COM + application in accordance with the assembly attributes, register the MyComPlusAssembly.dll file in the COM + application and register all ComVisible components in it, so everything will be visible and configured as expected in dcomcnfg. This command will also create a new new TLB file. The build is built using AnyCPU, so on the x64 versions of Windows the dllhost.exe process will work as 64-bit, and on the x86 version of Windows it will work as 32-bit. In addition, my dll file must NOT be placed in the GAC (which is why I use the RegSvcs.exe command line utility / appdir switch). Everything works as expected when installing the COM + assembly with the above batch file.
I started writing a Wix deployment project (v3.6) for my application, which is supposed to do the same thing: Create a COM + application, register a .NET assembly and all ComVisible components. Please note that this time I rely on the TLB file to come with the installer (* .msi). TLB was generated by the build process (VS 2010). To achieve the above, I 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 succeeds, but the installation process fails and rollback immediately after trying to register the DLL. The following error can be found in the log (for BOTH x86 and 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 may mean that the DLL registered in the COM + application is missing, i.e. the file is not located on disk. Although the installation process is quick, I have never seen the MyComPlusAssembly.dll file being copied to the disk (before [INSTALLDIR_SERVER]), all other files are on the disk when the installation starts to roll back (including TLB). Is this a synchronization problem?
remarks:
- This happens for both installer versions (x64 and x86).
- When you remove the
<complus:ComPlusAssembly...> (including attached components), the installation completes successfully and the (empty) application is created, that is, only the container, "without any assembly or COM +. - I tried to add a third "
<Component.../> " that creates a simple registry key and move all the " <complus:ComPlusApplication.../> ". This component will be executed after copying all files. The same result (error) as the log above.
What am I missing here?