none
Event Handling IDispatch::Invoke() Implementation of the CLR. RRS feed

  • Question

  • Hello all,

    1. I have recently made a report to Microsoft Connect regarding a possible bug in the CLR code that handles COM events fired from unmanaged COM servers :

    Microsoft Connect

    2. Since then, I have been doing research on the internals of the flow of event firing from an unmanaged COM server's IDispatch::Invoke() method call right down to the invokation of the managed object's event handler delegate function.


    3. I have managed to find some interesting information about a ComEventsSink class from :

    COMEventsSink.cs

    4. This class provides an implementation for IDispatch and is used by the ComEventsHelper and the ComEventsInfo classes. Its Invoke() method provided very good info to me and there is a hint on why an event method which takes a  SAFEARRAY reference parameter winds up returning E_INVALIDARG (an ArgumentException exception is thrown).

    5. I also had a look at the *_SinkHelper class declared in the disassembled IL code of the interop assembly generated by tlbimp.exe for an unmanaged COM server. I see that it directly calls the Invoke() method of the delegate with no reference to any ComEventsSink object.

    6. It is pretty clear that there must be some IDispatch implementation behind the SinkHelper class that gets called by the COM server event firing code.

    7. Since the SinkHelper class is derived from System.Object, I believe that the SinkHelper probably inherits this IDispatch implementation of the System.Object class.

    9.It is also possible that System.Object may internally use the ComEventsSink class to handle COM events.

    10. I was wondering if anyone has any knowledge of this IDispatch implementation ?

    11. Thanks, all.


    - Bio.



    Please visit my blog : http://limbioliong.wordpress.com/


    • Edited by Lim Bio Liong Sunday, July 10, 2016 10:55 AM Created hyperlinks for the web sites.
    Sunday, July 10, 2016 10:50 AM

All replies

  • Hi Bio,

    >>"I was wondering if anyone has any knowledge of this IDispatch implementation ? "

    I also can't find the implement on Microsoft reference source site. In COM, invoke method internally uses GetIDsOfNames. I think .NET will do the same. There is a thread on Stack Overflow which show us how to use IDispatch interface in C#.

    Calling a member of IDispatch COM interface from C#

    Best Regards,
    Li Wang


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, July 11, 2016 9:11 AM
    Moderator
  • Hello DotNetWang,

    1. Thanks for your reply.

    2. My COM server is written in ATL. The problem I am having are two-fold (as described in my Microsoft Connect report) :

    • I keep receiving E_INVALIDARG for the HRESULT return code of my call to IDispatch::Invoke() in my event firing code.
    • My SAFEARRAY parameter (passed by reference to the event) is not updated on return.

    3. At this time, I suspect that the ComEventsSink class is likely used internally by the CLR to handle COM events fired from unmanaged servers since it would not make sense to have 2 sets of source codes both intended to perform the same functionality.

    4. Take a look at the ComEventsSink class. It provides an implementation of IDispatch::Invoke() from which I noted that Variant::CopyFromIndirect() is called (near the end of the function).

    5. Variant::CopyFromIndirect() is called for VARIANTS in the DispParams which have been passed by reference.

    6. The source codes for Variant::CopyFromIndirect() is also provided at the reference source site. In the function, there is a switch statement in which the Variant Type is evaluated and we see that if the VT is VT_ARRAY, the default part takes effect :

                switch (vt) {
                    case VarEnum.VT_I1:
                        *(sbyte*)this._typeUnion._unionTypes._byref = (sbyte)value;
                        break;            
                    ...
                    ...
                    ...
                    default:
                        throw new ArgumentException("invalid argument type");
                }

    An ArgumentException is thrown.

    7. If ComEventsSink and/or the Variant class is currently used by the CLR, this is the likely cause of the E_INVALIDARG return code.

    8. However, my observations above are anecdotal and remain speculative.

    9. Thanks for your help, DotNetWang.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Monday, July 11, 2016 11:00 AM
  • Hello DotNet Wang,

    1. After some experimentation, I have emerged 2 viable workarounds for the problem that I faced concerning passing a referenced SAFEARRAY (i.e. SAFEARRAY**) from an unmanaged COM server event to a managed C# event handler.

    2. The first workaround passes the SAFEARRAY via a referenced VARIANT. This worked well. I have documented this in my blog in case you are interested :

    Passing a Reference to a SAFEARRAY as Parameter to a Managed COM Event Handler Part 2.

    3. The second workaround involves the use of the ICustomQueryInterface interface to enable a custom implementation of the IDispatch interface in C#. This works very well and allows for very refined control over the event handling process in managed code.

    4. I am currently writing a blog on this.

    5. At this time, I have a feeling that the default CLR IDispatch implementation for COM event handling (in managed code) is probably a thin wrapper that ultimately uses Reflection to invoke event delegates.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Tuesday, July 26, 2016 4:49 PM