I now have something that actually works. See below.

On 09-Aug-07 20:26, Thomas Heller wrote:
So I did it slightly different:

import comtypes.client as cc
import comtypes.gen.S7PROSIMLib as S7PS
class testVehikel:
    def __init__(self, progid, eventsClass):
        self.intf = cc.CreateObject(progid)
        self.cb = eventsClass
        cc.GetEvents(self.intf, self.cb, S7PS.IS7ProSimEvents)
        (...)
    (.... other methods ....)
    def __del__(self):
        (.... some cleaning up ....)
      
This runs, except that the __del__ method gets called before I expect it, and 
after it is called the other testVehikel  methods still run fine.
How is this possible?
    

This looks a little bit better.  Basically you do:

intf = cc.CreateObject(progid)
con = cc.GetEvents(intf, eventreceiver, event_interface)

The last parameter to GetEvents is optional, some COM objects expose enough
information so that comtypes can determine the default source interface itself.

Then, you have to keep the object that GetEvent() returns because when this object
goes away the advise connection is closed and cannot receive events any more.

Third, different from the pywin32 way, you pass an object as eventreceiver, NOT
a class.  The eventreceiver must have methods (event handlers) corresponding to the events that
it receives.  events that have no handlers are silently ignored.
  
Indeed, this code works fine (details, details... :-) ):

import comtypes.client as cc
import comtypes.gen.S7PROSIMLib as S7PS
class testVehikel:
    def __init__(self, progid, eventsClass):
        self.intf = cc.CreateObject(progid)
        self.rcvr = eventsClass()   ## just added () to assign an obj i.o. a class
        self.cb = cc.GetEvents(self.intf, self.rcvr, S7PS.IS7ProSimEvents)
        (....)

I do need the interface definition in GetEvents or I get:  "TypeError: cannot determine source interface". So be it.
Forth, comtypes has a useful function that will help exploring the events: ShowEvents().
This has the same signature and functionality as the GetEvents function, except that
you cannot pass the eventreceiver argument:  ShowEvents(obj [, interface]) constructs
a universal event receiver object itself.  This object will first simply print out
the event methods that it finds in the source interface, and then will print out
the event names and arguments when events are received.  Again, you must keep the
return value of the ShowEvents() call as long as you want to receive events.
  
I suppose I'll have to download the development version for that: version 0.2.1 seems not to have ShowEvents.
And finally, depending on the COM apartment your code runs in, and depending
on the COM object, you may need to run a windows MessageLoop so that events
are properly dispatched by COM.
  
I'll try that: right now some events seem to occur only when a corresponding dispatch routine is run, i.e. an event "Status changed" occurs if I call
"getStatus". I saw an example of how to do this in comtypes\test\test_ie.py.
What I wonder is how this message loop relates to the pywin message loop in which I currently run this code, or perhaps the wxPython message loop where this code will probably be running in later. BTW: the COM object resides in a DLL so I would think it runs in-process.

I final question:
What should the event routines look like? Currently they look like this:

class testCalls2:
    def ScanFinished(self, this, ScanInfo):
        print "Event: ScanFinished: ", ScanInfo
    (....)

on the basis of <clsid>.py, the result of GetMessage, saying this:

IS7ProSimEvents._methods_ = [
    COMMETHOD([helpstring(u'Fired when single scan is done.')], HRESULT, 
'ScanFinished',
              ( [], VARIANT, 'ScanInfo' )),
    (....)

I thought to have read somewhere that I need a (not further needed) 'this' 
argument. Should I do it like this or should the 'this' argument go?
So far I have not been able to trigger any of these routines and make them do 
their printing.
    


I think this is correct, the this parameter is needed
  
Almost correct. All event routines must return an integer, or I get this:

Traceback (most recent call last):
  File "source/callbacks.c", line 216, in 'converting callback result'
TypeError: int expected instead of NoneType instance
Exception  in <function func at 0x00EEF370> ignored

after which the thing continues happily.
At first I tried returning 0 (ERROR_SUCCESS) as the HRESULT , but this hangs up the code. Now I return 1 and it works fine.
The odd thing is that the methods in EventSink in comtypes\test\test_ie.py do not return anything. Is this a version problem (I use 0.2.1)?
So now the (working) event class looks like this:

class testCalls2:
    def ScanFinished(self, this, ScanInfo):
        print "Event: ScanFinished: ", ScanInfo
        return 1
    (.... more event functions ....)
Thomas
  
Thanks a million! I have something to build on now.
Len.
_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to