Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Introduction to Python, COM and PythonCOM Mark Hammond Skippi-Net, Melbourne, Australia [email protected] http://starship.python.net/crew/mhammond Introduction to Python, COM and PythonCOM The plan • Section I - Intro to Python – 30-45 mins • Section II - Intro to COM – 30-45 mins • Python and COM – The rest! Section I Introduction to Python What Is Python? • Created in 1990 by Guido van Rossum – While at CWI, Amsterdam – Now hosted by centre for national research initiatives, Reston, VA, USA • Free, open source – And with an amazing community • Object oriented language – “Everything is an object” Why Python? • Designed to be easy to learn and master – Clean, clear syntax – Very few keywords • Highly portable – Runs almost anywhere - high end servers and workstations, down to windows CE – Compiled to machine independent byte-codes • Extensible – Designed to be extensible using C/C++, thereby allowing access to many external libraries Most obvious and notorious features • Clean syntax plus high-level data types – Leads to fast coding • Uses white-space to delimit blocks – Humans generally do, so why not the language? – Try it, you will end up liking it • Variables do not need declaration – Although not a type-less language Pythonwin • We are using Pythonwin – Only available on Windows – GUI toolkit using Tkinter available for most platforms – Standard console Python available on all platforms • Has interactive mode for quick testing of code • Includes debugger and Python editor Interactive Python • Starting Python.exe, or any of the GUI environments present an interactive mode –>>> prompt indicates start of a statement or expression – If incomplete, ... prompt indicates second and subsequent lines – All expression results printed back to interactive console Variables and Types (1 of 3) • Variables need no declaration • >>> a=1 >>> • As a variable assignment is a statement, there is no printed result • >>> a 1 • Variable name alone is an expression, so the result is printed Variables and Types (2 of 3) • Variables must be created before they can be used • >>> b Traceback (innermost last): File "<interactive input>", line 1, in ? NameError: b >>> • Python uses exceptions - more detail later Variables and Types (3 of 3) • Objects always have a type • >>> a = 1 >>> type(a) <type 'int'> >>> a = "Hello" >>> type(a) <type 'string'> >>> type(1.0) <type 'float'> Assignment versus Equality Testing • Assignment performed with single = • Equality testing done with double = (==) – Sensible type promotions are defined – Identity tested with is operator. • >>> 1==1 1 >>> 1.0==1 1 >>> "1"==1 0 Simple Data Types • Strings – May hold any data, including embedded NULLs – Declared using either single, double, or triple quotes – >>> s = "Hi there" >>> s 'Hi there' >>> s = "Embedded 'quote'" >>> s "Embedded 'quote'" Simple Data Types – Triple quotes useful for multi-line strings – >>> s = """ a long ... string with "quotes" or anything else""" >>> s ' a long\012string with "quotes" or anything else' >>> len(s) 45 Simple Data Types • Integer objects implemented using C longs – Like C, integer division returns the floor – >>> 5/2 2 • Float types implemented using C doubles • Long Integers have unlimited size – Limited only by available memory – >>> long = 1L << 64 >>> long ** 5 2135987035920910082395021706169552114602704522 3566527699470416078222197257806405500229620869 36576L High Level Data Types • Lists hold a sequence of items – May hold any object – Declared using square brackets • >>> >>> >>> >>> 2 l = []# An empty list l.append(1) l.append("Hi there") len(l) High Level Data Types • >>> l [1, 'Hi there'] >>> >>> l = ["Hi there", 1, 2] >>> l ['Hi there', 1, 2] >>> l.sort() >>> l [1, 2, 'Hi there'] High Level Data Types • Tuples are similar to lists – Sequence of items – Key difference is they are immutable – Often used in place of simple structures • Automatic unpacking • >>> point = 2,3 >>> x, y = point >>> x 2 High Level Data Types • Tuples are particularly useful to return multiple values from a function • >>> x, y = GetPoint() • As Python has no concept of byref parameters, this technique is used widely High Level Data Types • Dictionaries hold key-value pairs – Often called maps or hashes. Implemented using hash-tables – Keys may be any immutable object, values may be any object – Declared using braces • >>> d={} >>> d[0] = "Hi there" >>> d["foo"] = 1 High Level Data Types • Dictionaries (cont.) • >>> len(d) 2 >>> d[0] 'Hi there' >>> d = {0 : "Hi there", 1 : "Hello"} >>> len(d) 2 Blocks • Blocks are delimited by indentation – Colon used to start a block – Tabs or spaces may be used – Maxing tabs and spaces works, but is discouraged • >>> if 1: ... print "True" ... True >>> Blocks • Many people hate this when they first see it – Almost all Python programmers come to love it • Humans use indentation when reading code to determine block structure – Ever been bitten by the C code?: • if (1) printf("True"); CallSomething(); Looping • The for statement loops over sequences • >>> for ch in "Hello": ... print ch ... H e l l o >>> Looping • Built-in function range() used to build sequences of integers • >>> for i in range(3): ... print i ... 0 1 2 >>> Looping • while statement for more traditional loops • >>> i = 0 >>> while i < 3: ... print i ... i = i + 1 ... 0 1 2 >>> Functions • Functions are defined with the def statement: • >>> def foo(bar): ... return bar >>> • This defines a trivial function named foo that takes a single parameter bar Functions • A function definition simply places a function object in the namespace • >>> foo <function foo at fac680> >>> • And the function object can obviously be called: • >>> foo(3) 3 >>> Classes • Classes are defined using the class statement • >>> class Foo: ... def __init__(self): ... self.member = 1 ... def GetMember(self): ... return self.member ... >>> Classes • A few things are worth pointing out in the previous example: – The constructor has a special name __init__, while a destructor (not shown) uses __del__ – The self parameter is the instance (ie, the this in C++). In Python, the self parameter is explicit (c.f. C++, where it is implicit) – The name self is not required - simply a convention Classes • Like functions, a class statement simply adds a class object to the namespace • >>> Foo <class __main__.Foo at 1000960> >>> • Classes are instantiated using call syntax • >>> f=Foo() >>> f.GetMember() 1 Modules • Most of Python’s power comes from modules • Modules can be implemented either in Python, or in C/C++ • import statement makes a module available • >>> import string >>> string.join( ["Hi", "there"] ) 'Hi there' >>> Exceptions • Python uses exceptions for errors – try / except block can handle exceptions • >>> try: ... 1/0 ... except ZeroDivisionError: ... print "Eeek" ... Eeek >>> Exceptions • try / finally block can guarantee execute of code even in the face of exceptions • >>> try: ... 1/0 ... finally: ... print "Doing this anyway" ... Doing this anyway Traceback (innermost last): File "<interactive input>", line 2, in ? ZeroDivisionError: integer division or modulo >>> Threads • Number of ways to implement threads • Highest level interface modelled after Java • >>> class DemoThread(threading.Thread): ... def run(self): ... for i in range(3): ... time.sleep(3) ... print i ... >>> t = DemoThread() >>> t.start() >>> t.join() 0 1 <etc> Standard Library • Python comes standard with a set of modules, known as the “standard library” • Incredibly rich and diverse functionality available from the standard library – All common internet protocols, sockets, CGI, OS services, GUI services (via Tcl/Tk), database, Berkeley style databases, calendar, Python parser, file globbing/searching, debugger, profiler, threading and synchronisation, persistency, etc External library • Many modules are available externally covering almost every piece of functionality you could ever desire – Imaging, numerical analysis, OS specific functionality, SQL databases, Fortran interfaces, XML, Corba, COM, Win32 API, etc • Way too many to give the list any justice Python Programs • Python programs and modules are written as text files with traditionally a .py extension • Each Python module has its own discrete namespace • Python modules and programs are differentiated only by the way they are called – .py files executed directly are programs (often referred to as scripts) – .py files referenced via the import statement are modules Python Programs • Thus, the same .py file can be a program/script, or a module • This feature is often used to provide regression tests for modules – When module is executed as a program, the regression test is executed – When module is imported, test functionality is not executed Python “Protocols” • Objects can support a number of different “protocols” • This allows your objects to be treated as: – – – – a sequence - ie, indexed or iterated over A mapping - obtain/assign keys or values A number - perform arithmetic A container - perform dynamic attribute fetching and setting – Callable - allow your object to be “called” Python “Protocols” • Sequence and container example • >>> class Protocols: ... def __getitem__(self, index): ... return index ** 2 ... def __getattr__(self, attr): ... return "A big " + attr ... >>> p=Protocols() >>> p[3] 9 >>> p.Foo 'A big Foo’ >>> More Information on Python • Can’t do Python justice in this short time frame – But hopefully have given you a taste of the language • Comes with extensive documentation, including an excellent tutorial and library reference – Also a number of Python books available • Visit www.python.org for more details Section II Introduction to COM What is COM? • Acronym for Component Object Model, a technology defined and implemented by Microsoft • Allows “objects” to be shared among many applications, without applications knowing the implementation details of the objects • A broad and complex technology • We can only provide a brief overview here What was COM • COM can trace its lineage back to DDE • DDE was expanded to Object Linking and Embedding (OLE) • VBX (Visual Basic Extensions) enhanced OLE technology for visual components • COM was finally derived as a general purpose mechanism – Initially known as OLE2 COM Interfaces • COM relies heavily on interfaces • An interface defines functionality, but not implementation – Each object (or more correctly, each class) defines implementation of the interface – Each implementation must conform to the interface • COM defines many interfaces – But often does not provide implementation of these interfaces COM Interfaces • Interfaces do not support properties – We will see how COM properties are typically defined later • Interfaces are defined using a vtable scheme similar to how C++ defines virtual methods • All interfaces have a unique ID (an IID) – Uses a Universally Unique Identifer (UUID) – UUIDs used for many COM IDs, including IIDs Classes • COM defines the concept of a class, used to create objects – Conceptually identical to a C++ or Python class – To create an object, COM locates the class factory, and asks it to create an instance • Classes have two identifiers – Class ID (CLSID) is a UUID, so looks similar to an IID – ProgID is a friendly string, and therefore not guaranteed unique IUnknown interface • Base of all COM interfaces – By definition, all interfaces also support the IUnknown interface • Contains only three methods – AddRef() and Release() for managing COM lifetimes • COM lifetimes are based on reference counts – QueryInterface() for obtaining a new interface from the object Creating objects, and obtaining interfaces • To create an object, the programmer specifies either the ProgID, or the CLSID • This process always returns the requested interface – or fails! • New interfaces are obtained by using the IUnknown::QueryInterface() method – As each interface derives from IUnknown, each interface must support QI Other standard interfaces • COM defines many interfaces, for example: • IStream – Defines file like operations • IStorage – Defines file system like semantics • IPropertyPage – Defines how a control exposes a property page • etc - many many interfaces are defined – But not many have implementations Custom interfaces • COM allows you to define your own interfaces • Interfaces are defined using an Interface Definition Language (IDL) • Tools available to assign unique IIDs for the interface • Any object can then implement or consume these interfaces IDispatch - Automation objects • IDispatch interface is used to expose dynamic object models • Designed explicitly for scripting languages, or for those languages that can not use normal COM interfaces – eg, where the interface is not known at compile time, or there is no compile time at all • IDispatch is used extensively – Microsoft Office, Netscape, Outlook, VB, etc almost anything designed to be scripted IDispatch - Automation objects • Methods and properties of the object model can be determined at runtime – Concept of Type Libraries, where the object model can be exposed at compile time • Methods and properties are used indirectly – GetIDsOfNames() method is used to get an ID for a method or property – Invoke() is used to make the call IDispatch - Automation objects • Languages usually hide these implementation details from the programmer • Example: object.SomeCall() – Behind the scenes, your language will: id = GetIDsOfNames("SomeCall") Invoke(id, DISPATCH_METHOD) • Example: object.SomeProp – id = GetIDsOfNames("SomeProp") Invoke(id, DISPATCH_PROP_GET) VARIANTs • The IDispatch interface uses VARIANTs as its primary data type • Simply a C union that supports the common data types – and many helper functions for conversion etc • Allows the single Invoke() call to accept almost any data type • Many languages hide these details, performing automatic conversion as necessary Implementation models • Objects can be implemented in a number of ways – InProc objects are implemented as DLLs, and loaded into the calling process • Best performance, as no marshalling is required – LocalServer/RemoteServer objects are implemented as stand-alone executables • Safer due to process isolation, but slower due to remoting • Can be both, and caller can decide, or let COM choose the best Distributed COM • DCOM allows objects to be remote from their caller • DCOM handles all marshalling across machines and necessary security • Configuration tools allow an administrator to configure objects so that neither the object nor the caller need any changes – Although code changes can be used to explicitly control the source of objects The Windows Registry • Information on objects stored in the Windows registry – – – – ProgID to CLSID mapping Name of DLL for InProc objects Name of EXE for LocalServer objects Other misc details such as threading models • Lots of other information also maintained in registry – Remoting proxies, object security, etc. Conclusion for Section II • COM is a complex and broad beast • Underlying it all is a fairly simple Interface model – Although all the bits around the edges combine to make it very complex • Hopefully we have given enough framework to put the final section into some context Section III Python and COM PythonCOM architecture • Underpinning everything is an extension module written in C++ that provides the core COM integration – Support for native COM interfaces exist in this module – Python reference counting is married with COM reference counting • Number of Python implemented modules that provide helpers for this core module Interfaces supported by PythonCOM • Over 40 standard interfaces supported by the framework • Extension architecture where additional modules can add support for their own interfaces – Tools supplied to automate this process – Number of extension modules supplied, bringing total interfaces to over 100 Using Automation from Python • Automation uses IDispatch to determine object model at runtime • Python function win32com.client.Dispatch() provides this run-time facility • Allows a native “look and feel” to these objects Using Automation - Example • We will use Excel for this demonstration • Excel ProgId is Excel.Application • >>> from win32com.client import Dispatch >>> xl=Dispatch("Excel.Application") >>> xl <COMObject Excel.Application> >>> Using Automation - Example • Now that we have an Excel object, we can call methods and set properties • But we can’t see Excel running? – It has a visible property that may explain things • >>> xl.Visible 0 • Excel is not visible, let’s make it visible >>> xl.Visible = 1 >>> Automation - Late vs. Early Bound • In the example we just saw, we have been using late bound COM – Python has no idea what properties or methods are available – As we attempt a method or property access, Python dynamically asks the object – Slight performance penalty, as we must resolve the name to an ID (GetIDsOfNames()) before calling Invoke() Automation - Late vs. Early Bound • If an object provides type information via a Type Library, Python can use early bound COM • Implemented by generating a Python source file with all method and property definitions – Slight performance increase as all names have been resolved to IDs at generation time, rather than run-time Automation - Late vs. Early Bound • Key differences between the 2 techniques: – Late bound COM often does not know the specific types of the parameters • Type of the Python object determines the VARIANT type created • Does not know about ByRef parameters, so no parameters are presented as ByRef – Early bound COM knows the types of the parameters • All Python types are coerced to the correct type • ByRef parameters work (returned as tuples) Playing with Excel • >>> xl.Workbooks.Add() <COMObject <unknown>> >>> xl.Range("A1:C1").Value = "Hi", "From", "Python" >>> xl.Range("A1:C1").Value ((L'Hi', L'From', L'Python'),) >>> xl.Range("A1:C1").PrintOut() >>> How did we know the methods? • Indeed, how did we know to use “Excel.Application”? • No easy answer - each application/object defines their own object model and ProgID • Documentation is the best answer – Note that MSOffice does not install the COM documentation by default - must explicitly select it during setup • COM browsers can also help Native Interfaces from Python • Examples so far have been using using IDispatch – win32com.client.Dispatch() function hides the gory details from us • Now an example of using interfaces natively – Need a simple example - Windows Shortcuts fits the bill • Develop some code that shows information about a Windows shortcut Native Interfaces from Python • 4 main steps in this process – Import the necessary Python modules – Obtain an object that implements the IShellLink interface – Obtain an IPersistFile interface from the object, and load the shortcut – Use the IShellLink interface to get information about the shortcut Native Interfaces from Python Step 1: Import the necessary Python modules – We need the pythoncom module for core COM support – We need the win32com.shell.shell module • This is a PythonCOM extension that exposes additional interfaces • >>> import pythoncom >>> from win32com.shell import shell Native Interfaces from Python Step 2: Obtain an object that implements the IShellLink interface • Use the COM function CoCreateInstance() • Use the published CLSID for the shell • The shell requires that the object request be for an InProc object. • Request the IShellLink interface Native Interfaces from Python Step 2: Obtain an object that implements the IShellLink interface • >>> sh = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, ... ... ... >>> sh None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink) <PyIShellLink at 0x1630b04 with obj at 0x14c9d8> >>> Native Interfaces from Python Step 3: Obtain an IPersist interface from the object, and load the shortcut • Use QueryInterface to obtain the new interface from the object • >>> pe= sh.QueryInterface(pythoncom.IID_IPersistFile) >>> pe.Load("c:/winnt/profiles/skip/desktop/IDLE.lnk") Native Interfaces from Python Step 4: Use the IShellLink interface to get information about the shortcut • >>> sh.GetWorkingDirectory() 'L:\\src\\python-cvs\\tools\\idle' >>> sh.GetArguments() 'l:\\src\\python-cvs\\tools\\idle\\idle.pyw' >>> Implementing COM using Python. • Final part of our tutorial is implementing COM objects using Python • 3 main steps we must perform – Implement a Python class that exposes the functionality – Annotate the class with special attributes required by the COM framework. – Register our COM object Implementing COM using Python. Step 1: Implement a Python class that exposes the functionality • We will build on our last example, by providing a COM object that gets information about a Windows shortcut • Useful to use from VB, as it does not have direct access to these interfaces. • We will design a class that can be initialised to a shortcut, and provides methods for obtaining the info. Implementing COM using Python Step 1: Implement a Python class that exposes the functionality • Code is getting to big for the slides • Code is basically identical to that presented before, except: – The code has moved into a class. – We store the IShellInfo interface as an instance attribute Implementing COM using Python Step 1: Implement a Python class that exposes the functionality • Provide an Init method that takes the name of the shortcut. • Also provide two trivial methods that simply delegate to the IShellInfo interface • Note Python would allow us to automate the delegation, but that is beyond the scope of this! Implementing COM using Python Step 2: Annotate the class with special attributes • PythonCOM requires a number of special attributes – The CLSID of the object (a UUID) • Generate using print pythoncom.CreateGuid() – The ProgID of the object (a friendly string) • Make one up! – The list of public methods • All methods not listed as public are not exposed via COM Implementing COM using Python Step 2: Annotate the class with special attributes • class PyShellLink: _public_methods_=['Init', 'GetWorkingDirectory', 'GetArguments'] _reg_clsid_="{58DE4632-9323-11D3-85F9-00C04FEFD0A7}" _reg_progid_="Python.ShellDemo" ... Implementing COM using Python Step 3: Register our COM object • General technique is that the object is registered when the module implementing the COM object is run as a script. – Recall previous discussion on modules versus scripts • Code is trivial – Call the UseCommandLine() method, passing the class objects we wish to register Implementing COM using Python Step 3: Register our COM object • Code is simple – note we are passing the class object, not a class instance. • if __name__=='__main__': UseCommandLine(PyShellLink) • Running this script yields: • Registered: Python.ShellDemo Testing our COM object • Our COM object can be used by any automation capable language – VB, Delphi, Perl - even VC at a pinch! • We will test with a simple VBScript program – VBScript is free. Could use full blown VB, or VBA. Syntax is identical in all cases Testing our COM object • set shdemo = CreateObject("Python.ShellDemo") shdemo.Init("c:\winnt\profiles\skip\deskt op\IDLE.lnk") WScript.Echo "Working dir is " + shdemo.GetWorkingDirectory() • Yields • Working dir is L:\src\python-cvs\tools\idle Summary • Python can make COM simple to work with – No reference count management – Many interfaces supported. – Natural use for IDispatch (automation) objects. • Simple to use COM objects, or implement COM objects Questions? More Information • Python itself – http://www.python.org – news:comp.lang.python • Python on Windows – http://www.python.org/windows • Mark Hammond’s Python extensions – http://starship.python.net/crew/mhammond – http://www.python.org/windows