7

我开发了一个 .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)。这是时间问题吗?

观察:

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

我在这里想念什么?

4

3 回答 3

0

这对我有用:

<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 查看您的组件是否由于缺少或不正确(错误的版本)依赖关系而无法加载。

于 2012-12-19T11:08:13.617 回答
0

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

我是这样做的:

编译链接后,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 中引用它们,瞧!

于 2014-03-24T07:52:11.217 回答
0

我将 COM+ 程序集的目标平台更改为 3.5,它工作正常。

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

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

于 2017-03-30T16:04:29.330 回答