Hi, I am trying to apply the Siemens S7ProSim Automation object using Python. However, after running makepy my test script fails. I have done some digging into DispatchWithEvents, makepy and MSDN. It turns out that the event interface seems not to be included in the result file from makepy, while the vtable for the same is. This causes calls to DispatchWithEvents to fail.
I ran the MS ITypelib viewer over the dll, and also makepy. Here are the results. For reference, from the OLE Viewer (some details left out): -------------------------------------------- // typelib filename: s7wspsmx.dll [ uuid(83CC0D80-FEDA-11D1-BE76-0060B06816CF), version(1.0), helpstring("Siemens S7ProSim COM Object") ] library S7PROSIMLib { // Forward declare all types defined in this typelib interface IS7ProSimEvents; interface IS7ProSim; [ odl, uuid(83CC0D82-FEDA-11D1-BE76-0060B06816CF), helpstring("Event interface for S7ProSim COM Object"), oleautomation ] interface IS7ProSimEvents : IUnknown { [helpstring("Fired when single scan is done.")] HRESULT _stdcall ScanFinished(VARIANT ScanInfo); [helpstring("Fired when unable to connect to Control Engine.")] HRESULT _stdcall ConnectionError( BSTR ControlEngine, long Error); [helpstring("Fired when a new PLC switch state is detected.")] HRESULT _stdcall PLCSimStateChanged(BSTR NewState); [helpstring("Fired when a Pause/Continue state change is detected.")] HRESULT _stdcall PauseStateChanged(BSTR NewState); [helpstring("Fired when a ScanMode change is detected.")] HRESULT _stdcall ScanModeChanged(BSTR NewState); }; [ uuid(83CC0D83-FEDA-11D1-BE76-0060B06816CF), helpstring("S7ProSim Class") ] coclass S7ProSim { [default] interface IS7ProSim; [default, source] interface IS7ProSimEvents; }; [ odl, uuid(83CC0D81-FEDA-11D1-BE76-0060B06816CF), helpstring("IS7ProSim Interface for S7ProSim COM Object"), dual, oleautomation ] interface IS7ProSim : IDispatch { (.... dispatchable functions ....) }; (.... constant declarations ....) }; For reference, from '83CC0D80-FEDA-11D1-BE76-0060B06816CFx0x1x0.py' (some details left out): ------------------------------------------------------------------------------ # -*- coding: mbcs -*- # Created by makepy.py version 0.4.95 # By python version 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)] # From type library 's7wspsmx.dll' # On Wed Jul 18 17:55:20 2007 """Siemens S7ProSim COM Object""" makepy_version = '0.4.95' python_version = 0x20400f0 (....) CLSID = IID('{83CC0D80-FEDA-11D1-BE76-0060B06816CF}') MajorVersion = 1 MinorVersion = 0 LibraryFlags = 8 LCID = 0x0 class constants: (....) from win32com.client import DispatchBaseClass class IS7ProSim(DispatchBaseClass): """IS7ProSim Interface for S7ProSim COM Object""" CLSID = IID('{83CC0D81-FEDA-11D1-BE76-0060B06816CF}') coclass_clsid = IID('{83CC0D83-FEDA-11D1-BE76-0060B06816CF}') (.... dispatchable functions ....) from win32com.client import CoClassBaseClass # This CoClass is known by the name 'S7wspsmx.S7ProSim.1' class S7ProSim(CoClassBaseClass): # A CoClass # S7ProSim Class CLSID = IID('{83CC0D83-FEDA-11D1-BE76-0060B06816CF}') coclass_sources = [ ] coclass_interfaces = [ IS7ProSim, ] default_interface = IS7ProSim IS7ProSim_vtables_dispatch_ = 1 IS7ProSim_vtables_ = [ (.... dispatchable funtions table entries ....) ] IS7ProSimEvents_vtables_dispatch_ = 0 IS7ProSimEvents_vtables_ = [ (( 'ScanFinished' , 'ScanInfo' , ), 1, (1, (), [ (12, 0, None, None) , ], 1 , 1 , 4 , 0 , 12 , (3, 0, None, None) , 0 , )), (( 'ConnectionError' , 'ControlEngine' , 'Error' , ), 2, (2, (), [ (8, 0, None, None) , (3, 0, None, None) , ], 1 , 1 , 4 , 0 , 16 , (3, 0, None, None) , 0 , )), (( 'PLCSimStateChanged' , 'NewState' , ), 3, (3, (), [ (8, 0, None, None) , ], 1 , 1 , 4 , 0 , 20 , (3, 0, None, None) , 0 , )), (( 'PauseStateChanged' , 'NewState' , ), 4, (4, (), [ (8, 0, None, None) , ], 1 , 1 , 4 , 0 , 24 , (3, 0, None, None) , 0 , )), (( 'ScanModeChanged' , 'NewState' , ), 5, (5, (), [ (8, 0, None, None) , ], 1 , 1 , 4 , 0 , 28 , (3, 0, None, None) , 0 , )), ] RecordMap = { } CLSIDToClassMap = { '{83CC0D81-FEDA-11D1-BE76-0060B06816CF}' : IS7ProSim, '{83CC0D83-FEDA-11D1-BE76-0060B06816CF}' : S7ProSim, } CLSIDToPackageMap = {} win32com.client.CLSIDToClass.RegisterCLSIDsFromDict( CLSIDToClassMap ) VTablesToPackageMap = {} VTablesToClassMap = { '{83CC0D81-FEDA-11D1-BE76-0060B06816CF}' : 'IS7ProSim', '{83CC0D82-FEDA-11D1-BE76-0060B06816CF}' : 'IS7ProSimEvents', } NamesToIIDMap = { 'IS7ProSimEvents' : '{83CC0D82-FEDA-11D1-BE76-0060B06816CF}', 'IS7ProSim' : '{83CC0D81-FEDA-11D1-BE76-0060B06816CF}', } win32com.client.constants.__dicts__.append(constants.__dict__) ----------end of listings --------------------------------------------------------------- Note the differences between these listings in the definition of CoClass IS7ProSim, repeated here for convenience: Ole Viewer: [ uuid(83CC0D83-FEDA-11D1-BE76-0060B06816CF), helpstring("S7ProSim Class") ] coclass S7ProSim { [default] interface IS7ProSim; [default, source] interface IS7ProSimEvents; }; makepy class S7ProSim(CoClassBaseClass): # A CoClass # S7ProSim Class CLSID = IID('{83CC0D83-FEDA-11D1-BE76-0060B06816CF}') coclass_sources = [ ] coclass_interfaces = [ IS7ProSim, ] default_interface = IS7ProSim OLE Viewer finds a second interface IS7ProSimEvents that is made the default source makepy does not recognise IS7ProSimEvents as an interface at all. Running my (test) script yields this: ---------------------- import win32com.client as w32c sS7PROSIM = 'S7wspsmx.S7ProSim.1' class testCalls: (.... class definition with event functions ....) obj = w32c.DispatchWithEvents(sS7PROSIM, testCalls) Result: File "C:\Python24\Lib\site-packages\win32com\client\__init__.py", line 263, in DispatchWithEvents raise ValueError, "This COM object does not support events." ValueError: This COM object does not support events. In file "C:\Python24\Lib\site-packages\win32com\client\__init__.py", line 261-263: events_class = getevents(clsid) if events_class is None: raise ValueError, "This COM object does not support events." get_events(clsid) seems to return None. The clsid given to getevents is "IID('{83CC0D81-FEDA-11D1-BE76-0060B06816CF}')" This is the clsid for the IS7ProSim, derived from IDispatch. In file "C:\Python24\Lib\site-packages\win32com\client\__init__.py", line 323-376: def getevents(clsid): (....) # find clsid given progid or clsid clsid=str(pywintypes.IID(clsid)) # return default outgoing interface for that class klass = gencache.GetClassForCLSID(clsid) try: return klass.default_source except AttributeError: # See if we have a coclass for the interfaces. try: return gencache.GetClassForCLSID(klass.coclass_clsid).default_source except AttributeError: return None gencache.GetClassForCLSID(clsid) returns the class with docstring """IS7ProSim Interface for S7ProSim COM Object""" This is correct. This class has no sources, as can be seen in the OLE Viewer output, and the AttributError is thrown. OK. klass.coclass_clsid is '{83CC0D83-FEDA-11D1-BE76-0060B06816CF}'. OK. gencache.GetClassForCLSID(klass.coclass_clsid) returns a class with the following properties: base class : CoClassBaseClass coclass_interface : [<class win32com.gen_py.83CC0D80-FEDA-11D1-BE76-0060B06816CFx0x1x0.IS7ProSim at 0x00E4DCF0>] coclass_sources : [] clsid : {83CC0D83-FEDA-11D1-BE76-0060B06816CF} There is no attribute default_source, so the AttributeError is thrown again. This is correct with respect to the makepy output, but not with repsect to the actual OLE object. IMHO the makepy output should have included IS7PrSomEvents as an interface and declared it as default_source within CoClass S7SimPro. Right? So how come it does not? Tracking the makepy actions: ---------------------------- A convenient break point location is makepy.py line 263: gen.generate(....) Walking on till genpy.py line 737 self.CollectOleItemInfosFromType() returned a (correct) list of all OleItem information headers: infotype doc[0] doc[1] TKIND_INTERFACE, 'IS7ProSimEvents', 'Event interface for S7ProSim COM Object' TKIND_COCLASS, 'S7ProSim', 'S7ProSim Class' TKIND_DISPATCH, 'IS7ProSim', 'IS7ProSim Interface for S7ProSim COM Object' a number of (infotype 0 and 6) entries for the constant enumerations This list is run through to colelct and build all oleItems, enumItems, recordItems and vtableItems pass 0: TKIND_INTERFACE, 'IS7ProSimEvents', 'Event interface for S7ProSim COM Object' oleItem, vtableItem = self._Build_Interface(type_info_tuple) returns (None, <VTableItem>) returns (None, <VTableItem>). This will lead to the exclusion of this interface later on. So how does this happen? In self._Build_Interface: oleItem = vtableItem = None if infotype == pythoncom.TKIND_DISPATCH or \ (infotype == pythoncom.TKIND_INTERFACE and attr[11] & pythoncom.TYPEFLAG_FDISPATCHABLE): oleItem = DispatchItem(info, attr, doc) Well, infotype == TKIND_INTERFACE, and attr[11] (wTypeFlags) == 256 (TYPEFLAG_FOLEAUTOMATION). This seems to be a good reason to ignore the interface: oleItem remains None, BTW: a simple DisPatch call (i.o. DispatchWithEvents) works fine, except for ignoring the events of course. Did I stumble on a bug here or am I completely missing a point? Please help out. Thanks, Len Remmerswaal _______________________________________________ Python-win32 mailing list Python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32