使用ExeCOMServer时,无法将类型为“...”的COM对象转换为接口类型“...”

时间:2012-05-25 08:20:32

标签: c# com interface casting

我正在使用这个exe com服务器:

https://cfx.svn.codeplex.com/svn/Visual%20Studio%202008/CSExeCOMServer/ExeCOMServer.cs

  • 我的编程是一个com应用程序
  • 我的另一个com对象的com方法是void Init(AppsScriptRunningContext rc);
  • 在这个方法中我尝试读出一个属性并得到此错误
  

无法转换类型的COM对象   'AppsScriptLib.AppsScriptRunningContextClass'到接口类型   'AppsScriptLib.IAppsScriptRunningContext'。此操作失败   因为QueryInterface调用COM组件的接口   由于IID'{4D2E5723-87C2-49C1-AA28-ED2D88275100}'失败   以下错误:不支持此类接口(来自HRESULT的异常:   0x80004002(E_NOINTERFACE))

如果我的应用程序不是com服务器而是普通的com应用程序,则没有错误。 这就是为什么我认为错误是由exe com服务器产生的。

https://cfx.svn.codeplex.com/svn/Visual%20Studio%202008/CSExeCOMServer/ExeCOMServer.cs

问候,克里斯

2 个答案:

答案 0 :(得分:7)

这是一个非常令人遗憾的代码示例,取得成功的可能性非常接近于零。它是MSDN论坛支持小组的产品,他们的工作未在Microsoft进行同行评审。一个团队成员later acknowledged认为这不是正确的方法。

该代码的一个问题是它完全忽略了注册服务的MSDN文档中的备注.RegisterTypeForComClients()方法:

  

请注意,不支持使用平台调用来调用非托管CoRegisterClassObject和CoDisconnectObject方法来注册和取消注册COM对象。

不幸的是,没有解释为什么它不受支持。关键问题是COM接口总是需要在进程外激活情况下进行封送。这是通过在客户端创建代理来完成的,该接口的实例具有与原始接口相同的所有方法,但其实现的方法通过RPC将方法的参数发送到其他进程。在服务器端,存根执行相同但相反的角色,使用方法参数构建堆栈帧并进行实际的方法调用。

在.NET中创建代理和存根非常简单,反射使其变得简单。由构建在框架中的Remoting管道完成。然而,它在COM中并不容易,它没有任何类似于反射的东西。它有两种基本的完成方式,首先是用IDL语言编写COM接口定义并用midl.exe编译它。这可以自动生成执行编组的C源代码,您可以从中构建DLL。然后需要在HKCR \ Interface注册表项中正确注册该DLL,以便COM可以在需要封送接口时查找并加载DLL。如果您的接口派生自IDispatch并将其自身限制为OLE自动化兼容的参数类型,则可以使用第二种方法。然后,您可以生成类型库并使用标准编组器。这需要注册类型库,以及HKCR \ Interface中的相应键,以便COM了解它。

这是.NET进程外服务器中不会​​发生的部分。您没有midl.exe来帮助您生成代理/存根DLL,并且您没有获得使用标准编组器的注册帮助。这是错误消息的真正含义,E_NOINTERFACE在这里真的意味着它找不到任何方法来编组接口。是的,糟糕的错误信息。

.NET中正式支持的创建进程外COM服务器的方法是将其注册到COM +。使用System.EnterpriseServices.ServicedComponent类作为基类。 MSDN库文章is here

答案 1 :(得分:1)

我建议在主线程中进行更改并帮助我!

在主线程中查找(主要在“Program.cs”中)[STAThread]行并将其更改为[MTAThread]。