[python-win32] Help Needed on Handling Events from a Proprietary COM Object

Darren McElfresh dmcelfresh at yahoo.com
Wed Feb 29 15:01:42 CET 2012


Thanks for your help on this!

I expect an "event" to make a callback on my event handler.

I updated my code to not utilize getevents, since I'm using DispatchWithEvents, and removed my call to MsgWaitForMultipleObjects and updated the call to PumpWaitingMessages in a loop, to just be PumpMessages; however it still doesn't seem to work.

So at this point I basically have:
    class Events():
        def OnChange(self, e=defaultNamedNotOptArg):
            ....
        ....
    event_source = view.newItemEventSource( server.typeForName(server.TypeNames.CHANGEREQUEST) )
    event_monitor = win32com.client.DispatchWithEvents( event_source, Events )

    pythoncom.PumpMessages()


The C++ code snippets are the following
    class CMyListener :
        // _StItemSink is the default source (outgoing) dspinterface for 
        // StItemEventSource objects. 
        public IDispatchImpl<_IStItemSink, &DIID__IStItemSink, &LIBID_StarTeam>,
        public CComObjectRoot
    {
    public:
        CMyListener() {}
    BEGIN_COM_MAP(CMyListener)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(_IStItemSink)
    END_COM_MAP()

    ....
        // _IStItemSink is a dspinterface.
        // We must implement IDispatch::Invoke().
        STDMETHOD(Invoke)(    DISPID dispIdMember, 
                            REFIID riid, LCID lcid, 
                            WORD wFlags, 
                            DISPPARAMS FAR* pDispParams, 
                            VARIANT FAR* pVarResult, 
                            EXCEPINFO FAR* pExcepInfo, 
                            unsigned int FAR* puArgErr )
        {
            ....
        }

    ....

        // Create the event source for CHANGEREQUEST items.
        CComPtr<IStItemEventSource> source;
        hr = stView->newItemEventSource(type, &source);
        if (!VerifyHR(hr, IID_IStView, stView)) {
            return(false);
        }
    
        // The event source is the connection point container.
        CComPtr<IConnectionPointContainer> cpc;
        hr = source->QueryInterface(IID_IConnectionPointContainer, (void**)&cpc);
        if (!VerifyHR(hr, IID_IStItemEventSource, source)) {
            return(false);
        }
    
        // Find the connection point for Item events.
        // We save it so that we can call IConnectionPointContainer::Unadvise() later.
        hr = cpc->FindConnectionPoint(DIID__IStItemSink, &m_cp);
        if (!VerifyHR(hr, IID_IConnectionPointContainer, cpc)) {
            return(false);
        }
    
        // Instantiate our listener.
        CComObject<CMyListener>* listener = NULL;
        hr = CComObject<CMyListener>::CreateInstance(&listener);
        if (!VerifyHR(hr)) {
            return(false);
        }
    
        // Slip in a pointer to the parent dialog.
        listener->m_dlg = this;
    
        // Connect the listener.
        // We save the cookie so that we can call IConnectionPointContainer::Unadvise() later.
        hr = m_cp->Advise(listener, &m_cookie);
        if (!VerifyHR(hr, IID_IConnectionPoint, m_cp)) {
            return(false);

    

Any ideas on what I'm missing?  Is it that the object is an Dispatch Interface, and so I'm not handling that correctly?

Thanks,
Darren




________________________________
 From: Mark Hammond <skippy.hammond at gmail.com>
To: Darren McElfresh <dmcelfresh at yahoo.com> 
Cc: "python-win32 at python.org" <python-win32 at python.org> 
Sent: Tuesday, February 28, 2012 5:15 PM
Subject: Re: [python-win32] Help Needed on Handling Events from a Proprietary COM Object
 
On 29/02/2012 8:26 AM, Darren McElfresh wrote:
> I’ve read through numerous posts on how to get this to work, but I’ve
> realized it is time to ask for help.
> In general I have a COM object that returns an event handler:
> /event_source = com_object.newEventSource( arg_data )/
> I’ve tried establishing the connection points necessary by creating an
> event class derived on the sink co-class of this event source:
> /class Events(win32com.client.getevents(COM_LIB.CLSID)):/
> I included all of the methods that were mentioned in the generated code
> from makepy.From there I tried to utilize DispatchWithEvents to connect
> the listener:
> /event_monitor = win32com.client.DispatchWithEvents( event_source, Events )/

Using DispatchWithEvents means you shouldn't need to use getevents manually at all - it does the getevents for you.  So just defining your Events class without a base-class should work - check out the docstring for DispatchWithEvents.

> Everything seems fine at this point, but when I use try to listen it
> never seems to fire:
> /rc = win32event.WaitForSingleObject( event_monitor.event, TIME )/

What is event_monitor.event?  I guess it must be an integer event handle, but it is worth checking it is sane.  Also, that doesn't really make sense as an event sink - presumably you have referenced the 'event' attribute before an event has fired, so the actual firing of an event doesn't seem to need to do anything - it just sets the handle object and wouldn't need to make a callback into your handler.  Generally the firing of an event will explicitly call a method you supply, but that doesn't seem to be the case here.

Even if that was "normal" for your object, you might need MsgWaitForMultipleObjects - a message loop way well be needed to deliver the event calls (ie, so the event handler functions can be called).

> I’ve even tried (even though I don’t think it is necessary for single
> threaded applications):
> /pythoncom.PumpWaitingMessages()/

A single threaded application will have to do *something* while it is waiting for the events to fire, so unless you are in a UI like pythonwin, you *will* need something like PumpMessages - otherwise your thread will just terminate.  PumpWaitingMessages only pumps what is queued now - you need PumpMessages to pump "forever" - or until you call PostQuitMessage to kill the pump, presumably in response to a future event)

But I'm missing something - either you expect an "event" to set a Windows event handle (and therefore probably need MsgWaitForMultipleObjects) or you expect an "event" to make a callback on your event handler (in which case you need something like PumpMessages) - but the 2 scenarios are quite different depending on what is expected to happen.

> However that didn’t seem to have any impact either.No matter what I try
> – I can’t get my handlers to fire.I have sample code on how to do this
> in C++, and I have already taken the sample Java code and have my own
> version of that working; however I’d prefer to use Python if I can get
> it to work.
> I can provide my code (or the samples), but it is somewhat lengthy so I
> was hoping someone would see what I was missing right away?

Maybe you could just provide a summary of the relevant C++ code?

Mark
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-win32/attachments/20120229/b20187b1/attachment-0001.html>


More information about the python-win32 mailing list