在 GAC 外部的 COM+ 应用程序中注册 .NET 程序集



我开发了一个.NET程序集(.NET 4.0,强名称),它公开了两个服务组件。程序集 (dll) 应该承载在 COM+ 应用程序中,并使用 COM+ 属性(程序集和组件级别)进行修饰。例如,程序集级别属性:

//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")]

目前(开发原因),我一直在运行以下脚本来创建 COM+ 应用程序并注册程序集(及其所有组件):

%windir%Microsoft.NETFrameworkv4.0.30319RegSvcs.exe /appdir:"%CD%" MyComPlusAssembly.dll 

上面的批处理文件将根据程序集修饰属性创建(在单次运行中)COM+ 应用程序,在 COM+ 应用中注册 MyComPlusAssembly.dll 文件并注册其中的所有 ComVisible 组件,因此所有内容都可见,并在 dcomcnfg 中按预期配置。此命令还将生成一个新的 TLB 文件。 该程序集是使用 AnyCPU 构建的,因此在 x64 版本的 Windows 上,dllhost.exe 进程将以 64 位运行,而在 x86 版本的 Windows 上,它将以 32 位运行。另外,我的 dll文件不应该放在GAC 中(这就是我使用 RegSvcs.exe 命令行实用程序的/appdir 开关的原因)。使用上述批处理文件安装 COM+ 程序集时,一切都按预期工作。

我开始为我的应用程序编写一个 Wix (v3.6) 部署项目,该项目应该做同样的事情,即:创建 COM+ 应用程序,注册 .NET 程序集和所有 ComVisible 组件。请注意,这次我依赖于TLB文件随安装程序(*.msi)一起提供的事实。TLB 由构建过程生成 (VS 2010)。 为了实现上述目标,我添加了以下Wix组件(灵感来自Wix COM+扩展文档 - 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)ServerMyComPlusAssembly.dll" KeyPath="yes"/>
<CreateFolder>
<util:PermissionEx GenericAll="yes" User="NT AUTHORITYLocalService"/>
</CreateFolder>
<complus:ComPlusApplication Id="ComPlusServerApp"
AccessChecksLevel="applicationComponentLevel"
Activation="local"
ApplicationAccessChecksEnabled="no"
ApplicationDirectory="[INSTALLDIR_SERVER]"
ApplicationId="MyComPlusAssembly.dll"
Authentication="none"
Description="MyComPlusAssembly.dll"
Identity="NT AUTHORITYLocalService"
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)Servercmp_MyComPlusAssembly.tlb" KeyPath="yes"/>
</Component>
</DirectoryRef>   

MSI 项目成功生成,但安装过程失败,并在尝试注册 dll 后立即回滚。 可以在日志中找到以下错误(对于x86和x64版本):

Action 16:33:37: RegisterComPlusAssemblies. Registering COM+ components
RegisterComPlusAssemblies: DLL: C:Program FilesMyAppServerMyComPlusAssembly.dll
ComPlusInstallExecute:  Registering assembly, key: ComPlusServerAssembley
ComPlusInstallExecute:  ExceptionInfo: Code='0', Source='System.EnterpriseServices', Description='Failed to load assembly 'c:program filesmyappserverMyComPlusAssembly.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

上述错误可能意味着在 COM+ 应用中注册的 dll 丢失,即文件不在磁盘上。 虽然安装过程很快,但我从未见过MyComPlusAssembly.dll文件被复制到磁盘(到[INSTALLDIR_SERVER]),当安装开始回滚时,所有其他文件都在磁盘上(包括TLB)。这是时间问题吗?

观察:

  1. 对于两个版本的安装程序(x64和x86),都会发生这种情况。
  2. 删除"<complus:ComPlusAssembly...>"标签(包括 嵌套组件),安装成功且 (空) 创建应用程序,即 - 只有容器",没有任何 程序集或 COM+ 托管组件。
  3. 我尝试添加第三个"<Component.../>",它创建了一个简单的 注册表项并移动所有 "<complus:ComPlusApplication.../>"代码。此组件将是 复制所有文件后执行。与日志相同的结果(错误) 以上。

我在这里错过了什么?

我将 COM+ 程序集的目标平台更改为 3.5 并且它起作用了。

问题与从WixComPlusExtension调用的System.EnterpriseServices.dll版本有关。该库至少有几个版本:2.0.xxxx 和 4.0.xxxx。 WixComPlusExtension调用RegisterDotNetAssembly(cpasmexec.cpp)方法,该方法使用System.EnterpriseServices.RegistrationHelper类来注册程序集。事实是,当您针对为框架 4 或更高版本构建的 .net COM+ 库从版本 2.0.xxxx 的 System.EnterpriseServices 调用 RegistrationHelper.InstallAssembly 时,您会收到"无法加载程序集"错误。

任何想法如何调整WixComPlusExtension(它是开源的)使其调用框架4的System.EnterpriseServices?

这对我有用:

<Component Id="cmp502C27298171EA4E966A386B188D734C" Guid="{7A5ADAA7-8D43-4E91-80DB-764BB1E13887}">
<File Id="filB4BA1D295EA5EC7D92FD7FEFDD1251C2" KeyPath="yes" Source="$(var.BinComPlusFolder)MyComponent.dll" />
<complus:ComPlusApplication Id="MyApp" Name="MyApp" Description="My App" ApplicationAccessChecksEnabled="no" AccessChecksLevel="applicationComponentLevel" Authentication="packet" ImpersonationLevel="impersonate" Activation="local" ApplicationDirectory="[ServicesBinFolder]" Identity="[SERVICE_USERNAME]" Password="[SERVICE_PASSWORD]" ShutdownAfter="3" Deleteable="yes" CRMEnabled="yes" ThreeGigSupportEnabled="no" ConcurrentApps="3" RecycleLifetimeLimit="60" RecycleMemoryLimit="500000" RecycleExpirationTimeout="15" RecycleCallLimit="0" RecycleActivationLimit="0" DumpEnabled="no" DumpOnException="no" DumpOnFailfast="no" DumpPath="%systemroot%system32comdmp" QueuingEnabled="no" />
<complus:ComPlusAssembly Id="filB4BA1D295EA5EC7D92FD7FEFDD1251C2" Application="MyApp" DllPath="[#filB4BA1D295EA5EC7D92FD7FEFDD1251C2]" TlbPath="[#fil447CD49CDBE45EACEE125A362902CF2F]" Type=".net" RegisterInCommit="yes" />
</Component>

也许你应该省略 DllPathFromGAC 属性?

编辑:这是在Windows XP和Windows 2008 32位上的Wix v3.6上。要确保的另一件事是,您还安装了 COM+ 组件所需的所有依赖项。在安装过程中使用程序集绑定日志查看器查看组件是否由于缺少或不正确的(错误版本)依赖项而无法加载。

似乎有很多这样的例子,但即使你遵循它们,你也可能不会成功。

我是这样做的:

编译并链接后,cl *.cs -o foo.dll

tlbexp foo.dll
heat file foo.dll -o foodll.wxs
heat file foo.tlb -o foodlltlb.wxs

一些手动编辑 foodlltlb.wxs 文件,因为从热量生成的 wxs 会生成蜡烛 (3.8) 的警告/错误(基本,TypeLib 必须是 File 的子级)

修复您的 guid 和组件 ID,在您的主 wxs 中引用它们,瞧!

最新更新