1 / 112

Python and COM

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

azizi
Télécharger la présentation

Python and COM

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Python and COM Greg Stein Mark Hammond

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

  3. Introduction to COM

  4. 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

  5. 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

  6. 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

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

  8. 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

  9. 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

  10. 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

  11. Creating Objects • Standard COM API for creation • CoCreateInstance, passing: • CLSID identifying the object to create • IID identifying the initial interface requested

  12. 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…

  13. 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>

  14. 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!

  15. 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

  16. 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

  17. 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”

  18. 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!

  19. 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.

  20. 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”

  21. 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)

  22. 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.

  23. 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

  24. 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

  25. PythonCOM Framework

  26. 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

  27. 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

  28. Using Python as a COM client

  29. 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

  30. 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!)

  31. 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

  32. v-table interface Python C++ PythonCOM Interfaces2 of 3 PythonCOM Interface Server Client Interface Interface

  33. IDispatch interface Python C++ PythonCOM Interfaces3 of 3 PythonCOM Interface IDispatch Client Wrapper Server

  34. 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

  35. 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!)

  36. 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

  37. 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

  38. 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

  39. 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

  40. 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

  41. 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

  42. Static Dispatch Implementation2 of 4 • Demo C:\> 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

  43. 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

  44. 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!

  45. 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

  46. 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

  47. 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.

  48. 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

  49. 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.)

  50. 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

More Related