Post on 06-Jan-2016
description
transcript
Python and COM
Greg Stein
Mark Hammond
Tutorial Agenda
• Introduction to COM
• PythonCOM Framework
• Using Python as a COM client
• Using Python as a COM server
• Advanced topics
• Futures
Introduction to COM
COM/OLE and ActiveX
• Component Object Model– Specification for implementing and defining
objects
• OLE is the old name, COM is the official name, ActiveX is the marketing name– All the same - the Microsoft Marketing
Machine
What is a COM interface?
• A technique for implementing objects– Uses a “vtable” to define methods– Does not have properties
• Basically a C++ object with only public methods– But not C++ specific - just borrowed
implementation technique– Allows implementation from other languages– All interfaces have a unique ID
IUnknown
• Base class of all interfaces– Every COM object must implement
• Defines object lifetimes– Reference counted using “AddRef” and
“Release” methods
• Defines techniques for querying the object for something useful– QueryInterface method
• No other functionality - simply defines these 3 methods
Custom interfaces
• Any interface derived from IUnknown– Therefore must follow IUnknown rules for
lifetimes
• Derived?– Means object can be used as its base. Simple
implementation using vtables
• All interfaces are custom interfaces– Not a standard part of COM per-se, just follow
its rules
Objects vs. Interfaces
• Interfaces simply define functionality
• Objects, once instantiated, implement the interface– Object class also has unique ID
• Objects always provide multiple interfaces– At least IUnknown and some other functional
interface
CLSIDs, GUIDs, UUIDs, IIDs
• COM defines 128 bit identifier, and API for creating them– “High degree of certainty” that these are globally
unique
• All use the same type and implementation, acronym reflects different usage– IID == Interface ID, GUID == Globally Unique
Identifier, CLSID == Class ID, UUID == Universally Unique Identifier, etc
– API for converting to and from Strings
Registering Objects
• Objects register themselves in the Windows Registry– Register with their Unique CLSID
• Also register a name for the object– COM provides API for translating, but names
are not guaranteed unique– Many objects self register
Creating Objects
• Standard COM API for creation– CoCreateInstance, passing:
• CLSID identifying the object to create
• IID identifying the initial interface requested
C++ Pseudo Code
// Create an object, but only get back
// IUnknown pointer, with new reference
IUnknown *pUnk = CoCreateInstance(“MyObject”, ...)
// Ask the object for a pointer to a useful implementation!
pUseful = pUnk->QueryInterface( IID_IUseful, ...)
pUnk->Release(); // finished with this.
pUseful->DoSomethingUseful();
…
pUseful->Release(); // Object now dies…
Custom Interface Example1 of 2
• Native Interfaces using Word– You would be unlikely to use Word this way– Demonstrative purposes only!
• >>> import ni, win32com, pythoncom>>> o=pythoncom.CoCreateInstance \ ("Word.Application", None, pythoncom.CLSCTX_ALL, pythoncom.IID_IUnknown)>>> o<PyIUnknown at 0x834b04 with obj at 0x423474>
Custom Interface Example2 of 2
• >>> o.QueryInterface( \ pythoncom.IID_IPersist)<PyIPersist at 0x85dd54 with obj at 0x423464>
• Almost identical to the pseudo code above– In fact, Python is far better than C++, as long as
we support the required interfaces natively
• No AddRef or Release required, or even exposed– Release() currently exposed, but not for long!
IDispatch - poor man’s COM1 of 2
• Also known as “Automation”
• Derived from IUnknown
• Defines vtable methods to determine “dispatch methods and properties” at runtime– Perfect for scripting languages which have no
compile step, or which are not C++!
• Optionally uses Type Libraries so optimizations can be made at compile time
IDispatch - poor man’s COM2 of 2
• What many people know as COM– Microsoft marketing machine– In reality, a small, but somewhat useful part of
COM
• Many useful COM interfaces do not support IDispatch– Native MAPI, Active Scripting/Debugging,
ActiveX Controls, Speech Recognition, etc
• Very hard from C/C++, very easy from VB
Core InterfacesIntroduction
• COM tends to use interfaces for everything. Example:– Instead of using a file pointer/handle, a
“Stream” interface is used, which provides file like semantics
– Anyone free to implement the stream interface using any technique they choose
– Such interfaces not necessarily part of COM per-se, but we consider them “core interfaces”
Core InterfacesEnumerators
• Enumerators provide access into a list of values
• Provides Next, Skip, Reset and Clone methods
• Different enumerator interfaces for different types:– IEnumGUID - Enumerate list of GUID’s– IEnumFooBar - Enumerate list of FooBars!
Core InterfacesCollections
• Alternative technique for accessing lists
• Usually only used via IDispatch– Uses “tricks” only IDispatch has available, such
as properties!– Therefore not a real interface
• Used to provide array like semantics for VB, etc– Methods include Count() and Item(). Count
often implied by len(), Item() often omitted.
Core InterfacesStreams and Storage
• IStream provides file like semantics
• IStorage provides file system like semantics
• Programs can write to this specification without needing to know the destination of the data
• COM provides implementations of these for “structured storage files”
Core InterfacesMonikers
• Provide file name to object mapping semantics
• Fundamental concept is to provide an indirection level to an underlying object, and a program neutral way of accessing the underlying object– File and URL Monikers do just that– Pointer monikers allow anyone to implement an
abstract indirection to an object (e.g., into a message store, etc)
Core InterfacesConnectionPoints
• Provides simple callback functionality
• Client sets up connection point object
• Object passed to Connection Point Container object
• Container calls methods on the Connection Point when appropriate
• Typically used as an event mechanism (e.g., ActiveX Controls). This is how VB finds the list of events for an object.
Core InterfacesAnd the Rest
• Plenty of others not listed here
• Anything in core PythonCOM is considered core– By us, anyway - YMMV :-)
• Check out the sources, Help Files, or forthcoming documentation– Who was going to write that?– Extensions to PythonCOM - present and future
Error Handling
• All methods use HRESULT return code– Multiple “success” codes, and many failure
codes– ISupportErrorInfo interface for richer error
information
• IDispatch uses EXCEP_INFO structure
• PythonCOM transparently maps these
• More detail in Server section
PythonCOM Framework
PythonCOM Framework
• Supports use of Python for both COM servers and COM clients
• Easy for the Python programmer
• Dispatch friendly with core support for most common vtable interfaces
• Easily extended for new vtable interfaces
PythonCOM Extensions
• Model allows for COM extension DLLs– Once loaded, looks like native support to the
Python programmer
• MAPI, ActiveX Scripting and Debugging all use this technique– Import them once, and PythonCOM will serve
up their interfaces
• Makes for stable core, with more frequent extension releases
Using Python as a COM client
Python COM ClientsThe Problem
• Calling a COM object from Python
• COM = vtable = C++ (not Python)
• IDispatch removes vtable requirement– Imposes coding burden on client– IDispatch is still vtable based, so core problem
remains
Python COM ClientsThe Answer
• We need an intermediary between a Python object and COM’s vtables– These are called “interfaces” (c.f. “gateways”
for the server side - poor choice of terminology, but this is what we use!)
PythonCOM Interfaces1 of 3
• Very similar to standard Python extension modules
• Conceptually identical to wrapping any C++ object in Python– 1:1 mapping between the COM pointer and
Python object– Pulls apart arguments using PyArg_ParseTuple– Makes call on underlying pointer– Handles errors, exceptions, and return values
PythonCOM Interfaces2 of 3
Interface
Interface
Interface
v-ta
ble
inte
rfac
e
C++Python
Client
Server
PythonCOM
PythonCOM Interfaces3 of 3
InterfaceIDispatch
IDis
patc
h in
terf
ace
C++Python
Client ServerWrapper
PythonCOM
IDispatch vs. vtable
• IDispatch implemented in PythonCOM.dll like any other interface– No Dynamic logic implemented in DLL– Only GetIDsOfNames and Invoke exposed
• win32com.client Python code implements all IDispatch logic
• Calls the above 2 methods dynamically to obtain method and property information
IDispatch Implementation
• 2 modes of IDispatch usage– Dynamic, where no information about an object
is known at runtime• All determination of methods and properties made
at runtime
– Static, where full information about an object is known before hand
• Information comes from a “Type Library”
• Not all objects have Type Libraries (including Python objects!)
Dynamic IDispatch Implementation1 of 5
• Implemented by win32com.client.dynamic– Also makes use of win32com.client.build– Uses __getattr__ and __setattr__ methods in
Python to implement its magic
Dynamic IDispatch Implementation2 of 5
• Not perfect solution as– __getattr__ has no idea if the attribute being
requested is a property reference or a method reference
– No idea if the result of a method call is required (i.e., is it a sub or a function)
– Python must guess at the variable types– Big problem tends to be “byref” params - by
default these are not handled
Dynamic IDispatch Implementation3 of 5
• win32com.client.Dispatch kicks it all off
• Demo>>> import ni
>>> from win32com.client import Dispatch
>>> w=Dispatch(“Word.Application”)
>>> w.Visible = 1
• Starts Winword, and makes it visible
Dynamic Dispatch Implementation4 of 5
• Pros– No setup steps - just works– Provides quick scripting access to components
• Cons– Relatively slow– You need to know the object model of the
target. Not self documenting.• Actually, Python can make many objects self
documenting, but this is beyond the scope of this
Dynamic Dispatch Implementation5 of 5
• Smart Dispatch vs. Dumb Dispatch– To overcome some potential problems, Python
attempts to use Type Info even for dynamic objects
– Slows down considerably for certain objects– win32com.client.DumbDispatch provides
alternative implementation which does not attempt to locate type information
• For many servers, will provide excellent results and speed
Static Dispatch Implementation1 of 4
• Generates .py file from Type Information– win32com.client.makepy does this
• Python code then imports this module
• Python knows everything about the object– No confusion between methods and properties– Byref args handled correctly– No dynamic lookups - much faster
Static Dispatch Implementation2 of 4
• DemoC:\> cd “\Program Files\Microsoft Office\Office”
C:\> \python\python \python\win32com\client\makepy.py msword8.olb > \python\msword8.py
...
C:> start python
>>> import msword8 # grind, grind :-)
>>> w = msword8.Application()
>>> w.Visible = 1
Static Dispatch Implementation3 of 4
• Pros– ByRef args handled correctly
• Result becomes a tuple in that case
– All types handled correctly• Python knows the type required, so doesnt have to
guess. More scope to coerce
– Significantly faster– Python source file documents methods and
properties available
Static Dispatch Implementation4 of 4
• Cons– Need to hunt down type library– Need to enter cryptic command to generate code– No standard place to put generated code– Compiling code may take ages
• Not real problem, as this is a once only step
– Type library may not be available
• Many Cons listed are not permanent - help would be appreciated!
Dispatch, VARIANTs and Python Types
• VARIANT– COM concept for IDispatch interface
• Just a C union, with a flag for the type, and an API for manipulating and converting
– IDispatch always uses VARIANT objects• In reality, COM is not typeless - most servers
assume a particular type in the variant
– Most (only!) complex code in PythonCOM deals with VARIANT conversions
Dispatch, VARIANTs and Python Types
• Python has 2 modes of conversion– Python type drives VARIANT type
• Python knows no better
• Creates VARIANT based on type of Python object
– Known type drives VARIANT type• For static IDispatch, Python often known exactly
type required
• Attempt to coerce the Python object to VARIANT of this type
win32com.client Files1 of 2
• makepy.py, dynamic.py– Static and dynamic IDispatch implementations
respectively
• build.py– Utility code used by both modules above
• CLSIDToClass.py– Manages dictionary of Python classes, mapped
by CLSID. Code generated by makepy.py automatically populates this.
win32com.client Files2 of 2
• combrowse.py– Basic COM browser that requires Pythonwin.
Simply double-click on it.
• tlbrowse.py– Basic Type Library browser that requires Pythonwin
• util.py– Utiility helpers
• connect.py– Connection point client base class
Client Side Error Handling1 of 2
• Client interfaces raise pythoncom.com_error exception
• Exception consists of:– HRESULT
• 32 bit error code, defined by OLE
– Error Message• Should be language independant
– (cont.)
Client Side Error Handling2 of 2
• COM Exception Tuple– Tuple of (wcode, AppName, AppMessage,
HelpFile, HelpContext, scode), all of which are application defined
– Exception object itself, or any part of it, may be None
• Arg Error– Integer containing the argument number that
caused the error– Often None if error does not relate to specific
argument
SWIG and COM Client Interfaces1 of 3
• Recent changes to SWIG allow it to generate client side native interfaces– ie, any custom interface not based on IDispatch
can be generated
• Uses existing SWIG functionality and M.O.– ie, maintain .i files, and SWIG generates .c files
• Native MAPI support generated this way– Pretty serious API, and it works a treat!
SWIG and COM Client Interfaces2 of 3
• Sample .i from MAPI#define TABLE_SORT_DESCEND TABLE_SORT_DESCEND
HRESULT MAPIInitialize( MAPIINIT_0 *INPUT);HRESULT MAPILogonEx(
ULONG INPUT, TCHAR *inNullString,...IMAPISession **OUTPUT
);
SWIG and COM Client Interfaces3 of 3
• Notes– #defines are carried into module– Many functions are completely trivial– SWIG handles input/output params– Scope for even better integration with COM
• e.g., maybe the first cut at the .i could be generated from the Type Info.
– More work and discussions with Dave Beazley needed!
Using Python as a COM server
Python COM ServersThe Problem
• Exposing a Python object as a COM object
• COM = vtable = C++ (not Python)
• IDispatch removes vtable requirement– Imposes coding burden on client– Some interfaces are defined as a vtable
• Answer: we need an intermediary between COM’s vtables and a Python object– These are called “gateways”
Gateways1 of 2
• Gateways act as the intermediary– Hold reference to the Python object– Map C++ method calls into Python calls– Map parameters and return values
• A gateway is a C++ object implementing a particular COM interface
• Gateways are registered with the framework and instantiated as needed to support particular interfaces as they are requested
Gateways2 of 2
• The default gateway supports IDispatch– All Python COM servers automatically support
IDispatch
• Default also supports ISupportErrorInfo, a standard interface for returning extended error information
Gateways3 of 3
Gateway
Gateway
Gateway
v-ta
ble
inte
rfac
e
C++ Python
Client
Wrapper Server
PythonCOM
Calling Python Methods
• The Python COM framework defines an IDispatch-oriented protocol for how the gateways call into Python:– _QueryInterface_ : determine support for a
particular COM interface– _GetIDsOfNames_ : look up a dispatch
identifier (DISPID) for a given name– _Invoke_ : invoke a method with specified
parameters
Policies1 of 2
• “Features” of the gateway protocol:– Non-intuitive for a Python programmer– Usually requires support structures for the
DISPID handling– Subtleties with some of the parameters and
return values
• Result: hard for Python programmers to write a COM server
• Answer: “policy objects”
Policies2 of 2
• A “policy” specifies how to implement a Python COM server
• The policy object maps the gateway protocol to the given implementation policy
• The default policy is usually sufficient
• Custom policies may be created and used– An advanced topic (discussed later)
Instantiation1 of 3
• The framework calls the CreateInstance function in the win32com.server.policy module– Hard-wired call to CreateInstance, but behavior
can easily be hooked through custom policies
• When your COM object is registered, an additional registry key specifies the creator function– Typically “mymodule.MyClass”
Instantiation2 of 3
• The registry key is read by the default policy and used to instantiate your object
• COM does not provide additional parameters to your creator function (the __init__ method)– Make sure that any parameters have defaults– COM+ will provide this capability
• Registry can specify a custom policy
Instantiation3 of 3
PythonCOM policy.py
CreateInstance(clsid, riid)
clsid, riid
returned
Interface
creates
pUnk
clsid, riid
returned
The Default Policy
• Python server objects (instances) are annotated with special attributes– Typically specified as class attributes– Most are optional
• _public_methods_– A list of strings specifying the methods that
clients are allowed to call– This is the only required attribute
A Quick Example
class MyPythonServer:
_public_methods_ = [ ‘SomeMethod’ ]
def SomeMethod(self, arg1, arg2):
do_some_work(arg1)
return whatever(arg2)
• Note that the only difference for the Python programmer is the addition of the _public_methods_ attribute
Useful Attributes
• _public_attrs_ : what Python attributes should be exposed as COM Properties
• _readonly_attrs_ : which of the above should be considered read-only
• _com_interfaces_ : what COM interfaces beyond IDispatch are supported
Wrapping1 of 3
• The process of associating a gateway instance and a policy instance with a particular Python instance is known as “wrapping”
• Similarly, retrieving the Python instance is known as “unwrapping”
• Objects returned by Python COM servers must be wrapped (the framework does not automatically wrap)
Wrapping2 of 3
Gateway
Policy
Server
This diagram shows the organization of theobjects involved in a Python COM server andwhere the “wrapping” term came from
Wrapping3 of 3
• Wrapping an object that will be returned:
from win32com.server import util...def method(self, arg):
ob = whatever(arg)return util.wrap(ob)
• Unwrapping (of an argument) is rare– You must know the object is a Python object
(and what to do with it once unwrapped)– Usually used in relatively closed systems
Error Handling1 of 3
• COM defines simple result codes with the HRESULT type and associated constants
• Extended error information includes description, help file, context, etc
• Returned via EXCEP_INFO structure in IDispatch or through ISupportErrorInfo
• Framework maps Python exceptions to COM result codes and exceptions
Error Handling2 of 3
• If the Python exception is an instance, then framework looks for special attributes to fill in COM extended exception information– Just raise an instance with the right attributes– See exception.Exception utility class
• Otherwise, the framework does its best
Error Handling3 of 3
• When called via IDispatch, it returns the exception via EXCEP_INFO
• For non-Dispatch calls, the caller may follow up by using ISupportErrorInfo to retrieve the exception
• ISupportErrorInfo is part of the base gateway class and is always present
Collections1 of 3
• Collections are sequence-like objects that typically implement the Add, Remove, and Item methods and a Count property
• Some Collections (such as those provided natively by VB) can be indexed using numbers (acts as a sequence) or using strings (acts as a mapping)
• win32com.server.util.Collection is a simple numerically indexed Collection class
Collections2 of 3
• The Item method is special– It should be the “default” method, meaning that
VB can implicitly call it without using its name– The predefined DISPID_VALUE value refers to
the default method– Item can be called with one parameter (the
index) or with two parameters (an index and a new value to place at that index)
– This duality is not handled well by the default policy nor server.util.Collection
– Also beware the numeric vs. string indexing
Collections3 of 3
• The Python COM framework defines returning a list or tuple to mean returning a SAFEARRAY of VARIANT values– This means your object must explicitly return an
object that obeys the Collection protocol– A custom policy could be used to automatically
wrap sequences with a Collection– Only recognizes list and tuple
• avoids treating a string as a sequence
• instances are not checked for sequence behavior
Enumerators1 of 3
• Enumerators are used by clients to enumerate a collection (sequence)– VBScript automatically fetches an enumerator
for script code such as:for each item in collection
• Standard COM protocol uses the predefined DISPID_NEWENUM value and calls IDispatch::Invoke()– Default policy calls your _NewEnum method
Enumerators2 of 3
• IEnumVARIANT is the interface used by Automation clients (such as VB)– Your returned enumerator must implement the
IEnumVARIANT interface– Values returned from Next() are VARIANTs
(see client section for discussion of COM enumerator interfaces)
– Support for IEnumVARIANT part of core– Python datatypes are easily coerced into
VARIANTs by the IEnumVARIANT gateway
Enumerators3 of 3
• win32com.server.util.NewEnum(seq) will return an enumerator for a given sequence
• Custom enumerators are easily written:– Dynamic sequences– Special handling of enumerated values– Subclass from server.util.ListEnumerator,
ListEnumeratorGateway, or write from scratch
• New gateways needed for interfaces other than IEnumVARIANT
Server Utilities
• Various functionality available in win32com.server.*– ...connect : connection points– ...exception : exception handling– ...policy : framework support– ...register : server object registration– ...util : miscellaneous utilities
win32com.server.connect
• Supplies utilities and classes for the server side of connection points
win32com.server.exception
• Exports a single class: Exception
• Constructor has keyword arguments for the status code, description, help file, etc.
• The Exception class places these values into instance variables
• The Python COM framework picks up the values for returning to the caller
win32com.server.policy
• Framework knows about this file– Hard-coded reference, so it must exist
• Provides CreateInstance for the framework– Provides hooks for custom policies and
dispatchers
• Defines various standard policies and dispatchers– Future: the policies and dispatchers will move
out to separate files for easier maintainability
win32com.server.register
• Utilities for registering your COM servers
• Two primary functions:– RegisterServer()– UnregisterServer()
• Typically, registration for servers in a file is performed when the file is run from the command line (e.g. “python myservers.py”)
• RegisterServer() has many options; see its doc string for more information
win32com.server.register Exampleclass MyClass:
_public_methods_ = [ “MyMethod” ]
# … class definition
if __name__ == “__main__”:
import sys
from win32com.server import register
if len(sys.argv) > 1 and sys.argv[1] == “--unregister”:
register.UnregisterServer(“{…}”, “The.ProgID”)
else:
register.RegisterServer(“{…}”, “MyModule.MyClass”,
progID=“The.ProgID”)
win32com.server.util
• wrap()
• unwrap()
• NewEnum()– ListEnumerator class– ListEnumeratorGateway class
• Collection class
win32com.makegw
• Tool for interfaces and gateways– SWIG now my preference for interfaces - gateways
somewhat harder
• Generate once, and never again– compare with SWIG, which allows multiple
generations - particularly useful as support is added after initial generation
• Better than hand-coding– Active Scripting, Debugging and some others done
this way
Advanced Topics
Advanced: Dispatchers1 of 2
• Debugging and tracing utility– Almost identical to policies; simply delegate to
actual policy
• Only used during development, so zero runtime overhead in release
• Implementation is not for speed, but for assistance in debugging– e.g., IIDs translated if possible to names, often
using the registry or dictionary lookups, etc
Advanced: Dispatchers2 of 2
• Log information about your server– All method calls made– All IDispatch mapping– All QueryInterface requests
• Dispatchers available that send to various debugging “terminals”– win32dbg debugger, win32trace utility, existing
stdout, etc.– Easy to write your own if you have specific
debugging requirements
Advanced: Wrapping1 of 5
• All Python server objects are wrapped with at least two objects: the policy and the gateway– Caveat: a custom policy may implement the
actual server rather than using another object (see win32com.servers.dictionary)
– Dispatchers can actually add a third layer into this group
Advanced: Wrapping2 of 5
• Since a gateway is referenced with a C++ interface pointer, Python cannot hold the reference– Wrap once more with a framework “interface”
(we’ll call it a PyInterface to distinguish from COM interfaces)
– The PyInterface is removed by the framework (exposing the C++ pointer) when a PyInterface is returned by a server
Advanced: Wrapping3 of 5
Gateway
Policy
Server
Interface
Pyt
hon
C+
+
Returned to COM client(the framework removes the PyInterface)
Advanced: Wrapping4 of 5
• win32com.pythoncom.WrapObject() wraps a Python object with a gateway and a PyInterface– Pass it the policy object (which is wrapping the
Python server object)– Optional parameter specifies the IID of a
gateway to use for the wrapping (the gateway must be registered with the COM framework)
Advanced: Wrapping5 of 5
• Unwrapping is performed through a special COM interface: IUnwrapPythonObject
• pythoncom.UnwrapObject() queries for this interface on the COM object held within the PyInterface object that is passed
• The base gateway class implements this COM interface (so all gateways have it)
• The interface’s single method returns the gateway’s underlying Python object
Advanced: Custom Policies1 of 7
• Why use a custom policy?– Special error handling, creation, calling
mechanisms, validation, etc– Write the policy class and enter the appropriate
information into the registry so that the framework will use your policy
– Be sure to use your custom policy when wrapping your objects
Advanced: Custom Policies2 of 7
• Other provided policies– BasicWrapPolicy : handy base class– MappedWrapPolicy : low level mapping-based
handling of names and properties and methods– DesignatedWrapPolicy : build onto the Mapped
policy a way for objects to easily specify the properties and methods
– DynamicPolicy : determine methods and properties dynamically
Advanced: Custom Policies3 of 7
• Example: custom instantiation– A single Python COM server was used to
represent multiple COM objects– At instantiation time, it used the CLSID passed
to the policy to look in the registry for more detailed information
– A child/sub object was created, based on the registered information; the COM server provided some generic behavior for all of the child objects
Advanced: Custom Policies4 of 7
• Example: error handling– Returning “KeyError” or other Python
exceptions to callers was undesirable– Wrap all Invokes with an exception handler that
would map Python errors into a generic error– Let through pythoncom.com_error unchanged– If a “magic” registry value was present, then a
full traceback was placed into the exception (rather than simply “internal error”)
Advanced: Custom Policies5 of 7
• Example: data validation– If the server object had a _validation_map_
attribute, then a custom validation method would be called for all Property “puts”
– _validation_map_ would map a Property name to a type signature that the _validate_() method would test against
– The Invoke method was hooked to call the _validate_() method
Advanced: Custom Policies6 of 7
• Example: functions for Property get/put– The Item() method in Collections is really
treated as a parameterized property– Using a custom policy, get_Item() can be
differentiated from put_Item()– Allowed for get_Count() and the absence of
put_Count() implied read-only
Advanced: Custom Policies7 of 7
• Example: alter mechanism for specifying the available properties– Using the _validation_map_ from a previous
example, the available properties are easily derived (simply the keys of the mapping)
– Avoided duplication of property specification (one in _validation_map_ and one in _public_attrs_)
Advanced: Threading1 of 2
• Python is normally “single threaded”; the least capable COM threading model
• With care, it could be possible to mark an object as “free threaded” to fool how COM handles the object, but Python will continue to allow only one thread per process to run
• This behavior is fine for many applications where Python is a COM client, but it breaks down for some server scenarios
Advanced: Threading2 of 2
• The problem can be reduced by applying patches with allow Python to be truly free-threaded– Slows down single thread case– Applies mainly to multiprocessor use
• More work on threading is needed and is in progress on the Thread-SIG
Futures
Future Directions
• Auto wrap and unwrap
• COM+
• SWIG
• makepy
Future: Auto Wrapping
• This could be done today, but wasn’t:– Leaving it to Python increased flexibility– Complexity involved with needing a way to
specify two things during any wrapping process: the policy and the gateway
• Moving to COM+ will be an opportune time to change
• Annotation through attributes will control wrapping process
Future: COM+1 of 3
• What is COM+ ?– Upcoming revision of COM– Runtime services: memory management,
interceptors, object model changes, language independence, etc
– see: http://www.microsoft.com/cominfo
Future: COM+2 of 3
• Python already has most of COM+’s facilities and matches its model strongly
• Huge win for Python:– Simplify COM programming even more– Will reduce the framework and associated
overheads– Better language compatibilities– Major reduction in dependence on vtables– Better type handling
Future: COM+3 of 3
• Any Python object can be a COM+ server, provided it is registered appropriately– Note that COM+ registration will be easier
• Auto wrapping
• “import somedll” will load the “metadata” from the DLL and automatically make its classes and constants available
Future: SWIG
• Depends largely on what Dave Beazley is willing to support!
• Interface support needs more work– Framework is OK– Mainly adding all interfaces and types to SWIG
library
• Gateways still a long way off– Future here quite uncertain
• Some sort of IDL parsing highly desirable
Future: makepy
• Functionally quite complete– Some cleanup desirable, but works well
• Architectural issues outstanding– Where does generated code go?
• Utilities for automatic generation– From program ID– Integration with COM browser– Integration with some GUI interface