title: C# Running Active Automation Object - How to Source events?
body: <p>I have a (long running) console application, written in C#, which I want to be able to manipulate through COM (so no InProc DLLs and regasm.exe). <code>IDispatch</code> is all I need - so a classic OLE Automation object.</p>
  
  <p>Here I'll present a minimal version of what I try to do. I've defined a COM class like this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>[ComVisible(true)]
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  [Guid("9009311a-c0b2-42a4-8e7c-f42091d71594")]
  public interface ITestEvents {
      void OnEvent();
  }
  
  [ComVisible(true)]
  [ClassInterface(ClassInterfaceType.AutoDispatch)]
  [ComSourceInterfaces(typeof(ITestEvents))]
  public class ComClass {
      public event Action OnEvent;
  
      public int Test() {
          return 100;
      }
  }
  </code></pre>
  
  <p>In <code>Main()</code> I simply register the object in the Running Object Table (ROT) with <code>"comTestApp"</code> Moniker and sleep the application.
  You can see the full source <a href="https://pastebin.com/eYfaWDbG" rel="nofollow noreferrer">here</a>.</p>
  
  <p>This works just fine when I try to invoke the object's methods. For example, this VBScript works OK:</p>
  
  <pre class="lang-vb prettyprint-override"><code>Set obj = GetObject("comTestApp")
  WScript.Echo obj.Test() Rem prints 100
  </code></pre>
  
  <p>But when I try to connect the events:</p>
  
  <pre class="lang-vb prettyprint-override"><code>Set obj = GetObject("comTestApp")
  WScript.Echo obj.Test() Rem Works
  
  WScript.ConnectObject obj, "obj_" Rem Fails
  
  Sub obj_OnEvent
      WScript.Echo "Wish it worked"
  End Sub
  </code></pre>
  
  <p>I get error on calling <code>ConnectObject</code> (error 0x80020009 "Could not connect object").</p>
  
  <p>The same code (only the class GUID/ProgID have to be added) works if I register the assembly as InProc object with regasm.exe but I don't need that. I need access to the running application and that's why I use the ROT.</p>
  
  <p>I created a simple C++ test to see if I can find out more about the problem. The source is <a href="https://pastebin.com/879FCkeR" rel="nofollow noreferrer">here</a>. I have written a minimal COM object implementing the <code>IDispatch</code> interface which should act as the Event Sink. First I get the object from the ROT, query for the <code>IConnectionPointContainer</code>, then get <code>IConnectionPoint</code> for <code>ITestEvents</code>'s IID and finally call its <code>Advise()</code> method. As with VBScript, it fails (although I get another error - 0x80040202). I placed a breakpoint on the <code>QueryInterface</code> method of the event sink to see what happens when <code>Advise()</code> is called. I can see that <code>QueryInterface</code> is called for various interfaces and finally it requests my <code>ITestEvents</code>, which I return and set status <code>S_OK</code>. But still, the <code>Advise()</code> method returns the above error.</p>
  
  <p>I have also tried another thing: I've set the GUID of the <code>ITestEvents</code> to <code>{00020400-0000-0000-C000-000000000046}</code> which is the IID of <code>IDispatch</code>. And now <code>Advise()</code> returns <code>S_OK</code>! I have even simulated an event and the <code>Invoke()</code> method of the event sink gets called! Alas this does not solve the problem in general. If you request it directly from <code>IConnectionPointContainer</code> by IID - you get it, but it seems it is not properly enumerated by <code>ITypeInfo</code> and VBScript still does not work.</p>
  
  <p>I have almost no experience with COM so I'm not sure where to go from here. The fact that if I use the <code>IDispatch</code> IID makes it work, makes me wonder if some custom Marshaling is needed for the <code>ITestEvents</code> interface, although it is pure <code>IDispatch</code> so I think it should be handled well by the runtime.</p>
  
  <p>Thank you!</p>