我开发了一个 .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.NET\Framework\v4.0.30319\RegSvcs.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)\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>
MSI 项目构建成功,但安装过程失败,并在尝试注册 dll 后立即回滚。可以在日志中找到以下错误(对于x86和 x64 版本):
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
上述错误可能表示COM+应用程序中正在注册的dll丢失,即文件不在磁盘上。尽管安装过程很快,但我从未见过将 MyComPlusAssembly.dll 文件复制到磁盘(到 [INSTALLDIR_SERVER]),当安装开始回滚时,所有其他文件都在磁盘上(包括 TLB)。这是时间问题吗?
观察:
- 安装程序的两个版本(x64 和 x86)都会发生这种情况。
- 删除“
<complus:ComPlusAssembly...>
”标签(包括嵌套组件)时,安装成功并创建(空)应用程序,即 - 只有容器”,没有任何程序集或 COM+ 托管组件。 - 我尝试添加第三个“
<Component.../>
”,它创建一个简单的注册表项并将所有“<complus:ComPlusApplication.../>
”代码移至其中。该组件将在所有文件被复制后执行。与上面的日志相同的结果(错误)。
我在这里想念什么?