使用ExeCOMServer时无法将类型为'...'的COM对象强制转换为接口类型'...'

4

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

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

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

无法将类型为“AppsScriptLib.AppsScriptRunningContextClass”的COM对象强制转换为接口类型“AppsScriptLib.IAppsScriptRunningContext”。此操作失败,因为针对具有IID'{4D2E5723-87C2-49C1-AA28-ED2D88275100}'的接口的COM组件的QueryInterface调用由于以下错误而失败:没有支持此类接口(HRESULT的异常0x80004002(E_NOINTERFACE))。

如果我的应用程序不是一个com服务器而是一个普通的com应用程序,则不会出现错误。这就是为什么我认为该错误是由exe com服务器产生的原因。

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

问候,克里斯


错误非常明显。您将对象声明为“AppsScriptLib.IAppsScriptRunningContext”,而不是当前类型。请更新您的问题并将代码内联到问题中,谢谢。 - Security Hound
1
@Ramhound:正如masterchris_99所说,应用程序运行良好,问题似乎出在ExeCOMServer上。也许这取决于COMObject的注册... - Aykut Çevik
代码库项目是否标记为com-visible?否则,当您使用installUtil.exe进行注册时,它将不会创建com接口。 - YvesR
你有更完整的示例代码(包括IAppsScriptRunningContext def等)吗? - Simon Mourier
2个回答

8
这是一个非常令人遗憾的代码示例,成功的几率非常接近于零。它是MSDN论坛支持小组的产品,他们的工作没有在Microsoft进行同行评审。其中一名团队成员后来承认这不是正确的方法。
该代码存在问题,完全忽略了RegistrationServices.RegisterTypeForComClients()方法在MSDN文档中的备注:

请注意,不支持使用平台调用调用未管理的CoRegisterClassObject和CoDisconnectObject方法来注册和注销COM对象。

很遗憾,没有解释为什么不支持。关键问题在于,在进程外激活的情况下,COM接口总是需要进行编组。这是通过在客户端创建一个代理来完成的,该代理是接口的实例,具有与原始接口相同的所有方法,但其实现的方法通过RPC将方法的参数发送到另一个进程。在服务器端,存根执行相同但相反的角色,使用方法参数构建堆栈帧并进行实际的方法调用。
在.NET中创建代理和存根非常容易,反射使其变得简单。由框架内置的Remoting管道完成。但是,在COM中,这并不容易,它没有任何类似于反射的东西。有两种基本方法可以完成此操作,首先是使用IDL语言编写COM接口定义,并使用midl.exe进行编译。这可以自动生成执行从中构建DLL所需的编组的C源代码。然后需要正确注册该DLL以便COM能够在需要编组接口时找到并加载该DLL。如果您的接口派生自IDispatch并限制自己于OLE Automation兼容的参数类型,则可以使用第二种方法。然后可以生成类型库并使用标准的编组器。这需要注册类型库以及HKCR\Interface中适当的键,以便COM知道它。

这是.NET进程外服务器中没有发生的部分。您没有midl.exe来帮助您生成代理/存根DLL,也没有获得使用标准编组器的注册帮助。这就是错误消息实际上在说什么,E_NOINTERFACE在这里确实意味着它找不到任何编组接口的方法。是的,糟糕的错误消息。

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

谢谢,但是使用COM+时我需要使用强名称。但由于使用了许多没有强名称的引用,在相应的上下文中这不是一个选项。 - masterchris_99
嗯,强命名程序集相当琐碎。这是COM服务器的通用要求,DLL地狱是不容忽视的。听起来你正在自说自话,而错过了实际执行此操作的好选择。 - Hans Passant
请告诉我如何签署现有的外部 C++ COM 组件?我没有选项将已签名的外部组件部署到其他客户端。 - masterchris_99
一个C++组件?我以为你是在尝试用.NET做这个。抱歉,我不知道你在说什么。我建议你提出另一个关于它的问题,并记录下你所采取的确切步骤和错误信息。 - Hans Passant

2

我得到了一个建议,在主线程中进行更改,这对我很有帮助!

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接