none
Events fired from managed code to unmananged c++ client RRS feed

  • Question


  • If have seen a lot of samples as to how to have managed events firing to an unmanged VB client.  I have a c++ client so of course I can't find an example to help me understand what I am doing wrong.  Everything compiles.  It fails on trying to add my event handler saying my handler does not support a needed interface.  In the past (all unmanaged code), the client handler only had to support the event interface and IDispatch (if the event interface was not derived from IDispatch).  Somebody please tell me what interface I need to support and equally important...why it is different with a managed server versus unmanged server. Sample code would be great.  Thanks in advance.

    Managed server:
    // Interface definitions.
    namespace ClassLibrary2
    {
        public delegate void EventDelegate(string s);

        [ComVisible(true),
        InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
        public interface EventSinkClass
        {
            void EventDelegate(string s);
        }

        [ComVisible(true)]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface Interface1
        {
            string Foo { get; set; }
            void Bar(int x);
            event EventDelegate Event;
        }
    }


    // Server code
    namespace ClassLibrary2
    {
        [ComVisible(true),
        ClassInterface(ClassInterfaceType.None),
        ComSourceInterfaces(typeof(EventSinkClass))]
        public class Class1: Interface1
        {
            #region Interface1 Members
            public string Foo
            {
                get { ... }
                set { ... }
            }
            public void Bar(int x)
            {
                if (Event != null)
                    Event("Event");
            }
            public event EventDelegate Event;
            #endregion
        }
    }



    // Unmanged client

    // Client mainline code
    #import "C:\tmp\ClassLibrary2\bin\debug\classlibrary2.tlb" no_namespace raw_interfaces_only
        EventHandler handler;
        CComPtr<Interface1> inter1;
        HRESULT hr2 = CoCreateInstance( __uuidof( Class1 ), NULL, CLSCTX_INPROC_SERVER, __uuidof( Interface1 ), (void **)&inter1 );
    //  ****** Fails on the next line saying the handler (EventHandler) does not support an interface.
        hr2 = inter1->add_Event( &handler );
        hr2 = inter1->Bar( 10 );
        hr2 = inter1->remove_Event( &handler );

    // Supporting Event Handler class
    class EventHandler: public EventSinkClass
    {
        public:
            // IUnknown
            STDMETHOD_(ULONG, AddRef)()        { return 2; }
            STDMETHOD_(ULONG, Release)()    { return 1; }
            STDMETHOD(QueryInterface)( REFIID riid, void **ppvObject );

            // IDispatch
            STDMETHOD(GetTypeInfoCount)(unsigned int *pn) {    *pn = 1; return S_OK;}
            STDMETHOD(GetTypeInfo)(unsigned int index, LCID lcid, ITypeInfo **pTypeInfo)
                { if ( index != 0 )    return DISP_E_BADINDEX;    *pTypeInfo = NULL;    return E_NOTIMPL;}
            STDMETHOD(GetIDsOfNames)( REFIID riid, LPOLESTR *rgszNames,
                UINT cNames, LCID lcid, DISPID *rgdispid)    { return E_NOTIMPL; }
            STDMETHOD(Invoke)( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags,
                DISPPARAMS *pdispParams, VARIANT *pVarResult, EXCEPINFO *pei, UINT *puArgErr);
    };
    HRESULT EventHandler::QueryInterface(REFIID iid, void **ppUnk)
    {
        if ( iid == IID_IUnknown )
            *ppUnk = this;
        else if ( iid == __uuidof(EventSinkClass))
            *ppUnk = this;
        else
        {
            *ppUnk = NULL;
            return E_NOINTERFACE;
        }
        ((IUnknown *)(*ppUnk))->AddRef();
        return S_OK;
    }
    // IDispatch

    HRESULT tEventHandler::Invoke( DISPID dispid, REFIID riid, LCID lcid, WORD wFlags,
        DISPPARAMS *pdispParams, VARIANT *pVarResult, EXCEPINFO *pei, UINT *puArgErr)
    {
        //Winner....winner... chicken dinner...... If we can ever get this far!!!!
        return E_NOTIMPL;
    }




    Tuesday, March 18, 2008 1:56 AM

Answers


  • Where to start with where I went wrong......
    1. Do not declare your event inside of your interface.  I believe this was left over prior to my understanding of of what ComSourceInterfaces does for me.  By doing this, you effectively add methods to connect and disconnect to your event instead of using the IConnectionPoint and IConnectionPointContainer interfaces.  This might work but it is not the traditional COM people are us to with their unmanaged code.  I switch my client to use AtlAdvise and AtlUnadvise.

    2.  The .Net server will be calling the GetIDsOfNames method of your event handler.  Make sure it work (and not stubbed out like mine was) otherwise it fail while trying to fire the event and your Invoke will never be called.

    3.  Make sure your event name in your class matches the name of the method in your EventSinkInterface.  If not, it will not connect when you do an ATLAdvise.

    I guess all I needed was more time.  Hope I did not confuse anyone.

    Tuesday, March 18, 2008 4:39 PM