我有一个第三方组件,比如说FIPreviewHandler来处理预览,它实现了IPreviewHandler。FIPreviewHandler作为托管组件实现,并通过互操作的方式使用IPreviewHandler接口和相关接口。使用regasm.exe将FIPreviewHandler注册为COM。
我有一个客户端应用程序,它也是托管的。我想在我的应用程序中创建一个FIPreviewHandler实例作为COM组件。
我有一个定义IPreviewHandler和相关接口的互操作程序集。
当我使用Activator.CreateInstance()在GetTypeByCLSID()返回的类型上创建FIPreviewHandler的实例时,它为FIPreviewHandler返回了正确的CLSID,它返回一个托管实例,因为它有可用的实际程序集,并跳过COM。当我尝试将此实例QI/强制转换为任何接口时,例如IPreviewHandler,它返回null,因为它是作为托管对象加载的,虽然由FIPreviewHandler实现的IPreviewHandler接口与我在互操作中拥有的接口相同,但它位于不同的命名空间/程序集中,因此返回null。如果它向我返回一个COM实例/RCW (System.__ComObject),它将不会考虑命名空间,并且会转换良好,并返回一个有效实例。
FIPreviewHandler是一个32位组件,在64位的Win7机器上,如果我将我的客户端应用程序编译为"Any CPU",Activator.CreateInstance()会返回一个COM实例/RCW (System.__ComObject),因为它找不到64位的FIPreviewHandler实现,因此返回一个代理。在这种情况下,我的应用程序工作得很好。但当我为x86编译它时,它得到32位实现,并返回实际托管类的托管实例,而不是COM实例,因此失败。
我不能使用在FIPreviewHandler的程序集中定义的接口,因为我必须为IPreviewHandler编写一个通用客户端,并且我的应用程序可以与实现IPreviewHandler的任何组件一起工作,这对于作为COM对象访问FIPreviewHandler的基于C++的客户端非常有效,但是对于托管客户端是失败的。
我希望我说的有道理,我真的很感激任何帮助。
发布于 2011-04-24 20:12:42
我的经验是,微软是故意这样做的。他们不希望您的两个托管代码程序集通过COM进行通信。如果您尝试在项目中添加支持COM作为COM引用的程序集,则会出现同样的错误。
如果COM接口是获得所需功能的唯一方法,则非托管包装应该可以做到这一点。用C++或VB6 (或任何对COM友好的非托管语言)编写一个新的COM服务器,它包装了您的第三方托管COM服务器。然后,将此新包装DLL作为COM服务器添加到托管代码项目中。
发布于 2011-04-27 09:12:46
使用PInvoke调用COM函数CoCreateInstance(Ex),并将互操作程序集中定义的CLSID和IPreviewHandler的IID传递给它。这样,.NET就没有机会进行干预了。
你说你有一个互操作程序集。如果这是由第三方程序集的作者分发的PIA,这是最好的,但如果您必须自己构建它,也没问题。(PIA不必在GAC中注册,尽管它们通常是注册的。)您可以通过在IL反汇编程序中加载互操作程序集并查找类的System.Runtime.InteropServices.GuidAttribute属性来获取CLSID。
https://stackoverflow.com/questions/3119596
复制相似问题