.net COM注册:位置重要吗?

.net COM注册:位置重要吗?,.net,com,com-interop,.net,Com,Com Interop,我在一个解决方案中有两个项目-例如,ProjectA和ProjectB。这两个项目都是为COM互操作注册的,ProjectAreferencesProjectB——当ProjectA生成时,它将ProjectB.dll复制到其输出文件夹中 现在,COM客户端需要访问ProjectB.tlb。我尝试使用后期生成事件将类型库从ProjectB的输出文件夹复制到ProjectA;乍一看,这是可行的——COM客户端可以“看到”.tlb中的类型 问题是,每当COM客户端尝试调用.tlb中的方法时,就会出现

我在一个解决方案中有两个项目-例如,
ProjectA
ProjectB
。这两个项目都是为COM互操作注册的,
ProjectA
references
ProjectB
——当
ProjectA
生成时,它将
ProjectB.dll
复制到其输出文件夹中

现在,COM客户端需要访问
ProjectB.tlb
。我尝试使用后期生成事件将类型库从
ProjectB
的输出文件夹复制到
ProjectA
;乍一看,这是可行的——COM客户端可以“看到”.tlb中的类型

问题是,每当COM客户端尝试调用.tlb中的方法时,就会出现一个自动化错误

我的直觉是.tlb需要在使用它的位置创建/注册,因此我取消选中了
ProjectB
中的“注册COM互操作”框,从生成后事件中删除了
xcopy
,并在
ProjectA
的生成后事件中添加了
regasm.exe/tlb
调用,以便在
ProjectA
的输出文件夹中创建并注册
ProjectB.tlb
。。。然后我清理并重建了解决方案

同样的事情:COM客户端可以看到这些类型,但是当它试图实际使用公开的API时会抛出一个自动化错误

这两个项目原本是同一个项目。我们决定将它们分开,这样当我们发布
ProjectA
的更新时,我们就可以这样做,而不会导致COM客户端引用
ProjectB
中的代码时出现兼容性问题。这个主意似乎很好,但是……这可能吗?如果是,怎么做


还是将
ProjectB
折叠回
ProjectA
我唯一的希望就是让COM客户端使用
ProjectB
公开的COM API?

TLB的位置无关紧要;对于编译器来说,这只是元数据。它不在运行时使用。但是,.NET必须能够在运行时定位程序集DLL,这可能很微妙

.NET将尝试使用常用的Fusion探测规则定位DLL,这些规则基于客户端进程EXE的位置,而不是DLL或TLB的位置。这基本上给了你三个选择:

  • 您可以将项目A.DLL和
    项目B.DLL
    复制到与客户端的EXE相同的文件夹中
我不这么做,因为我发现这很。。。像联合国一样。这让人惊讶。此外,客户机通常位于不方便的位置(例如IIS主机进程)

这就给您留下了另外两个选择:

  • 您可以将两个DLL都放在GAC中。(请注意,这是运行
    regasm.com
    为com互操作注册程序集的一个单独步骤。)

  • 在COM中注册程序集时,可以添加
    regasm.exe
    /Codebase
    参数,该参数指定.NET应该记住要注册的DLL的位置,并在运行时在同一位置查找它

请记住,您必须对这两个程序集运行
regasm.exe
,以便在将运行它们的计算机上为COM互操作注册它们

删除“注册COM互操作”选项只意味着COM互操作中唯一可见的类是那些显式具有[ComVisible]属性的类。选中该选项后,COM兼容的每个类都将可见

但是抛出了一个自动化错误

自动化客户端中的错误报告通常非常糟糕。这是“这不是我的问题,给别人打电话”错误报告。Java吃微软午餐的一个重要原因。非常重要的是,首先要诊断根本原因来解决这个问题,这需要从.NET项目开始。在这种特殊情况下,很可能会导致此错误

选择ProjectA作为启动项目,然后选择项目>属性>调试选项卡。选择“启动外部程序”,并在“命令行参数”框中输入自动化客户端主机或测试程序的名称。使用调试>异常并勾选CLR异常的抛出复选框。按F5键启动客户机,当抛出异常时,调试器会介入,并向您显示出错的原因

ProjectA引用ProjectB-当ProjectA生成时,它复制ProjectB.dll

这不好,肯定会导致此问题。如果A确实依赖于B,它将只复制ProjectB。换句话说,您在实际制作能够独立运行的COM服务器的过程中失败了。您必须删除引用,现在将得到一个编译错误,显示此依赖关系是如何进入的

此依赖项将在运行时触发FileNotFoundException,CLR将不知道如何查找ProjectB.dll。它不在探测路径中。事实上,它可以找到ProjectA.dll并没有帮助,它从注册表中得到了这个提示

如果你不能打破对B的依赖,但你的目标是使B独立,而不是A,那么使用以下技术之一:

  • 使用ILMerge将ProjectB合并到ProjectA.dll中,以便只有一个文件
  • 在GAC中安装ProjectB,以便始终可以找到它。一般来说,COM服务器的正确方法是DLL地狱的好解决方案,尽管您不喜欢在自己的机器上使用它
  • 将ProjectB.dll复制到与自动化客户端的EXE相同的目录中。现在它处于探测路径中,并且总是可以找到。避免开发人员机器上的GAC的正确解决方法
  • 让ProjectA实现AppDomain.CurrentDomain.AssemblyResolve事件。您需要在订阅事件时使用一个好的触发器,该事件是保证由客户端创建的类的构造函数

Mat,这是Excel的吗?Excel自动化的行为与.NET不同。。。如果这是基于Excel的,请让我知道我想我知道