Search code examples
c#cominterfacecasting

Unable to cast COM object of type '...' to interface type '...' while using an ExeCOMServer


I'm using this exe com server:

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

  • my prog is a com app
  • my com method which take another com object is void Init(AppsScriptRunningContext rc);
  • in this method I try to read out an property and get this error

Unable to cast COM object of type 'AppsScriptLib.AppsScriptRunningContextClass' to interface type 'AppsScriptLib.IAppsScriptRunningContext'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{4D2E5723-87C2-49C1-AA28-ED2D88275100}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))

If my app is not a com server but a normal com app there is no error. Thats why I think the error is produced by the exe com server.

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

Regards, Chris


Solution

  • That's a very regrettable code sample, the odds of having success with it are very close to zero. It is a product of the MSDN forums support group and their work isn't being peer-reviewed at Microsoft. One team member later acknowledged that this is not the correct way to do it.

    An issue with that code is that it completely ignores the Remark in the MSDN documentation for RegistrationServices.RegisterTypeForComClients() method:

    Note that using platform invoke to call the unmanaged CoRegisterClassObject and CoDisconnectObject methods for registration and unregistration of COM objects is not supported.

    Unfortunately without explaining why it isn't supported. The key problem is that a COM interface always needs to be marshaled in an out-of-process activation case. This is done by creating a proxy at the client side, an instance of the interface that has all the same methods as the original interface but whose implemented methods send the arguments of the method to the other process through RPC. At the server side, a stub performs the same but opposite role, building a stack frame with the method arguments and making the actual method call.

    Creating the proxy and the stub is pretty easy in .NET, reflection makes it simple. Done by the Remoting plumbing built into the framework. It is however not easy in COM, it doesn't have anything similar to reflection. There are two basic ways it gets done, firstly by writing the COM interface definitions in the IDL language and compiling it with midl.exe. Which can automatically generate the C source code that does the marshaling from which you can build a DLL. That DLL then needs to be registered properly in the HKCR\Interface registry key so that COM can find and load the DLL whenever the interface needs to be marshaled. A second way is available if your interface is derived from IDispatch and limits itself to OLE Automation compatible argument types. You can then generate a type library and use the standard marshaller. This requires the type library to be registered, along with appropriate keys in HKCR\Interface so COM knows about it.

    That's the part that doesn't happen in a .NET out-of-process server. You don't have midl.exe to help you generate the proxy/stub DLL and you don't get the registration help to use the standard marshaller. Which is what the error message is really saying, E_NOINTERFACE here really means that it couldn't find any way to marshal the interface. Yes, crappy error message.

    The officially supported way in .NET to create an out-of-process COM server is to register it with COM+. Using the System.EnterpriseServices.ServicedComponent class as a base class. The MSDN library article is here.