我在解决方案中有两个项目 - 比如ProjectA
和ProjectB
。这两个项目都注册了COM互操作,ProjectA
引用ProjectB
- 当ProjectA
构建时,它将ProjectB.dll
复制到其输出文件夹中。
现在,COM客户端需要访问ProjectB.tlb
。我尝试使用xcopy
将ProjectB
的输出文件夹中的类型库ProjectA
添加到ProjectB
中;一目了然,这样做 - COM客户端可以“看到”.tlb中的类型。
问题在于,只要COM客户端尝试调用.tlb中的方法,就会出现自动化错误。
我的直觉是.tlb需要在其使用的位置创建/注册,所以我取消选中xcopy
中的“注册COM互操作”框,删除了{{1}来自后期构建事件,并在regasm.exe /tlb
的构建后事件中添加了ProjectA
调用,以便在{{1}的输出文件夹中创建并注册ProjectB.tlb
} ...然后我清理并重建了解决方案。
同样的事情:COM客户端看到类型,但在尝试实际使用公开的API时会抛出自动化错误。
这两个项目原本是同一个。我们决定拆分它们,以便在我们发送ProjectA
的更新时,我们可以这样做,而不会引起引用ProjectA
中代码的COM客户端的兼容性问题。这个想法似乎非常好,但是......它甚至可能吗?如果是这样,怎么样?
或者将ProjectB
折回ProjectB
我唯一的希望是让COM客户端使用ProjectA
公开的COM API吗?
答案 0 :(得分:3)
TLB位置并不重要;它只是编译器带来的元数据的好处。它没有在运行时使用。但是,.NET必须能够在运行时找到程序集DLL,这可能很微妙。
.NET将尝试使用通常的Fusion探测规则来定位DLL,这些规则基于客户端进程EXE 的位置,而不是DLL的位置,或TLB的位置物。这基本上给你三个选择:
ProjectA.DLL
和ProjectB.DLL
复制到与客户端EXE相同的文件夹中。我不这样做,因为我发现它非常...... 类似于COM的。令人惊讶的是。此外,客户端通常位于不方便的位置(例如IIS主机进程)。
这给你留下了另外两个选择:
您可以将两个DLL放在GAC中。 (请注意,这是运行regasm.com
以注册COM互操作程序集的单独步骤。)
您可以在COM中注册程序集时添加/Codebase
regasm.exe
参数,该参数指定.NET应记住正在注册的DLL的位置,并在运行时查找它同一地点。
请记住,无论如何都必须使用两个程序集运行regasm.exe
,以便在将要运行它们的计算机上注册COM interop。
删除"注册COM互操作"选项只是意味着COM互操作可见的唯一类是明确具有[ComVisible]属性的类。选中该选项后,每个与COM兼容的类都将可见。
答案 1 :(得分:3)
但会引发自动化错误
自动化客户端中的错误报告通常很糟糕。这是"这不是我的问题,打电话给其他人"错误报告。 Java吃微软午餐的一个重要原因。通过诊断潜在原因以及需要从.NET项目开始,首先解决这个问题非常重要。在这种特殊情况下非常可能会导致此错误。
选择ProjectA作为启动项目,然后选择Project>属性>调试选项卡。选择"启动外部程序"并将自动化客户端主机或测试程序的名称放在"命令行参数"框。使用Debug>例外并勾选CLR异常的Thrown复选框。按F5启动客户端,调试器在抛出异常时进入,并显示出错的地方。
ProjectA引用ProjectB - 当ProjectA构建时,它会复制ProjectB.dll
这不好并且保证会导致此问题。如果A实际上对B具有依赖性,它将仅复制ProjectB。换句话说,您未能真正使COM服务器独立运行。您必须删除引用,现在您将收到一个编译错误,显示此依赖关系是如何进入的。
此依赖项将在运行时触发FileNotFoundException,CLR不知道如何查找ProjectB.dll。它不在探测路径中。它可以找到ProjectA.dll的事实没有帮助,它从注册表中得到了提示。
如果你不能打破对B的依赖,但你的任务是使B独立而不是A,那么使用以下技术之一: