Python and COM Greg Stein Mark Hammond Tutorial

  • Slides: 112
Download presentation
Python and COM Greg Stein Mark Hammond

Python and COM Greg Stein Mark Hammond

Tutorial Agenda • • • Introduction to COM Python. COM Framework Using Python as

Tutorial Agenda • • • Introduction to COM Python. COM Framework Using Python as a COM client Using Python as a COM server Advanced topics Futures

Introduction to COM

Introduction to COM

COM/OLE and Active. X • Component Object Model – Specification for implementing and defining

COM/OLE and Active. X • Component Object Model – Specification for implementing and defining objects • OLE is the old name, COM is the official name, Active. X is the marketing name – All the same - the Microsoft Marketing Machine

What is a COM interface? • A technique for implementing objects – Uses a

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 •

IUnknown • Base class of all interfaces – Every COM object must implement • Defines object lifetimes – Reference counted using “Add. Ref” and “Release” methods • Defines techniques for querying the object for something useful – Query. Interface method • No other functionality - simply defines these 3 methods

Custom interfaces • Any interface derived from IUnknown – Therefore must follow IUnknown rules

Custom interfaces • Any interface derived from IUnknown – Therefore must follow IUnknown rules for lifetimes • Derived? – Means object can be used as its base. Simplementation 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

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

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

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 – Co. Create. Instance, passing: •

Creating Objects • Standard COM API for creation – Co. Create. Instance, 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,

C++ Pseudo Code // Create an object, but only get back // IUnknown pointer, with new reference IUnknown *p. Unk = Co. Create. Instance(“My. Object”, . . . ) // Ask the object for a pointer to a useful implementation! p. Useful = p. Unk->Query. Interface( IID_IUseful, . . . ) p. Unk->Release(); // finished with this. p. Useful->Do. Something. Useful(); … p. Useful->Release(); // Object now dies…

Custom Interface Example 1 of 2 • Native Interfaces using Word – You would

Custom Interface Example 1 of 2 • Native Interfaces using Word – You would be unlikely to use Word this way – Demonstrative purposes only! • >>> import ni, win 32 com, pythoncom >>> o=pythoncom. Co. Create. Instance ("Word. Application", None, pythoncom. CLSCTX_ALL, pythoncom. IID_IUnknown) >>> o <Py. IUnknown at 0 x 834 b 04 with obj at 0 x 423474>

Custom Interface Example 2 of 2 • >>> o. Query. Interface(  pythoncom. IID_IPersist)

Custom Interface Example 2 of 2 • >>> o. Query. Interface( pythoncom. IID_IPersist) <Py. IPersist at 0 x 85 dd 54 with obj at 0 x 423464> • 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 Add. Ref or Release required, or even exposed – Release() currently exposed, but not for long!

IDispatch - poor man’s COM 1 of 2 • Also known as “Automation” •

IDispatch - poor man’s COM 1 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 COM 2 of 2 • What many people know as

IDispatch - poor man’s COM 2 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, Active. X Controls, Speech Recognition, etc • Very hard from C/C++, very easy from VB

Core Interfaces Introduction • COM tends to use interfaces for everything. Example: – Instead

Core Interfaces Introduction • 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 Interfaces Enumerators • Enumerators provide access into a list of values • Provides

Core Interfaces Enumerators • Enumerators provide access into a list of values • Provides Next, Skip, Reset and Clone methods • Different enumerator interfaces for different types: – IEnum. GUID - Enumerate list of GUID’s – IEnum. Foo. Bar - Enumerate list of Foo. Bars!

Core Interfaces Collections • Alternative technique for accessing lists • Usually only used via

Core Interfaces Collections • 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 Interfaces Streams and Storage • IStream provides file like semantics • IStorage provides

Core Interfaces Streams 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 Interfaces Monikers • Provide file name to object mapping semantics • Fundamental concept

Core Interfaces Monikers • 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 Interfaces Connection. Points • Provides simple callback functionality • Client sets up connection

Core Interfaces Connection. Points • 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. , Active. X Controls). This is how VB finds the list of events for an object.

Core Interfaces And the Rest • Plenty of others not listed here • Anything

Core Interfaces And the Rest • Plenty of others not listed here • Anything in core Python. COM is considered core – By us, anyway - YMMV : -) • Check out the sources, Help Files, or forthcoming documentation – Who was going to write that? – Extensions to Python. COM - present and future

Error Handling • All methods use HRESULT return code – Multiple “success” codes, and

Error Handling • All methods use HRESULT return code – Multiple “success” codes, and many failure codes – ISupport. Error. Info interface for richer error information • IDispatch uses EXCEP_INFO structure • Python. COM transparently maps these • More detail in Server section

Python. COM Framework

Python. COM Framework

Python. COM Framework • Supports use of Python for both COM servers and COM

Python. COM 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

Python. COM Extensions • Model allows for COM extension DLLs – Once loaded, looks

Python. COM Extensions • Model allows for COM extension DLLs – Once loaded, looks like native support to the Python programmer • MAPI, Active. X Scripting and Debugging all use this technique – Import them once, and Python. COM will serve up their interfaces • Makes for stable core, with more frequent extension releases

Using Python as a COM client

Using Python as a COM client

Python COM Clients The Problem • Calling a COM object from Python • COM

Python COM Clients The 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 Clients The Answer • We need an intermediary between a Python object

Python COM Clients The 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!)

Python. COM Interfaces 1 of 3 • Very similar to standard Python extension modules

Python. COM Interfaces 1 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 Py. Arg_Parse. Tuple – Makes call on underlying pointer – Handles errors, exceptions, and return values

Python. COM Interfaces 2 of 3 Interface Client Server Interface Python. COM Python C++

Python. COM Interfaces 2 of 3 Interface Client Server Interface Python. COM Python C++ v-table interface Interface

Python. COM Interfaces 3 of 3 Wrapper Interface Python. COM Python C++ Server IDispatch

Python. COM Interfaces 3 of 3 Wrapper Interface Python. COM Python C++ Server IDispatch interface Client

IDispatch vs. vtable • IDispatch implemented in Python. COM. dll like any other interface

IDispatch vs. vtable • IDispatch implemented in Python. COM. dll like any other interface – No Dynamic logic implemented in DLL – Only Get. IDs. Of. Names and Invoke exposed • win 32 com. 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

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 Implementation 1 of 5 • Implemented by win 32 com. client. dynamic

Dynamic IDispatch Implementation 1 of 5 • Implemented by win 32 com. client. dynamic – Also makes use of win 32 com. client. build – Uses __getattr__ and __setattr__ methods in Python to implement its magic

Dynamic IDispatch Implementation 2 of 5 • Not perfect solution as – __getattr__ has

Dynamic IDispatch Implementation 2 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 Implementation 3 of 5 • win 32 com. client. Dispatch kicks it

Dynamic IDispatch Implementation 3 of 5 • win 32 com. client. Dispatch kicks it all off • Demo >>> >>> import ni from win 32 com. client import Dispatch w=Dispatch(“Word. Application”) w. Visible = 1 • Starts Winword, and makes it visible

Dynamic Dispatch Implementation 4 of 5 • Pros – No setup steps - just

Dynamic Dispatch Implementation 4 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 Implementation 5 of 5 • Smart Dispatch vs. Dumb Dispatch – To

Dynamic Dispatch Implementation 5 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 – win 32 com. client. Dumb. Dispatch provides alternative implementation which does not attempt to locate type information • For many servers, will provide excellent results and speed

Static Dispatch Implementation 1 of 4 • Generates. py file from Type Information –

Static Dispatch Implementation 1 of 4 • Generates. py file from Type Information – win 32 com. 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 Implementation 2 of 4 • Demo C: > cd “Program FilesMicrosoft OfficeOffice”

Static Dispatch Implementation 2 of 4 • Demo C: > cd “Program FilesMicrosoft OfficeOffice” C: > pythonwin 32 comclientmakepy. py msword 8. olb > pythonmsword 8. py. . . C: > start python >>> import msword 8 # grind, grind : -) >>> w = msword 8. Application() >>> w. Visible = 1

Static Dispatch Implementation 3 of 4 • Pros – By. Ref args handled correctly

Static Dispatch Implementation 3 of 4 • Pros – By. Ref 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 Implementation 4 of 4 • Cons – Need to hunt down type

Static Dispatch Implementation 4 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 •

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 Python. COM deals with VARIANT conversions

Dispatch, VARIANTs and Python Types • Python has 2 modes of conversion – Python

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

win 32 com. client Files 1 of 2 • makepy. py, dynamic. py –

win 32 com. client Files 1 of 2 • makepy. py, dynamic. py – Static and dynamic IDispatch implementations respectively • build. py – Utility code used by both modules above • CLSIDTo. Class. py – Manages dictionary of Python classes, mapped by CLSID. Code generated by makepy. py automatically populates this.

win 32 com. client Files 2 of 2 • combrowse. py – Basic COM

win 32 com. client Files 2 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 Handling 1 of 2 • Client interfaces raise pythoncom. com_error exception

Client Side Error Handling 1 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 Handling 2 of 2 • COM Exception Tuple – Tuple of

Client Side Error Handling 2 of 2 • COM Exception Tuple – Tuple of (wcode, App. Name, App. Message, Help. File, Help. Context, 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 Interfaces 1 of 3 • Recent changes to SWIG allow

SWIG and COM Client Interfaces 1 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 Interfaces 2 of 3 • Sample. i from MAPI #define

SWIG and COM Client Interfaces 2 of 3 • Sample. i from MAPI #define TABLE_SORT_DESCEND HRESULT MAPIInitialize( MAPIINIT_0 *INPUT); HRESULT MAPILogon. Ex( ULONG INPUT, TCHAR *in. Null. String, . . . IMAPISession **OUTPUT );

SWIG and COM Client Interfaces 3 of 3 • Notes – #defines are carried

SWIG and COM Client Interfaces 3 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

Using Python as a COM server

Python COM Servers The Problem • Exposing a Python object as a COM object

Python COM Servers The 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”

Gateways 1 of 2 • Gateways act as the intermediary – Hold reference to

Gateways 1 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

Gateways 2 of 2 • The default gateway supports IDispatch – All Python COM

Gateways 2 of 2 • The default gateway supports IDispatch – All Python COM servers automatically support IDispatch • Default also supports ISupport. Error. Info, a standard interface for returning extended error information

Gateways 3 of 3 Gateway Client Wrapper Gateway v-table interface Gateway Python. COM C++

Gateways 3 of 3 Gateway Client Wrapper Gateway v-table interface Gateway Python. COM C++ Python Server

Calling Python Methods • The Python COM framework defines an IDispatch-oriented protocol for how

Calling Python Methods • The Python COM framework defines an IDispatch-oriented protocol for how the gateways call into Python: – _Query. Interface_ : determine support for a particular COM interface – _Get. IDs. Of. Names_ : look up a dispatch identifier (DISPID) for a given name – _Invoke_ : invoke a method with specified parameters

Policies 1 of 2 • “Features” of the gateway protocol: – Non-intuitive for a

Policies 1 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”

Policies 2 of 2 • A “policy” specifies how to implement a Python COM

Policies 2 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)

Instantiation 1 of 3 • The framework calls the Create. Instance function in the

Instantiation 1 of 3 • The framework calls the Create. Instance function in the win 32 com. server. policy module – Hard-wired call to Create. Instance, 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. My. Class”

Instantiation 2 of 3 • The registry key is read by the default policy

Instantiation 2 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

Instantiation 3 of 3 clsid, riid Python. COM clsid, riid policy. py Create. Instance(clsid,

Instantiation 3 of 3 clsid, riid Python. COM clsid, riid policy. py Create. Instance(clsid, riid) returned creates Interface p. Unk

The Default Policy • Python server objects (instances) are annotated with special attributes –

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 My. Python. Server: _public_methods_ = [ ‘Some. Method’ ] def

A Quick Example class My. Python. Server: _public_methods_ = [ ‘Some. Method’ ] def Some. Method(self, arg 1, arg 2): do_some_work(arg 1) return whatever(arg 2) • 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

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

Wrapping 1 of 3 • The process of associating a gateway instance and a

Wrapping 1 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)

Wrapping 2 of 3 Gateway Policy Server This diagram shows the organization of the

Wrapping 2 of 3 Gateway Policy Server This diagram shows the organization of the objects involved in a Python COM server and where the “wrapping” term came from

Wrapping 3 of 3 • Wrapping an object that will be returned: from win

Wrapping 3 of 3 • Wrapping an object that will be returned: from win 32 com. 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 Handling 1 of 3 • COM defines simple result codes with the HRESULT

Error Handling 1 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 ISupport. Error. Info • Framework maps Python exceptions to COM result codes and exceptions

Error Handling 2 of 3 • If the Python exception is an instance, then

Error Handling 2 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 Handling 3 of 3 • When called via IDispatch, it returns the exception

Error Handling 3 of 3 • When called via IDispatch, it returns the exception via EXCEP_INFO • For non-Dispatch calls, the caller may follow up by using ISupport. Error. Info to retrieve the exception • ISupport. Error. Info is part of the base gateway class and is always present

Collections 1 of 3 • Collections are sequence-like objects that typically implement the Add,

Collections 1 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) • win 32 com. server. util. Collection is a simple numerically indexed Collection class

Collections 2 of 3 • The Item method is special – It should be

Collections 2 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

Collections 3 of 3 • The Python COM framework defines returning a list or

Collections 3 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

Enumerators 1 of 3 • Enumerators are used by clients to enumerate a collection

Enumerators 1 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 _New. Enum method

Enumerators 2 of 3 • IEnum. VARIANT is the interface used by Automation clients

Enumerators 2 of 3 • IEnum. VARIANT is the interface used by Automation clients (such as VB) – Your returned enumerator must implement the IEnum. VARIANT interface – Values returned from Next() are VARIANTs (see client section for discussion of COM enumerator interfaces) – Support for IEnum. VARIANT part of core – Python datatypes are easily coerced into VARIANTs by the IEnum. VARIANT gateway

Enumerators 3 of 3 • win 32 com. server. util. New. Enum(seq) will return

Enumerators 3 of 3 • win 32 com. server. util. New. Enum(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. List. Enumerator, List. Enumerator. Gateway, or write from scratch • New gateways needed for interfaces other than IEnum. VARIANT

Server Utilities • Various functionality available in win 32 com. server. * –. .

Server Utilities • Various functionality available in win 32 com. server. * –. . . connect : connection points –. . . exception : exception handling –. . . policy : framework support –. . . register : server object registration –. . . util : miscellaneous utilities

win 32 com. server. connect • Supplies utilities and classes for the server side

win 32 com. server. connect • Supplies utilities and classes for the server side of connection points

win 32 com. server. exception • Exports a single class: Exception • Constructor has

win 32 com. 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

win 32 com. server. policy • Framework knows about this file – Hard-coded reference,

win 32 com. server. policy • Framework knows about this file – Hard-coded reference, so it must exist • Provides Create. Instance 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

win 32 com. server. register • Utilities for registering your COM servers • Two

win 32 com. server. register • Utilities for registering your COM servers • Two primary functions: – Register. Server() – Unregister. Server() • Typically, registration for servers in a file is performed when the file is run from the command line (e. g. “python myservers. py”) • Register. Server() has many options; see its doc string for more information

win 32 com. server. register Example class My. Class: _public_methods_ = [ “My. Method”

win 32 com. server. register Example class My. Class: _public_methods_ = [ “My. Method” ] # … class definition if __name__ == “__main__”: import sys from win 32 com. server import register if len(sys. argv) > 1 and sys. argv[1] == “--unregister”: register. Unregister. Server(“{…}”, “The. Prog. ID”) else: register. Register. Server(“{…}”, “My. Module. My. Class”, prog. ID=“The. Prog. ID”)

win 32 com. server. util • wrap() • unwrap() • New. Enum() – List.

win 32 com. server. util • wrap() • unwrap() • New. Enum() – List. Enumerator class – List. Enumerator. Gateway class • Collection class

win 32 com. makegw • Tool for interfaces and gateways – SWIG now my

win 32 com. 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 Topics

Advanced: Dispatchers 1 of 2 • Debugging and tracing utility – Almost identical to

Advanced: Dispatchers 1 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: Dispatchers 2 of 2 • Log information about your server – All method

Advanced: Dispatchers 2 of 2 • Log information about your server – All method calls made – All IDispatch mapping – All Query. Interface requests • Dispatchers available that send to various debugging “terminals” – win 32 dbg debugger, win 32 trace utility, existing stdout, etc. – Easy to write your own if you have specific debugging requirements

Advanced: Wrapping 1 of 5 • All Python server objects are wrapped with at

Advanced: Wrapping 1 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 win 32 com. servers. dictionary) – Dispatchers can actually add a third layer into this group

Advanced: Wrapping 2 of 5 • Since a gateway is referenced with a C++

Advanced: Wrapping 2 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 Py. Interface to distinguish from COM interfaces) – The Py. Interface is removed by the framework (exposing the C++ pointer) when a Py. Interface is returned by a server

Advanced: Wrapping 3 of 5 Gateway Policy C++ Python Interface Returned to COM client

Advanced: Wrapping 3 of 5 Gateway Policy C++ Python Interface Returned to COM client (the framework removes the Py. Interface) Server

Advanced: Wrapping 4 of 5 • win 32 com. pythoncom. Wrap. Object() wraps a

Advanced: Wrapping 4 of 5 • win 32 com. pythoncom. Wrap. Object() wraps a Python object with a gateway and a Py. Interface – 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: Wrapping 5 of 5 • Unwrapping is performed through a special COM interface:

Advanced: Wrapping 5 of 5 • Unwrapping is performed through a special COM interface: IUnwrap. Python. Object • pythoncom. Unwrap. Object() queries for this interface on the COM object held within the Py. Interface 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 Policies 1 of 7 • Why use a custom policy? – Special

Advanced: Custom Policies 1 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 Policies 2 of 7 • Other provided policies – Basic. Wrap. Policy

Advanced: Custom Policies 2 of 7 • Other provided policies – Basic. Wrap. Policy : handy base class – Mapped. Wrap. Policy : low level mapping-based handling of names and properties and methods – Designated. Wrap. Policy : build onto the Mapped policy a way for objects to easily specify the properties and methods – Dynamic. Policy : determine methods and properties dynamically

Advanced: Custom Policies 3 of 7 • Example: custom instantiation – A single Python

Advanced: Custom Policies 3 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 Policies 4 of 7 • Example: error handling – Returning “Key. Error”

Advanced: Custom Policies 4 of 7 • Example: error handling – Returning “Key. Error” 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 Policies 5 of 7 • Example: data validation – If the server

Advanced: Custom Policies 5 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 Policies 6 of 7 • Example: functions for Property get/put – The

Advanced: Custom Policies 6 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 Policies 7 of 7 • Example: alter mechanism for specifying the available

Advanced: Custom Policies 7 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: Threading 1 of 2 • Python is normally “single threaded”; the least capable

Advanced: Threading 1 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: Threading 2 of 2 • The problem can be reduced by applying patches

Advanced: Threading 2 of 2 • The problem can be reduced by applying patches with allow Python to be truly freethreaded – 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

Futures

Future Directions • • Auto wrap and unwrap COM+ SWIG makepy

Future Directions • • Auto wrap and unwrap COM+ SWIG makepy

Future: Auto Wrapping • This could be done today, but wasn’t: – Leaving it

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

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

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,

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! •

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 •

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