我开发了一个 .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 后立即回滚。
可以在日志中找到以下错误(对于 BOTH 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)时,所有其他文件都在磁盘上。这是时间问题吗?
观察:
<complus:ComPlusAssembly...>
”标签(包括嵌套组件),安装成功并出现(空)
应用程序被创建,即 - 只有容器”,没有任何
程序集或 COM+ 托管组件。
<Component.../>
”,它创建了一个简单的注册表项并移动所有
“
<complus:ComPlusApplication.../>
” 代码。该组件将复制所有文件后执行。与日志相同的结果(错误)
以上。
我在这里缺少什么?
最佳答案
这对我有用:
<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%\system32\com\dmp" 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+ 组件所需的所有依赖项。使用 Assembly Binding Log Viewer在安装期间查看您的组件是否由于缺少或不正确(错误的版本)依赖项而无法加载。
关于.net - 在 GAC 之外的 COM+ 应用程序中注册 .NET 程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13944373/