I've made good progress on our project to port our XMetaL JScript macros to Python (see the thread from about a month ago referring to the project). All the macros (a couple of hundred of them) have been rewritten in Python, and they all appear to work correctly (though testing in earnest is still to come).
One problem we ran into was that there are a number of XMetaL API calls which are documented to return an object of a specific type but which actually return an interface to the base type of the documented type. For example, the Add() method of a CommandBarControls object is documented to return a CommandBarButton object if the parameter specifying the control type is 1, but a CommandBarPopup if the parameter passed is 5. However, regardless of which value that parameter is given, what is actually returned is a CommandBarControl object, that is, an object of the base class. Clearly that documentation assumes that the interface navigation between base and derived classes will be transparent to the scripting code. Here's the mystery part. When we used the properties of the returned object in our JScript macros, the code worked as advertised. However, the equivalent Python code blows up, with an error claiming that we are trying to use a property which our object does not possess. And the error message says that our object is a CommandBarControl object, not a CommandBarButton or CommandBarPopup object. So the mystery is: why does the JScript code work, when Python code doing the same thing does not? The vendor came up with a workaround, which is for us to explicitly cast the interface which is returned to the type we need to use ourselves. For example, replacing button = toolbar.Controls.Add(1) with control = toolbar.Controls.Add(1) button = win32com.client.CastTo(control, "CommandBarButton") This works. We have over a dozen places in our code where we've had to apply this workaround. However, I would like to solve the mystery if that's possible, because I always prefer knowing how and why the tools we use do what they do. Cuts down on the number of unpleasant surprises. :-} I can think of two possible explanations. The first would be that the vendor is detecting when the scripting engine is JScript and is behaving differently in that case, performing the cast and actually returning the interface to the specific derived class instead of the interface to the base class. It's hard to imagine what the incentive would be for the vendor to do this (have the API behave differently depending on what the scripting engine is). Also, I asked them point blank if that's what's going on, and they said that it isn't. The other, more plausible explanation would be that JScript is navigating between the interfaces using the introspection capabilities provided by the COM architecture. When it sees a method call or property access on an interface for which the method or property isn't implemented, but for which derived classes exist which do implement it, it figures out which one supports the method or property, effectively doing the casting for us. The weak link in this explanation is the question: what would the scripting engine do if more than one derived class implemented the method invoked or the property accessed? Presumably that would trigger an exception. Normally I would clear up such a puzzle by reading the specification for the underlying framework. However, when I asked the vendor for the Windows Scripting Interface specification used to expose their scripting API, they told me that such a document doesn't exist. Assuming the second explanation above is correct, why is the Python scripting support not performing the interface navigation which (for example) JScript and VBScript are doing, and which the documentation for the XMetaL APIs appears to assume will happen? Or is there a third explanation for the mystery which has eluded me? Thanks, Bob Kline _______________________________________________ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32