0

For development, I use an out-of-process COM server contained in an EXE file without registering it. This works fine as long as the clients only use late binding and I start the server EXE before starting one single client. (The server registers a class factory, which then is used by the client.)

I know that this is a hack, and I know this can stop working with the next update of any OS component. I'm only doing this for development, not for testing, and definitely not for anything related to production.

However, using events doesn't work: The client reports a CONNECT_E_CANNOTCONNECT in the call to IConnectionPoint.Advise, i.e. when "subscribing" to the event.

How can I make this work?

Some details:

  1. I have an interface IFooEvents with GUID {111blah...}, and the client (according to Procmon) tries to look up HKCR\Interfaces\{111blah...}. If this key was present, it would contain:

    [HKEY_CLASSES_ROOT\Interface\{111blah...}]
    @="IFooEvents"
    
    [HKEY_CLASSES_ROOT\Interface\{111blah...}\ProxyStubClsid32]
    @="{00020420-0000-0000-C000-000000000046}"          <-- PSDispatch?
    
    [HKEY_CLASSES_ROOT\Interface\{111blah...}\TypeLib]
    @="{GUID of the server assembly}"
    "Version"="1.0"
    

    What's relevant here? Is it the PSDispatch, and if yes, is there a way I can provide this information at runtime?

My test client happens to be .NET, and uses dynamic to make sure late binding is used.

  1. Stack trace:

    System.Runtime.InteropServices.COMException: 'No such interface supported
    at System.Runtime.InteropServices.ComTypes.IConnectionPoint.Advise(Object pUnkSink, Int32& pdwCookie)
    at System.Dynamic.ComEventSink.Initialize(Object rcw, Guid sourceIid)
    at System.Dynamic.ComEventSink..ctor(Object rcw, Guid sourceIid)
    at System.Dynamic.ComEventSink.FromRuntimeCallableWrapper(Object rcw, Guid sourceIid, Boolean createIfNotFound)
    at System.Dynamic.BoundDispEvent.InPlaceAdd(Object handler)
    at System.Dynamic.BoundDispEvent.TryBinaryOperation(BinaryOperationBinder binder, Object handler, Object& result)
    at CallSite.Target(Closure , CallSite , Object , SomethingHappenedEventHandler )
    at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
    at Program.Main()
    
  2. .NET framework stepping fails, VS reports that it can't find Binder.cs, and I wasn't able to step through the code. Moreover, I couldn't find the source of any of the code in the stack trace.

  3. For the sake of completeness: Everything works fine when the COM server EXE file is registered.

If it's not possible, I'd appreciate to know why, simply to learn more about COM.

Martin
  • 1,986
  • 15
  • 32
  • COM engine usually calls QueryInterface on your classes (like IMarshal, etc.). 99% of the time, noone answers these calls, so the system uses default impl, but maybe you could provide information by this mean. Can you check what interfaces are asked? Otherwise, do you have a small reproducing project or step by step? – Simon Mourier Aug 05 '19 at 10:12
  • @SimonMourier Server is .NET as well, and that's why I don't know how to debug e.g. calls to QueryInterface. Any hints? Reproducing project would be several 100 lines, but the ideas are here: [Out of process with .NET](https://support.microsoft.com/en-us/help/977996/how-to-develop-an-out-of-process-com-component-by-using-visual-c-visua), [Events with .NET](https://stackoverflow.com/a/39703172) – Martin Aug 05 '19 at 11:00
  • A reproducing project is not to help understand the question, it's to make sure people are talking strictly about the same thing, devil's in the details, and most of all, speed up (or even initiate) the help process. – Simon Mourier Aug 05 '19 at 12:38
  • *"This works fine as long as the clients only use late binding..."* Herein lies the rub. When firing events, the server acts like a client (it calls the interface), and the client like a server (it implements the interface and accepts incoming calls). Since you don't want to register the interface, it would only work if the server uses late binding for firing events; that is, the event interface should be a dispinterface. – Igor Tandetnik Aug 06 '19 at 00:07
  • @IgorTandetnik I don't think I got the point of your comment. The server calls the event interface which is implemented by the client, ok. The event interface *must* be dispinterface, ok. "Late binding" == dispinterface, ok. So there is no reason why the server shouldn't be using dispinterface when calling the event? Am I missing something? – Martin Aug 06 '19 at 09:05

0 Answers0