Uploaded Test files
104
venv/Lib/site-packages/win32com/HTML/GeneratedSupport.html
Normal file
|
@ -0,0 +1,104 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>Generated Python COM Support</TITLE>
|
||||
<META NAME="Version" CONTENT="8.0.3410">
|
||||
<META NAME="Date" CONTENT="10/11/96">
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">
|
||||
|
||||
<P><IMG SRC="image/pycom_blowing.gif" WIDTH=549 HEIGHT=99 ALT="Python and COM - Blowing the others away"></P>
|
||||
<H1>Generated Python COM Support</H1>
|
||||
<P>This file describes how the Python COM extensions support "generated files". The information contained here is for expert Python users, and people who need to take advantage of the advanced features of the support. More general information is available in the <A HREF="QuickStartClientCom.html">Quick Start to Client Side COM</A> documentation.</P>
|
||||
<H2>Introduction</H2>
|
||||
<P>Generated Python COM support means that a .py file exists behind a particular COM object. This .py file is created by a generation process from a COM type library.</P>
|
||||
<P>This documentation talks about the process of the creation of the .py files.</P>
|
||||
<H2>Design Goals</H2>
|
||||
<P>The main design goal is that the Python programmer need not know much about the type library they wish to work with. They need not know the name of a specific Python module to use a type library. COM uses an IID, version and LCID to identify a type library. Therefore, the Python programmer only need know this information to obtain a Python module.</P>
|
||||
<H2>How to generate support files</H2>
|
||||
<P>Support files can be generated either "off-line" by the makepy utility, or in custom Python code.</P>
|
||||
<P>Using makepy is in many ways far simpler - you simply pick the type library and you are ready to go! The <A HREF="QuickStartClientCom.html">Quick Start to Client Side COM</A> documentation describes this process.</P>
|
||||
<P>Often however, you will want to use code to ensure the type library has been processed. This document describes that process.</P>
|
||||
<H2>Usage</H2>
|
||||
<P>The win32com.client.gencache module implements all functionality. As described above, if you wish to generate support from code, you need to know the IID, version and LCID of the type library.</P>
|
||||
<P>The following functions are defined. The best examples of their usage is probably in the Pythonwin OCX Demos, and the COM Test Suite (particularly testMSOffice.py)</P>
|
||||
<P>Note that the gencache.py file supports being run from the command line, and provides some utilities for managing the cache. Run the file to see usage options.</P>
|
||||
<H2>Using makepy to help with the runtime generation</H2>
|
||||
<P>makepy supports a "-i" option, to print information about a type library. When you select a type library, makepy will print out 2 lines of code that you cant paste into your application. This will then allow your module to generate the makepy .py file at runtime, but will only take you a few seconds!</P>
|
||||
<H2>win32com.client.gencache functions</H2>
|
||||
<H3>def MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance = None):</H3>
|
||||
<P>Generate support for a type library.</P>
|
||||
<P>Given the IID, LCID and version information for a type library, generate and import the necessary support files.</P>
|
||||
<B><P>Returns</P>
|
||||
</B><P>The Python module. No exceptions are caught.</P>
|
||||
<B><P>Params</P>
|
||||
</B><I><P>typelibCLSID</I><BR>
|
||||
IID of the type library.</P>
|
||||
<I><P>major</I><BR>
|
||||
Integer major version.</P>
|
||||
<I><P>minor</I><BR>
|
||||
Integer minor version.</P>
|
||||
<I><P>lcid</I><BR>
|
||||
Integer LCID for the library.</P>
|
||||
<I><P>progressInstance</I><BR>
|
||||
A class instance to use as the progress indicator, or None to use the default GUI one. </P>
|
||||
<H3>def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance = None):</H3>
|
||||
<P>Ensure Python support is loaded for a type library, generating if necessary.</P>
|
||||
<P>Given the IID, LCID and version information for a type library, check and if necessary generate, then import the necessary support files.</P>
|
||||
<P>Returns:</P>
|
||||
<P>The Python module. No exceptions are caught during the generate process.</P>
|
||||
<B><P>Params</P>
|
||||
</B><I><P>typelibCLSID</I><BR>
|
||||
IID of the type library.</P>
|
||||
<I><P>major</I><BR>
|
||||
Integer major version.</P>
|
||||
<I><P>minor</I><BR>
|
||||
Integer minor version.</P>
|
||||
<I><P>lcid</I><BR>
|
||||
Integer LCID for the library.</P>
|
||||
<I><P>progressInstance</I><BR>
|
||||
A class instance to use as the progress indicator, or None to use the default GUI one. </P>
|
||||
<P> </P>
|
||||
<H3>def GetClassForProgID(<I>progid</I>):</H3>
|
||||
<P>Get a Python class for a Program ID</P>
|
||||
<P>Given a Program ID, return a Python class which wraps the COM object</P>
|
||||
<B><P>Returns</P>
|
||||
</B><P>The Python class, or None if no module is available.</P>
|
||||
<B><P>Params</P>
|
||||
</B><I><P>progid<BR>
|
||||
</I>A COM ProgramID or IID (eg, "Word.Application")</P>
|
||||
<P> </P>
|
||||
<H3>def GetModuleForProgID(progid):</H3>
|
||||
<P>Get a Python module for a Program ID</P>
|
||||
<P>Given a Program ID, return a Python module which contains the class which wraps the COM object.</P>
|
||||
<B><P>Returns</P>
|
||||
</B><P>The Python module, or None if no module is available.</P>
|
||||
<B><P>Params:</P>
|
||||
</B><I><P>progid <BR>
|
||||
</I>A COM ProgramID or IID (eg, "Word.Application")</P>
|
||||
<P> </P>
|
||||
<H3>def GetModuleForCLSID(clsid):</H3>
|
||||
<P>Get a Python module for a CLSID</P>
|
||||
<P>Given a CLSID, return a Python module which contains the class which wraps the COM object.</P>
|
||||
<B><P>Returns</P>
|
||||
</B><P>The Python module, or None if no module is available.</P>
|
||||
<B><P>Params</P>
|
||||
</B><I><P>progid<BR>
|
||||
</I>A COM CLSID (ie, not the description)</P>
|
||||
<P> </P>
|
||||
<H3>def GetModuleForTypelib(typelibCLSID, lcid, major, minor):</H3>
|
||||
<P>Get a Python module for a type library ID</P>
|
||||
<B><P>Returns</P>
|
||||
</B><P>An imported Python module, else None</P>
|
||||
<B><P>Params</B>:</P>
|
||||
<I><P>typelibCLSID</I><BR>
|
||||
IID of the type library.</P>
|
||||
<I><P>major</I><BR>
|
||||
Integer major version.</P>
|
||||
<I><P>minor</I><BR>
|
||||
Integer minor version</P>
|
||||
<I><P>lcid</I><BR>
|
||||
Integer LCID for the library.</P></BODY>
|
||||
</HTML>
|
90
venv/Lib/site-packages/win32com/HTML/PythonCOM.html
Normal file
|
@ -0,0 +1,90 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>Untitled</TITLE>
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY LINK="#0000ff" VLINK="#800080">
|
||||
|
||||
<H1><IMG SRC="image/pycom_blowing.gif" WIDTH=549 HEIGHT=99 ALT="Python and COM - Blowing the others away"></H1>
|
||||
<H1>Python and COM - Implementation Details </H1>
|
||||
<H2>Introduction </H2>
|
||||
<P>This document describes the technical implementation of the COM support in Python. It is primarily concerned with the underlying C++ interface to COM, although general Python issues are touched. </P>
|
||||
<P>This document is targeted at people who wish to maintain/enhance the standard COM support (typically by writing extension modules). For information on using Python and COM from a Python programmers perspective, please see the <A HREF="docindex.html">documentation index</A>. </P>
|
||||
<H2>General COM Support. </H2>
|
||||
<P>COM support in Python can be broken into 2 general areas - C++ support, and Python support. C++ support exists in the core PythonCOM module (plus any PythonCOM extension modules). Python support exists in the .py files that accompany the core module. </P>
|
||||
<H2>Naming Conventions </H2>
|
||||
<P>The naming conventions used by Python code will be: </P>
|
||||
|
||||
<UL>
|
||||
<LI>The Python "New Import" (ni) module will be used, allowing packages, or nested modules. </LI>
|
||||
<LI>The package name will be "win32com". </LI>
|
||||
<LI>The core module name will be "pythoncom" (ie, "win32com.pythoncom") </LI></UL>
|
||||
|
||||
<P>The rest of the naming conventions are yet to be worked out. </P>
|
||||
<H2>Core COM support. </H2>
|
||||
<P>This section is involved with the core C++ support in "pythoncom". </P>
|
||||
<P>The organisation of PythonCOM support falls into 3 discrete areas. </P>
|
||||
<H3>COM Client Support </H3>
|
||||
<P>This is the ability to manipulate other COM objects via their exposed interface. This includes use of IDispatch (eg using Python to start Microsoft Word, open a file, and print it.) but also all client side IUnknown derived objects fall into this category, including ITypeLib and IConnectionPoint support. </P>
|
||||
<H3>COM Server Support </H3>
|
||||
<P>This is ability for Python to create COM Servers, which can be manipulated by another COM client. This includes server side IDispatch (eg, Visual Basic starting a Python interpreter, and asking it to evaluate some code) but also all supported server side IUnknown derived classes. </P>
|
||||
<H3>Python/COM type and value conversion </H3>
|
||||
<P>This is internal code used by the above areas to managed the conversion to and from Python/COM types and values. This includes code to convert an arbitrary Python object into a COM variant, manages return types, and a few other helpers. </P>
|
||||
<H2>COM Structures and Python Types </H2>
|
||||
<P>OLE supports many C level structures for the COM API, which must be mapped to Python. </P>
|
||||
<H3>VARIANT </H3>
|
||||
<P>Variants are never exposed as such to Python programs. The internal framework always converts all variants to and from Python types. In some cases, type descriptions may be used, which force specific mappings, although in general the automatic conversion works fine. </P>
|
||||
<H3>TYPEDESC </H3>
|
||||
<P>A tuple, containing the elements of the C union. This union will be correctly decoded by the support code. </P>
|
||||
<H3>ELEMDESC </H3>
|
||||
<P>A tuple of TYPEDESC and PARAMDESC objects. </P>
|
||||
<H3>FUNCDESC </H3>
|
||||
<P>A funcdesc is a large and unwieldy tuple. Documentation to be supplied. </P>
|
||||
<H3>IID/CLSID </H3>
|
||||
<P>A native IID in Python is a special type, defined in pythoncom. Whenever a CLSID/IID is required, typically either an object, a tuple of type "iii(iiiiiiii)" or string can be used. </P>
|
||||
<P>Helper functions are available to convert to and from IID/CLSID and strings. </P>
|
||||
<H2>COM Framework </H2>
|
||||
<P>Both client and server side support have a specific framework in place to assist in supporting the widest possible set of interfaces. The framework allows external extension DLLs to be written, which extend the interfaces available to the Python user. </P>
|
||||
<P>This allows the core PythonCOM module to support a wide set of common interfaces, and other extensions to support anything obscure. </P>
|
||||
<H3>Client Framework </H3>
|
||||
<H4>QueryInterface and Types </H4>
|
||||
<P>When the only support required by Python is IDispatch, everything is simple - every object returned from QueryInterface is a PyIDispatch object. But this does not extend to other types, such as ITypeLib, IConnectionPoint etc., which are required for full COM support. </P>
|
||||
<P>For example, consider the following C++ psuedo-code: </P>
|
||||
<CODE><P>IConnectionPoint *conPt;<BR>
|
||||
someIDispatch->QueryInterface(IID_IConnectionPoint, (void **)&conPt);<BR>
|
||||
// Note the IID_ and type of the * could be anything!</CODE> </P>
|
||||
<P>This cast, and knowledge of a specific IID_* to type must be simulated in Python. </P>
|
||||
<P>Python/COM will therefore maintain a map of UID's to Python type objects. Whenever QueryInterface is called, Python will lookup this map, to determine if the object type is supported. If the object is supported, then an object of that type will be returned. If the object is not supported, then a PyIUnknown object will be returned. </P>
|
||||
<P>Note that PyIDispatch will be supported by the core engine. Therefore: </P>
|
||||
<CODE><P>>>> disp=someobj.QueryInterface(win32com.IID_Dispatch) </P>
|
||||
</CODE><P>will return a PyIDispatch object, whereas </P>
|
||||
<CODE><P>>>> unk=someobj.QueryInterface(SomeUnknownIID) # returns PyIUnknown<BR>
|
||||
>>> disp=unk.QueryInterface(win32com.IID_Dispatch) <BR>
|
||||
>>> unk.Release() # Clean up now, rather than waiting for unk death.</CODE> </P>
|
||||
<P>Is needed to convert to an IDispatch object. </P>
|
||||
<H4>Core Support </H4>
|
||||
<P>The core COM support module will support the IUnknown, IDispatch, ITypeInfo, ITypeLib and IConnectionPointContainer and IConnectionPoint interfaces. This implies the core COM module supports 6 different OLE client object types, mapped to the 6 IID_*'s representing the objects. (The IConnection* objects allow for Python to repsond to COM events) </P>
|
||||
<P>A psuedo-inheritance scheme is used. The Python types are all derived from the Python IUnknown type (PyIUnknown). Therefore all IUnknown methods are automatically available to all types, just as it should be. The PyIUnknown type manages all object reference counts and destruction. </P>
|
||||
<H4>Extensibility </H4>
|
||||
<P>To provide the above functionality, a Python map is provided, which maps from a GUID to a Python type object. </P>
|
||||
<P>The advantage of this scheme is an external extension modules can hook into the core support. For example, imagine the following code: </P>
|
||||
<CODE><P>>>> import myextracom # external .pyd supporting some interface.<BR>
|
||||
# myextracom.pyd will do the equivilent of</CODE> </P>
|
||||
<CODE><P># pythoncom.mapSupportedTypes(myextracom.IID_Extra, myextracom.ExtraType) <BR>
|
||||
>>> someobj.QueryInterface(myextracom.IID_Extra)</CODE> </P>
|
||||
<P>Would correctly return an object defined in the extension module. </P>
|
||||
<H3>Server Framework </H3>
|
||||
<H4>General Framework </H4>
|
||||
<P>A server framework has been put in place which provides the following features: </P>
|
||||
<P>All Interfaces provide VTBL support - this means that the Servers exposed by Python are callable from C++ and other compiled languages. </P>
|
||||
<P>Supports full "inproc" servers. This means that no external .EXE is needed making Python COM servers available in almost all cases. </P>
|
||||
<P>An extensible model which allows for extension modules to provide server support for interfaces defined in that module. A map is provided which maps from a GUID to a function pointer which creates the interface. </P>
|
||||
<H3>Python and Variant Types Conversion </H3>
|
||||
<P>In general, Python and COM are both "type-less". COM is type-less via the VARIANT object, which supports many types, and Python is type-less due to its object model. </P>
|
||||
<P>There are a number of areas where Python and OLE clash. </P>
|
||||
<H4>Parameters and conversions. </H4>
|
||||
<P>For simple calls, there are 2 helpers available which will convert to and from PyObjects and VARIANTS. The call to convert a Python object to a VARIANT is simple in that it returns a VARIANT of the most appropriate type for the Python object - ie, the type of the Python object determines the resulting VARIANT type. </P>
|
||||
<P>There are also more complex conversion routines available, wrapped in a C++ helper class. Typically, these helpers are used whenever a specific variant type is known (eg, when an ITypeInfo is available for the object being used). In this case, all efforts are made to convert the Python type to the requested variant type - ie, in this situation, the VARIANT type determines how the Python object is coerced. In addition, this code supports the use of "ByRef" and pointer paramaters, providing and freeing any buffers necessary for the call. </P></BODY>
|
||||
</HTML>
|
|
@ -0,0 +1,82 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>Quick Start to Client side COM and Python</TITLE>
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY LINK="#0000ff" VLINK="#800080">
|
||||
|
||||
<H1>Quick Start to Client side COM and Python</H1>
|
||||
<H2>Introduction</H2>
|
||||
<P>This documents how to quickly start using COM from Python. It is not a thorough discussion of the COM system, or of the concepts introduced by COM.</P>
|
||||
<P>Other good information on COM can be found in various conference tutorials - please see <A HREF="http://starship.python.net/crew/mhammond/conferences">the collection of Mark's conference tutorials</A></P>
|
||||
<P>For information on implementing COM objects using Python, please see <A HREF="http://www.python.org/windows/win32com/QuickStartServerCom.html">a Quick Start to Server side COM and Python</A></P>
|
||||
<P>In this document we discuss the following topics:</P>
|
||||
|
||||
<UL>
|
||||
<LI><A HREF="#Using">Using a COM object from Python</A> </LI>
|
||||
<LI><A HREF="#WhatObjects">How do I know which objects are available?</A> </LI>
|
||||
<LI><A HREF="#StaticDispatch">Static Dispatch/Type Safe objects (using the new improved makepy.py)</A></LI>
|
||||
<LI><A HREF="#UsingComConstants">Using COM Constants with makepy.</A></LI></UL>
|
||||
|
||||
<H2>Quick Start</H2>
|
||||
<H3><A NAME="Using">To use a COM object from Python</A></H3>
|
||||
<CODE><P>import win32com.client<BR>
|
||||
o = win32com.client.Dispatch("Object.Name")<BR>
|
||||
o.Method()<BR>
|
||||
o.property = "New Value"<BR>
|
||||
print o.property</P>
|
||||
</CODE><P>Example</P>
|
||||
<CODE><P>o = win32com.client.Dispatch("Excel.Application")<BR>
|
||||
o.Visible = 1<BR>
|
||||
o.Workbooks.Add() # for office 97 – 95 a bit different!<BR>
|
||||
o.Cells(1,1).Value = "Hello"</CODE> </P>
|
||||
<P>And we will see the word "Hello" appear in the top cell. </P>
|
||||
<H3><A NAME="WhatObjects">How do I know which methods and properties are available?</A></H3>
|
||||
<P>Good question. This is hard! You need to use the documentation with the products, or possibly a COM browser. Note however that COM browsers typically rely on these objects registering themselves in certain ways, and many objects to not do this. You are just expected to know.</P>
|
||||
<H4>The Python COM browser</H4>
|
||||
<P>PythonCOM comes with a basic COM browser that may show you the information you need. Note that this package requires Pythonwin (ie, the MFC GUI environment) to be installed for this to work.</P>
|
||||
<P>There are far better COM browsers available - I tend to use the one that comes with MSVC, or this one!</P>
|
||||
<P>To run the browser, simply select it from the Pythonwin <I>Tools</I> menu, or double-click on the file <I>win32com\client\combrowse.py</I></P>
|
||||
<H2><A NAME="StaticDispatch">Static Dispatch (or Type Safe) objects</A></H2>
|
||||
<P>In the above examples, if we printed the '<CODE>repr(o)</CODE>' object above, it would have resulted in</P>
|
||||
<CODE><P><COMObject Excel.Application></P>
|
||||
</CODE><P>This reflects that the object is a generic COM object that Python has no special knowledge of (other than the name you used to create it!). This is known as a "dynamic dispatch" object, as all knowledge is built dynamically. The win32com package also has the concept of <I>static dispatch</I> objects, which gives Python up-front knowledge about the objects that it is working with (including arguments, argument types, etc)</P>
|
||||
<P>In a nutshell, Static Dispatch involves the generation of a .py file that contains support for the specific object. For more overview information, please see the documentation references above.</P>
|
||||
<P>The generation and management of the .py files is somewhat automatic, and involves one of 2 steps:</P>
|
||||
|
||||
<UL>
|
||||
<LI>Using <I>makepy.py</I> to select a COM library. This process is very similar to Visual Basic, where you select from a list of all objects installed on your system, and once selected the objects are magically useable. </LI></UL>
|
||||
|
||||
<P>or</P>
|
||||
|
||||
<UL>
|
||||
<LI>Use explicit code to check for, and possibly generate, support at run-time. This is very powerful, as it allows the developer to avoid ensuring the user has selected the appropriate type library. This option is extremely powerful for OCX users, as it allows Python code to sub-class an OCX control, but the actual sub-class can be generated at run-time. Use <I>makepy.py</I> with a </I>-i</I> option to see how to include this support in your Python code.</LI></UL>
|
||||
|
||||
<P>The <I>win32com.client.gencache</I> module manages these generated files. This module has <A HREF="GeneratedSupport.html">some documentation of its own</A>, but you probably don't need to know the gory details!</P>
|
||||
<H3>How do I get at the generated module?</H3>
|
||||
<P>You will notice that the generated file name is long and cryptic - obviously not designed for humans to work with! So how do you get at the module object for the generated code?</P>
|
||||
<P>Hopefully, the answer is <I>you shouldn't need to</I>. All generated file support is generally available directly via <I>win32com.client.Dispatch</I> and <I>win32com.client.constants</I>. But should you ever really need the Python module object, the win32com.client.gencache module has functions specifically for this. The functions GetModuleForCLSID and GetModuleForProgID both return Python module objects that you can use in your code. See the docstrings in the gencache code for more details.</P>
|
||||
<H3>To generate Python Sources supporting a COM object</H3>
|
||||
<H4>Example using Microsoft Office 97.</H4>
|
||||
<P>Either:</P>
|
||||
|
||||
<UL>
|
||||
<LI>Run '<CODE>win32com\client\makepy.py</CODE>' (eg, run it from the command window, or double-click on it) and a list will be presented. Select the Type Library '<CODE>Microsoft Word 8.0 Object Library</CODE>' </LI>
|
||||
<LI>From a command prompt, run the command '<CODE>makepy.py "Microsoft Word 8.0 Object Library"</CODE>' (include the double quotes). This simply avoids the selection process. </LI>
|
||||
<LI>If you desire, you can also use explicit code to generate it just before you need to use it at runtime. Run <CODE>'makepy.py -i "Microsoft Word 8.0 Object Library"</CODE>' (include the double quotes) to see how to do this.</LI></UL>
|
||||
|
||||
<P>And that is it! Nothing more needed. No special import statements needed! Now, you simply need say</P>
|
||||
<CODE><P>>>> import win32com.client</P>
|
||||
<P>>>> w=win32com.client.Dispatch("Word.Application")</P>
|
||||
<P>>>> w.Visible=1</P>
|
||||
<P>>>> w</P>
|
||||
<P><win32com.gen_py.Microsoft Word 8.0 Object Library._Application></P>
|
||||
</CODE><P>Note that now Python knows the explicit type of the object.</P>
|
||||
<H3><A NAME="UsingComConstants">Using COM Constants</A></H3>
|
||||
<P>Makepy automatically installs all generated constants from a type library in an object called <I>win32com.clients.constants</I>. You do not need to do anything special to make these constants work, other than create the object itself (ie, in the example above, the constants relating to <I>Word</I> would automatically be available after the <CODE>w=win32com.client.Dispatch("Word.Application</CODE>") statement<CODE>.</P>
|
||||
</CODE><P>For example, immediately after executing the code above, you could execute the following:</P>
|
||||
<CODE><P>>>> w.WindowState = win32com.client.constants.wdWindowStateMinimize</P>
|
||||
</CODE><P>and Word will Minimize.</P></BODY>
|
||||
</HTML>
|
195
venv/Lib/site-packages/win32com/HTML/QuickStartServerCom.html
Normal file
|
@ -0,0 +1,195 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>Quick Start to Server Side COM and Python</TITLE>
|
||||
<META NAME="Version" CONTENT="8.0.3410">
|
||||
<META NAME="Date" CONTENT="10/11/96">
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">
|
||||
|
||||
<H1>Quick Start to Server side COM and Python</H1>
|
||||
<H2>Introduction</H2>
|
||||
<P>This documents how to quickly start implementing COM objects in Python. It is not a thorough discussion of the COM system, or of the concepts introduced by COM.</P>
|
||||
<P>For more details information on Python and COM, please see the <A HREF="http://www.python.org/windows/win32com/COMTutorial/index.htm">COM Tutorial given by Greg Stein and Mark Hammond at SPAM 6 (HTML format)</A> or download the same tutorial <A HREF="http://www.python.org/windows/win32com/COMTutorial.ppt">in PowerPoint format.</A></P>
|
||||
<P>For information on using external COM objects from Python, please see <A HREF="QuickStartClientCom.html">a Quick Start to Client side COM and Python</A>.</P>
|
||||
<P>In this document we discuss the <A HREF="#core">core functionality</A>, <A HREF="#Registering">registering the server</A>, <A HREF="#testing">testing the class</A>, <A HREF="#debugging">debugging the class</A>, <A HREF="#Exception">exception handling</A> and <A HREF="#Policies">server policies</A> (phew!)</P>
|
||||
<H2><A NAME="core">Implement the core functionality</A></H2>
|
||||
<H3><A NAME="Using">Implement a stand-alone Python class with your functionality</A></H3>
|
||||
<CODE><P>class HelloWorld:</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>def __init__(self):</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>self.softspace = 1</P>
|
||||
<P>self.noCalls = 0</P></DIR>
|
||||
</DIR>
|
||||
|
||||
<P>def Hello(self, who):</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>self.noCalls = self.noCalls + 1</P>
|
||||
<P># insert "softspace" number of spaces</P>
|
||||
<P>return "Hello" + " " * self.softspace + who</P></DIR>
|
||||
</DIR>
|
||||
</DIR>
|
||||
</DIR>
|
||||
|
||||
</CODE><P>This is obviously a very simple server. In particular, custom error handling would be needed for a production class server. In addition, there are some contrived properties just for demonstration purposes.</P>
|
||||
<H3>Make Unicode concessions</H3>
|
||||
<P>At this stage, Python and Unicode don’t really work well together. All strings which come from COM will actually be Unicode objects rather than string objects.</P>
|
||||
<P>To make this code work in a COM environment, the last line of the "Hello" method must become:</P><DIR>
|
||||
<DIR>
|
||||
<DIR>
|
||||
<DIR>
|
||||
|
||||
<CODE><P>return "Hello" + " " * self.softspace + str(who)</P></DIR>
|
||||
</DIR>
|
||||
</DIR>
|
||||
</DIR>
|
||||
|
||||
</CODE><P>Note the conversion of the "who" to "str(who)". This forces the Unicode object into a native Python string object.</P>
|
||||
<P>For details on how to debug COM Servers to find this sort of error, please see <A HREF="#debugging">debugging the class</A></P>
|
||||
<H3>Annotate the class with win32com specific attributes</H3>
|
||||
<P>This is not a complete list of names, simply a list of properties used by this sample.</P>
|
||||
<TABLE CELLSPACING=0 BORDER=0 CELLPADDING=7 WIDTH=637>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP">
|
||||
<P><B>Property Name</B></TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP">
|
||||
<B><P>Description</B></TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP">
|
||||
<P>_public_methods_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP">
|
||||
<P>List of all method names exposed to remote COM clients</TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP">
|
||||
<P>_public_attrs_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP">
|
||||
<P>List of all attribute names exposed to remote COM clients</TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>_readonly_attrs_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>List of all attributes which can be accessed, but not set.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<P>We change the class header to become:</P>
|
||||
<CODE><P>class HelloWorld:</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>_public_methods_ = ['Hello']</P>
|
||||
<P>_public_attrs_ = ['softspace', 'noCalls']</P>
|
||||
<P>_readonly_attrs_ = ['noCalls']</P>
|
||||
<P>def __init__(self):</P>
|
||||
<P>[Same from here…]</P></DIR>
|
||||
</DIR>
|
||||
|
||||
</CODE><H3><A NAME="Registering">Registering and assigning a CLSID for the object</A></H3>
|
||||
<P>COM requires that all objects use a unique CLSID and be registered under a "user friendly" name. This documents the process.</P>
|
||||
<H4>Generating the CLSID</H4>
|
||||
<P>Microsoft Visual C++ comes with various tools for generating CLSID's, which are quite suitable. Alternatively, the pythoncom module exports the function CreateGuid() to generate these identifiers.</P>
|
||||
<CODE><P>>>> import pythoncom<BR>
|
||||
>>> print pythoncom.CreateGuid()<BR>
|
||||
{7CC9F362-486D-11D1-BB48-0000E838A65F}</P>
|
||||
</CODE><P>Obviously the GUID that you get will be different than that displayed here.</P>
|
||||
<H4>Preparing for registration of the Class</H4>
|
||||
<P>The win32com package allows yet more annotations to be applied to a class, allowing registration to be effected with 2 lines in your source file. The registration annotations used by this sample are:</P>
|
||||
<TABLE CELLSPACING=0 BORDER=0 CELLPADDING=7 WIDTH=636>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP">
|
||||
<P><B>Property Name</B></TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP">
|
||||
<B><P>Description</B></TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP">
|
||||
<P>_reg_clsid_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP">
|
||||
<P>The CLSID of the COM object</TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP">
|
||||
<P>_reg_progid_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP">
|
||||
<P>The "program ID", or Name, of the COM Server. This is the name the user usually uses to instantiate the object</TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>_reg_desc_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>Optional: The description of the COM Server. Used primarily for COM browsers. If not specified, the _reg_progid_ is used as the description.</TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>_reg_class_spec_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>Optional: A string which represents how Python can create the class instance. The string is of format<BR>
|
||||
[package.subpackage.]module.class</P>
|
||||
<P>The portion up to the class name must be valid for Python to "import", and the class portion must be a valid attribute in the specified class.</P>
|
||||
<P>This is optional from build 124 of Pythoncom., and has been removed from this sample.</TD>
|
||||
</TR>
|
||||
<TR><TD WIDTH="34%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>_reg_remove_keys_</TD>
|
||||
<TD WIDTH="66%" VALIGN="TOP" HEIGHT=5>
|
||||
<P>Optional: A list of tuples of extra registry keys to be removed when uninstalling the server. Each tuple is of format ("key", root), where key is a string, and root is one of the win32con.HKEY_* constants (this item is optional, defaulting to HKEY_CLASSES_ROOT)</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<P>Note there are quite a few other keys available. Also note that these annotations are <I>not</I> required - they just make registration simple. Helper functions in the module <CODE>win32com.server.register</CODE> allow you to explicitly specify each of these attributes without attaching them to the class.</P>
|
||||
<P>The header of our class now becomes:</P>
|
||||
<CODE><P>class HelloWorld:</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>_reg_clsid_ = "{7CC9F362-486D-11D1-BB48-0000E838A65F}"</P>
|
||||
<P>_reg_desc_ = "Python Test COM Server"</P>
|
||||
<P>_reg_progid_ = "Python.TestServer"</P>
|
||||
<P>_public_methods_ = ['Hello']</P>
|
||||
<P>[same from here]</P></DIR>
|
||||
</DIR>
|
||||
|
||||
</CODE><H4>Registering the Class</H4>
|
||||
<P>The idiom that most Python COM Servers use is that they register themselves when run as a script (ie, when executed from the command line.) Thus the standard "<CODE>if __name__=='__main___':</CODE>" technique works well.</P>
|
||||
<P>win32com.server.register contains a number of helper functions. The easiest to use is "<CODE>UseCommandLine</CODE>".</P>
|
||||
<P>Registration becomes as simple as:</P>
|
||||
<CODE><P>if __name__=='__main__':<BR>
|
||||
	# ni only for 1.4!<BR>
|
||||
	import ni, win32com.server.register <BR>
|
||||
	win32com.server.register.UseCommandLine(HelloWorld)</P>
|
||||
</CODE><P>Running the script will register our test server.</P>
|
||||
<H2><A NAME="testing">Testing our Class</A></H2>
|
||||
<P>For the purposes of this demonstration, we will test the class using Visual Basic. This code should run under any version of Visual Basic, including VBA found in Microsoft Office. Any COM compliant package could be used alternatively. VB has been used just to prove there is no "smoke and mirrors. For information on how to test the server using Python, please see the <A HREF="QuickStartClientCom.html">Quick Start to Client side COM</A> documentation.</P>
|
||||
<P>This is not a tutorial in VB. The code is just presented! Run it, and it will work!</P>
|
||||
<H2><A NAME="debugging">Debugging the COM Server</A></H2>
|
||||
<P>When things go wrong in COM Servers, there is often nowhere useful for the Python traceback to go, even if such a traceback is generated.</P>
|
||||
<P>Rather than discuss how it works, I will just present the procedure to debug your server:</P>
|
||||
<B><P>To register a debug version of your class</B>, run the script (as above) but pass in a "<CODE>--debug</CODE>" parameter. Eg, for the server above, use the command line "<CODE>testcomserver.py --debug</CODE>".</P>
|
||||
<B><P>To see the debug output generated</B> (and any print statements you may choose to add!) you can simply select the "Remote Debug Trace Collector" from the Pythonwin Tools menu, or run the script "win32traceutil.py" from Windows Explorer or a Command Prompt.</P>
|
||||
<H2><A NAME="Exception">Exception Handling </A></H2>
|
||||
<P>Servers need to be able to provide exception information to their client. In some cases, it may be a simple return code (such as E_NOTIMPLEMENTED), but often it can contain much richer information, describing the error on detail, and even a help file and topic where more information can be found. </P>
|
||||
<P>We use Python class based exceptions to provide this information. The COM framework will examine the exception, and look for certain known attributes. These attributes will be copied across to the COM exception, and passed back to the client. </P>
|
||||
<P>The following attributes are supported, and correspond to the equivalent entry in the COM Exception structure:<BR>
|
||||
<CODE>scode, code, description, source, helpfile and helpcontext</P>
|
||||
</CODE><P>To make working with exceptions easier, there is a helper module "win32com.server.exception.py", which defines a single class. An example of its usage would be: </P>
|
||||
<CODE><P>raise COMException(desc="Must be a string",scode=winerror.E_INVALIDARG,helpfile="myhelp.hlp",...)</CODE> </P>
|
||||
<P>(Note the <CODE>COMException class supports (and translates) "desc" as a shortcut for "description", but the framework requires "description")</P>
|
||||
</CODE><H2><A NAME="Policies">Server Policies</A></H2>
|
||||
<P>This is information about how it all hangs together. The casual COM author need not know this. </P>
|
||||
<P>Whenever a Python Server needs to be created, the C++ framework first instantiates a "policy" object. This "policy" object is the gatekeeper for the COM Server - it is responsible for creating the underlying Python object that is the server (ie, your object), and also for translating the underlying COM requests for the object. </P>
|
||||
<P>This policy object handles all of the underlying COM functionality. For example, COM requires all methods and properties to have unique numeric ID's associated with them. The policy object manages the creation of these ID's for the underlying Python methods and attributes. Similarly, when the client whishes to call a method with ID 123, the policy object translates this back to the actual method, and makes the call. </P>
|
||||
<P>It should be noted that the operation of the "policy" object could be dictated by the Python object - the policy object has many defaults, but the actual Python class can always dictate its operation. </P>
|
||||
<H3>Default Policy attributes </H3>
|
||||
<P>The default policy object has a few special attributes that define who the object is exposed to COM. The example above shows the _public_methods attribute, but this section describes all such attributes in detail. </P>
|
||||
<H5>_public_methods_ </H5>
|
||||
<P>Required list of strings, containing the names of all methods to be exposed to COM. It is possible this will be enhanced in the future (eg, possibly '*' will be recognised to say all methods, or some other ideas…) </P>
|
||||
<H5>_public_attrs_ </H5>
|
||||
<P>Optional list of strings containing all attribute names to be exposed, both for reading and writing. The attribute names must be valid instance variables. </P>
|
||||
<H5>_readonly_attrs_ </H5>
|
||||
<P>Optional list of strings defining the name of attributes exposed read-only. </P>
|
||||
<H5>_com_interfaces_ </H5>
|
||||
<P>Optional list of IIDs exposed by this object. If this attribute is missing, IID_IDispatch is assumed (ie, if not supplied, the COM object will be created as a normal Automation object.</P>
|
||||
<P>and actual instance attributes: </P>
|
||||
<P>_dynamic_ : optional method </P>
|
||||
<P>_value_ : optional attribute </P>
|
||||
<P>_query_interface_ : optional method </P>
|
||||
<P>_NewEnum : optional method </P>
|
||||
<P>_Evaluate : optional method </P></BODY>
|
||||
</HTML>
|
22
venv/Lib/site-packages/win32com/HTML/docindex.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>win32com Documentation Index</TITLE>
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY LINK="#0000ff" VLINK="#800080">
|
||||
|
||||
<H1><IMG SRC="image/pycom_blowing.gif" WIDTH=549 HEIGHT=99 ALT="Python and COM - Blowing the others away"></H1>
|
||||
<H1>PythonCOM Documentation Index</H1>
|
||||
<P>The following documentation is available</P>
|
||||
<P><A HREF="QuickStartClientCom.html">A Quick Start to Client Side COM</A> (including makepy)</P>
|
||||
<P><A HREF="QuickStartServerCom.html">A Quick Start to Server Side COM</A></P>
|
||||
<P><A HREF="GeneratedSupport.html">Information on generated Python files (ie, what makepy generates)</A></P>
|
||||
<P><A HREF="variant.html">An advanced VARIANT object which can give more control over parameter types</A></P>
|
||||
<P><A HREF="package.html">A brief description of the win32com package structure</A></P>
|
||||
<P><A HREF="PythonCOM.html">Python COM Implementation documentation</A></P>
|
||||
<P><A HREF="misc.html">Misc stuff I don’t know where to put anywhere else</A></P>
|
||||
<H3>ActiveX Scripting</H3>
|
||||
<P><A HREF="../../win32comext/axscript/demos/client/ie/demo.htm">ActiveX Scripting Demos</A></P></BODY>
|
||||
</HTML>
|
BIN
venv/Lib/site-packages/win32com/HTML/image/BTN_HomePage.gif
Normal file
After Width: | Height: | Size: 211 B |
BIN
venv/Lib/site-packages/win32com/HTML/image/BTN_ManualTop.gif
Normal file
After Width: | Height: | Size: 215 B |
BIN
venv/Lib/site-packages/win32com/HTML/image/BTN_NextPage.gif
Normal file
After Width: | Height: | Size: 218 B |
BIN
venv/Lib/site-packages/win32com/HTML/image/BTN_PrevPage.gif
Normal file
After Width: | Height: | Size: 216 B |
BIN
venv/Lib/site-packages/win32com/HTML/image/blank.gif
Normal file
After Width: | Height: | Size: 864 B |
BIN
venv/Lib/site-packages/win32com/HTML/image/pycom_blowing.gif
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
venv/Lib/site-packages/win32com/HTML/image/pythoncom.gif
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
venv/Lib/site-packages/win32com/HTML/image/www_icon.gif
Normal file
After Width: | Height: | Size: 275 B |
31
venv/Lib/site-packages/win32com/HTML/index.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>win32com</TITLE>
|
||||
<META NAME="Template" CONTENT="C:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" LINK="#0000ff" VLINK="#0000ff">
|
||||
<DIR>
|
||||
|
||||
<P><!-- Enclose the entire page in UL, so bullets don't indent. --></P>
|
||||
<H1><IMG SRC="image/pycom_blowing.gif" WIDTH=549 HEIGHT=99></H1>
|
||||
<H2>Python and COM</H2>
|
||||
<H3>Introduction</H3>
|
||||
<P>Python has an excellent interface to COM (also known variously as OLE2, ActiveX, etc).</P>
|
||||
<P>The Python COM package can be used to interface to almost any COM program (such as the MS-Office suite), write servers that can be hosted by any COM client (such as Visual Basic or C++), and has even been used to provide the core ActiveX Scripting Support. </P>
|
||||
|
||||
|
||||
<UL>
|
||||
<LI>Note that win32com is now released in the win32all installation package. The <A HREF="../win32all/win32all.exe">installation EXE can be downloaded</A>, or you <A HREF="../win32all/">can jump to the win32all readme</A> for more details. </LI>
|
||||
<LI>Here is the <A HREF="win32com_src.zip">win32com source code</A> in a zip file. </LI></UL>
|
||||
</DIR>
|
||||
<DIR>
|
||||
|
||||
<H3>Documentation</H3>
|
||||
<P><A HREF="ActiveXScripting.html">Preliminary Active Scripting and Debugging documentation</A> is available.</P>
|
||||
<P>2 Quick-Start guides have been provided, which also contain other links. See the <A HREF="QuickStartClientCom.html">Quick Start for Client side COM</A> and the <A HREF="QuickStartServerCom.html">Quick Start for Server side COM</A> </P>
|
||||
</P></DIR>
|
||||
</DIR>
|
||||
</BODY>
|
||||
</HTML>
|
18
venv/Lib/site-packages/win32com/HTML/misc.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>Misc win32com Stuff</TITLE>
|
||||
<META NAME="Version" CONTENT="8.0.3410">
|
||||
<META NAME="Date" CONTENT="10/11/96">
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\HTML.DOT">
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" BGCOLOR="#ffffff">
|
||||
|
||||
<H1>Misc stuff I don’t know where to put anywhere else</H1>
|
||||
<H4>Client Side Dispatch</H4>
|
||||
<P>Using win32com.client.Dispatch automatically invokes all the win32com client side "smarts", including automatic usage of generated .py files etc.</P>
|
||||
<P>If you wish to avoid that, and use truly "dynamic" objects (ie, there is generated .py support available, but you wish to avoid it), you can use win32com.client.dynamic.Dispatch</P>
|
||||
<B><P>_print_details_() method</B><BR>
|
||||
If win32com.client.dynamic.Dispatch is used, the objects have a _print_details_() method available, which prints all relevant knowledge about an object (for example, all methods and properties). For objects that do not expose runtime type information, _print_details_ may not list anything.</P></BODY>
|
||||
</HTML>
|
37
venv/Lib/site-packages/win32com/HTML/package.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>The win32com package</TITLE>
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\html.dot">
|
||||
</HEAD>
|
||||
<BODY LINK="#0000ff" VLINK="#800080">
|
||||
|
||||
<H1><IMG SRC="image/pycom_blowing.gif" WIDTH=549 HEIGHT=99 ALT="Python and COM - Blowing the others away"></H1>
|
||||
<H1>The win32com package </H1>
|
||||
<FONT SIZE=2><P>This document describes the win32com package in general terms.</FONT> </P>
|
||||
<FONT SIZE=2><P>The COM support can be thought of as existing in 2 main portions - the C++ support code (the core PythonCOM module), and helper code, implemented in Python. The total package is known as "win32com".</FONT> </P>
|
||||
<FONT SIZE=2><P>The win32com support is stand-alone. It does not require Pythonwin.</FONT> </P>
|
||||
<H2>The win32com package </H2>
|
||||
<FONT SIZE=2><P>To facilitate an orderly framework, the Python "ni" module has been used, and the entire package is known as "win32com". As is normal for such packages, win32com itself does not provide any functionality. Some of the modules are described below:</FONT> </P>
|
||||
|
||||
<UL>
|
||||
<B><FONT SIZE=2><LI>win32com.pythoncom - core C++ support</B>. <BR>
|
||||
This module is rarely used directly by programmers - instead the other "helper" module are used, which themselves draw on the core pythoncom services.</FONT> </LI>
|
||||
<B><FONT SIZE=2><LI>win32com.client package<BR>
|
||||
</B>Support for COM clients used by Python. Some of the modules in this package allow for dynamic usage of COM clients, a module for generating .py files for certain COM servers, etc.</FONT> </LI>
|
||||
<B><FONT SIZE=2><LI>win32com.server package<BR>
|
||||
</B>Support for COM servers written in Python. The modules in this package provide most of the underlying framework for magically turning Python classes into COM servers, exposing the correct public methods, registering your server in the registry, etc. </LI>
|
||||
<B><LI>win32com.axscript<BR>
|
||||
</B>ActiveX Scripting implementation for Python.</FONT> </LI>
|
||||
<B><FONT SIZE=2><LI>win32com.axdebug<BR>
|
||||
</B>Active Debugging implementation for Python</FONT> </LI>
|
||||
<B><FONT SIZE=2><LI>win32com.mapi<BR>
|
||||
</B>Utilities for working with MAPI and the Microsoft Exchange Server</LI></UL>
|
||||
|
||||
</FONT><P> </P>
|
||||
<H2>The pythoncom module </H2>
|
||||
<FONT SIZE=2><P>The pythoncom module is the underlying C++ support for all COM related objects. In general, Python programmers will not use this module directly, but use win32com helper classes and functions. </P>
|
||||
<P>This module exposes a C++ like interface to COM - there are objects implemented in pythoncom that have methods "QueryInterface()", "Invoke()", just like the C++ API. If you are using COM in C++, you would not call a method directly, you would use pObject->Invoke( …, MethodId, argArray…). Similarly, if you are using pythoncom directly, you must also use the Invoke method to call an object's exposed method.</FONT> </P>
|
||||
<FONT SIZE=2><P>There are some Python wrappers for hiding this raw interface, meaning you should almost never need to use the pythoncom module directly. These helpers translate a "natural" looking interface (eg, obj.SomeMethod()) into the underlying Invoke call.</P></FONT></BODY>
|
||||
</HTML>
|
162
venv/Lib/site-packages/win32com/HTML/variant.html
Normal file
|
@ -0,0 +1,162 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>win32com.client.VARIANT</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H2>Introduction</H2>
|
||||
<p>
|
||||
win32com attempts to provide a seamless COM interface and hide many COM
|
||||
implementation details, including the use of COM VARIANT structures. This
|
||||
means that in most cases, you just call a COM object using normal Python
|
||||
objects as parameters and get back normal Python objects as results.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
However, in some cases this doesn't work very well, particularly when using
|
||||
"dynamic" (aka late-bound) objects, or when using "makepy" (aka early-bound)
|
||||
objects which only declare a parameter is a VARIANT.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>win32com.client.VARIANT</code> object is designed to overcome these
|
||||
problems.
|
||||
</p>
|
||||
|
||||
<h2>Drawbacks</h2>
|
||||
The primary issue with this approach is that the programmer must learn more
|
||||
about COM VARIANTs than otherwise - they need to know concepts such as
|
||||
variants being <em>byref</em>, holding arrays, or that some may hold 32bit
|
||||
unsigned integers while others hold 64bit signed ints, and they need to
|
||||
understand this in the context of a single method call. In short, this is
|
||||
a relatively advanced feature. The good news though is that use of these
|
||||
objects should never cause your program to hard-crash - the worst you should
|
||||
expect are Python or COM exceptions being thrown.
|
||||
|
||||
<h2>The VARIANT object</h2>
|
||||
|
||||
The VARIANT object lives in <code>win32com.client</code>. The constructor
|
||||
takes 2 parameters - the 'variant type' and the value. The 'variant type' is
|
||||
an integer and can be one or more of the <code>pythoncom.VT_*</code> values,
|
||||
possibly or'd together.
|
||||
|
||||
<p>For example, to create a VARIANT object which defines a byref array of
|
||||
32bit integers, you could use:
|
||||
|
||||
<pre>
|
||||
>>> from win32com.client import VARIANT
|
||||
>>> import pythoncom
|
||||
>>> v = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_I4,
|
||||
... [1,2,3,4])
|
||||
>>> v
|
||||
win32com.client.VARIANT(24579, [1, 2, 3, 4])
|
||||
>>>
|
||||
</pre>
|
||||
|
||||
This variable can then be used whereever a COM VARIANT is expected.
|
||||
|
||||
<h2>Example usage with dynamic objects.</h2>
|
||||
|
||||
For this example we will use the COM object used for win32com testing,
|
||||
<code>PyCOMTest.PyCOMTest</code>. This object defines a method which is
|
||||
defined in IDL as:
|
||||
<pre>
|
||||
HRESULT DoubleInOutString([in,out] BSTR *str);
|
||||
</pre>
|
||||
|
||||
As you can see, it takes a single string parameter which is also used as
|
||||
an "out" parameter - the single parameter will be updated after the call.
|
||||
The implementation of the method simply "doubles" the string.
|
||||
|
||||
<p>If the object has a type-library, this method works fine with makepy
|
||||
generated support. For example:
|
||||
|
||||
<pre>
|
||||
>>> from win32com.client.gencache import EnsureDispatch
|
||||
>>> ob = EnsureDispatch("PyCOMTest.PyCOMTest")
|
||||
>>> ob.DoubleInOutString("Hello")
|
||||
u'HelloHello'
|
||||
>>>
|
||||
</pre>
|
||||
|
||||
However, if makepy support is not available the method does not work as
|
||||
expected. For the next example we will use <code>DumbDispatch</code> to
|
||||
simulate the object not having a type-library.
|
||||
|
||||
<pre>
|
||||
>>> import win32com.client.dynamic
|
||||
>>> ob = win32com.client.dynamic.DumbDispatch("PyCOMTest.PyCOMTest")
|
||||
>>> ob.DoubleInOutString("Hello")
|
||||
>>>
|
||||
</pre>
|
||||
|
||||
As you can see, no result came back from the function. This is because
|
||||
win32com has no type information available to use, so doesn't know the
|
||||
parameter should be passed as a <code>byref</code> parameter. To work
|
||||
around this, we can use the <code>VARIANT</code> object.
|
||||
|
||||
<p>The following example explicitly creates a VARIANT object with a
|
||||
variant type of a byref string and a value 'Hello'. After making the
|
||||
call with this VARIANT the value is updated.
|
||||
|
||||
<pre>
|
||||
>>> import win32com.client.dynamic
|
||||
>>> from win32com.client import VARIANT
|
||||
>>> import pythoncom
|
||||
>>> ob = win32com.client.dynamic.DumbDispatch("PyCOMTest.PyCOMTest")
|
||||
>>> variant = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, "Hello")
|
||||
>>> variant.value # check the value before the call.
|
||||
'Hello'
|
||||
>>> ob.DoubleInOutString(variant)
|
||||
>>> variant.value
|
||||
u'HelloHello'
|
||||
>>>
|
||||
</pre>
|
||||
|
||||
<h2>Usage with generated objects</h2>
|
||||
|
||||
In most cases, objects with makepy support (ie, 'generated' objects) don't
|
||||
need to use the VARIANT object - the type information means win32com can guess
|
||||
the right thing to pass. However, in some cases the VARIANT object can still
|
||||
be useful.
|
||||
|
||||
Imagine a poorly specified object with IDL like:
|
||||
|
||||
<pre>
|
||||
HRESULT DoSomething([in] VARIANT value);
|
||||
</pre>
|
||||
|
||||
But also imagine that the object has a limitation that if the parameter is an
|
||||
integer, it must be a 32bit unsigned value - any other integer representation
|
||||
will fail.
|
||||
|
||||
<p>If you just pass a regular Python integer to this function, it will
|
||||
generally be passed as a 32bit signed integer and given the limitation above,
|
||||
will fail. The VARIANT object allows you to work around the limitation - just
|
||||
create a variant object <code>VARIANT(pythoncom.VT_UI4, int_value)</code> and
|
||||
pass that - the function will then be called with the explicit type you
|
||||
specified and will succeed.
|
||||
|
||||
<p>Note that you can not use a VARIANT object to override the types described
|
||||
in a type library. If a makepy generated class specifies that a VT_UI2 is
|
||||
expected, attempting to pass a VARIANT object will fail. In this case you
|
||||
would need to hack around the problem. For example, imagine <code>ob</code>
|
||||
was a COM object which a method called <code>foo</code> and you wanted to
|
||||
override the type declaration for <code>foo</code> by passing a VARIANT.
|
||||
You could do something like:
|
||||
|
||||
<pre>
|
||||
>>> import win32com.client.dynamic
|
||||
>>> from win32com.client import VARIANT
|
||||
>>> import pythoncom
|
||||
>>> dumbob = win32com.client.dynamic.DumbDispatch(ob)
|
||||
>>> variant = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, "Hello")
|
||||
>>> dumbob.foo(variant)
|
||||
</pre>
|
||||
|
||||
The code above converts the makepy supported <code>ob</code> into a
|
||||
'dumb' (ie, non-makepy supported) version of the object, which will then
|
||||
allow you to use VARIANT objects for the problematic methods.
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
30
venv/Lib/site-packages/win32com/License.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
Unless stated in the specfic source file, this work is
|
||||
Copyright (c) 1996-2008, Greg Stein and Mark Hammond.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither names of Greg Stein, Mark Hammond nor the name of contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
120
venv/Lib/site-packages/win32com/__init__.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
#
|
||||
# Initialization for the win32com package
|
||||
#
|
||||
|
||||
import win32api, sys, os
|
||||
import pythoncom
|
||||
|
||||
# flag if we are in a "frozen" build.
|
||||
_frozen = getattr(sys, "frozen", 1==0)
|
||||
# pythoncom dumbly defaults this to zero - we believe sys.frozen over it.
|
||||
if _frozen and not getattr(pythoncom, "frozen", 0):
|
||||
pythoncom.frozen = sys.frozen
|
||||
|
||||
# Add support for an external "COM Extensions" path.
|
||||
# Concept is that you can register a seperate path to be used for
|
||||
# COM extensions, outside of the win32com directory. These modules, however,
|
||||
# look identical to win32com built-in modules.
|
||||
# This is the technique that we use for the "standard" COM extensions.
|
||||
# eg "win32com.mapi" or "win32com.axscript" both work, even though they do not
|
||||
# live under the main win32com directory.
|
||||
__gen_path__ = ''
|
||||
__build_path__ = None
|
||||
### TODO - Load _all_ \\Extensions subkeys - for now, we only read the default
|
||||
### Modules will work if loaded into "win32comext" path.
|
||||
|
||||
def SetupEnvironment():
|
||||
HKEY_LOCAL_MACHINE = -2147483646 # Avoid pulling in win32con for just these...
|
||||
KEY_QUERY_VALUE = 0x1
|
||||
# Open the root key once, as this is quite slow on NT.
|
||||
try:
|
||||
keyName = "SOFTWARE\\Python\\PythonCore\\%s\\PythonPath\\win32com" % sys.winver
|
||||
key = win32api.RegOpenKey(HKEY_LOCAL_MACHINE , keyName, 0, KEY_QUERY_VALUE)
|
||||
except (win32api.error, AttributeError):
|
||||
key = None
|
||||
|
||||
try:
|
||||
found = 0
|
||||
if key is not None:
|
||||
try:
|
||||
__path__.append( win32api.RegQueryValue(key, "Extensions" ))
|
||||
found = 1
|
||||
except win32api.error:
|
||||
# Nothing registered
|
||||
pass
|
||||
if not found:
|
||||
try:
|
||||
__path__.append( win32api.GetFullPathName( __path__[0] + "\\..\\win32comext") )
|
||||
except win32api.error:
|
||||
# Give up in disgust!
|
||||
pass
|
||||
|
||||
# For the sake of developers, we also look up a "BuildPath" key
|
||||
# If extension modules add support, we can load their .pyd's from a completely
|
||||
# different directory (see the comments below)
|
||||
try:
|
||||
if key is not None:
|
||||
global __build_path__
|
||||
__build_path__ = win32api.RegQueryValue(key, "BuildPath")
|
||||
__path__.append(__build_path__)
|
||||
except win32api.error:
|
||||
# __build_path__ neednt be defined.
|
||||
pass
|
||||
global __gen_path__
|
||||
if key is not None:
|
||||
try:
|
||||
__gen_path__ = win32api.RegQueryValue(key, "GenPath")
|
||||
except win32api.error:
|
||||
pass
|
||||
finally:
|
||||
if key is not None:
|
||||
key.Close()
|
||||
|
||||
# A Helper for developers. A sub-package's __init__ can call this help function,
|
||||
# which allows the .pyd files for the extension to live in a special "Build" directory
|
||||
# (which the win32com developers do!)
|
||||
def __PackageSupportBuildPath__(package_path):
|
||||
# See if we have a special directory for the binaries (for developers)
|
||||
if not _frozen and __build_path__:
|
||||
package_path.append(__build_path__)
|
||||
|
||||
if not _frozen:
|
||||
SetupEnvironment()
|
||||
|
||||
# If we don't have a special __gen_path__, see if we have a gen_py as a
|
||||
# normal module and use that (ie, "win32com.gen_py" may already exist as
|
||||
# a package.
|
||||
if not __gen_path__:
|
||||
try:
|
||||
import win32com.gen_py
|
||||
# hrmph - 3.3 throws: TypeError: '_NamespacePath' object does not support indexing
|
||||
# attempting to get __path__[0] - but I can't quickly repro this stand-alone.
|
||||
# Work around it by using an iterator.
|
||||
__gen_path__ = next(iter(sys.modules["win32com.gen_py"].__path__))
|
||||
except ImportError:
|
||||
# If a win32com\gen_py directory already exists, then we use it
|
||||
# (gencache doesn't insist it have an __init__, but our __import__
|
||||
# above does!
|
||||
__gen_path__ = os.path.abspath(os.path.join(__path__[0], "gen_py"))
|
||||
if not os.path.isdir(__gen_path__):
|
||||
# We used to dynamically create a directory under win32com -
|
||||
# but this sucks. If the dir doesn't already exist, we we
|
||||
# create a version specific directory under the user temp
|
||||
# directory.
|
||||
__gen_path__ = os.path.join(
|
||||
win32api.GetTempPath(), "gen_py",
|
||||
"%d.%d" % (sys.version_info[0], sys.version_info[1]))
|
||||
|
||||
# we must have a __gen_path__, but may not have a gen_py module -
|
||||
# set that up.
|
||||
if "win32com.gen_py" not in sys.modules:
|
||||
# Create a "win32com.gen_py", but with a custom __path__
|
||||
import imp
|
||||
gen_py = imp.new_module("win32com.gen_py")
|
||||
gen_py.__path__ = [ __gen_path__ ]
|
||||
sys.modules[gen_py.__name__]=gen_py
|
||||
del imp
|
||||
gen_py = sys.modules["win32com.gen_py"]
|
||||
|
||||
# get rid of these for module users
|
||||
del os, sys, win32api, pythoncom
|
BIN
venv/Lib/site-packages/win32com/__pycache__/util.cpython-36.pyc
Normal file
53
venv/Lib/site-packages/win32com/client/CLSIDToClass.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
"""Manages a dictionary of CLSID strings to Python classes.
|
||||
|
||||
Primary use of this module is to allow modules generated by
|
||||
makepy.py to share classes. @makepy@ automatically generates code
|
||||
which interacts with this module. You should never need to reference
|
||||
this module directly.
|
||||
|
||||
This module only provides support for modules which have been previously
|
||||
been imported. The gencache module provides some support for loading modules
|
||||
on demand - once done, this module supports it...
|
||||
|
||||
As an example, the MSACCESS.TLB type library makes reference to the
|
||||
CLSID of the Database object, as defined in DAO3032.DLL. This
|
||||
allows code using the MSAccess wrapper to natively use Databases.
|
||||
|
||||
This obviously applies to all cooperating objects, not just DAO and
|
||||
Access.
|
||||
"""
|
||||
mapCLSIDToClass = {}
|
||||
|
||||
def RegisterCLSID( clsid, pythonClass ):
|
||||
"""Register a class that wraps a CLSID
|
||||
|
||||
This function allows a CLSID to be globally associated with a class.
|
||||
Certain module will automatically convert an IDispatch object to an
|
||||
instance of the associated class.
|
||||
"""
|
||||
|
||||
mapCLSIDToClass[str(clsid)] = pythonClass
|
||||
|
||||
def RegisterCLSIDsFromDict( dict ):
|
||||
"""Register a dictionary of CLSID's and classes.
|
||||
|
||||
This module performs the same function as @RegisterCLSID@, but for
|
||||
an entire dictionary of associations.
|
||||
|
||||
Typically called by makepy generated modules at import time.
|
||||
"""
|
||||
mapCLSIDToClass.update(dict)
|
||||
|
||||
def GetClass(clsid):
|
||||
"""Given a CLSID, return the globally associated class.
|
||||
|
||||
clsid -- a string CLSID representation to check.
|
||||
"""
|
||||
return mapCLSIDToClass[clsid]
|
||||
|
||||
def HasClass(clsid):
|
||||
"""Determines if the CLSID has an associated class.
|
||||
|
||||
clsid -- the string CLSID to check
|
||||
"""
|
||||
return clsid in mapCLSIDToClass
|
547
venv/Lib/site-packages/win32com/client/__init__.py
Normal file
|
@ -0,0 +1,547 @@
|
|||
# This module exists to create the "best" dispatch object for a given
|
||||
# object. If "makepy" support for a given object is detected, it is
|
||||
# used, otherwise a dynamic dispatch object.
|
||||
|
||||
# Note that if the unknown dispatch object then returns a known
|
||||
# dispatch object, the known class will be used. This contrasts
|
||||
# with dynamic.Dispatch behaviour, where dynamic objects are always used.
|
||||
|
||||
import pythoncom
|
||||
from . import dynamic
|
||||
from . import gencache
|
||||
import sys
|
||||
import pywintypes
|
||||
|
||||
_PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
|
||||
|
||||
|
||||
def __WrapDispatch(dispatch, userName = None, resultCLSID = None, typeinfo = None, \
|
||||
UnicodeToString=None, clsctx = pythoncom.CLSCTX_SERVER,
|
||||
WrapperClass = None):
|
||||
"""
|
||||
Helper function to return a makepy generated class for a CLSID if it exists,
|
||||
otherwise cope by using CDispatch.
|
||||
"""
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
if resultCLSID is None:
|
||||
try:
|
||||
typeinfo = dispatch.GetTypeInfo()
|
||||
if typeinfo is not None: # Some objects return NULL, some raise exceptions...
|
||||
resultCLSID = str(typeinfo.GetTypeAttr()[0])
|
||||
except (pythoncom.com_error, AttributeError):
|
||||
pass
|
||||
if resultCLSID is not None:
|
||||
from . import gencache
|
||||
# Attempt to load generated module support
|
||||
# This may load the module, and make it available
|
||||
klass = gencache.GetClassForCLSID(resultCLSID)
|
||||
if klass is not None:
|
||||
return klass(dispatch)
|
||||
|
||||
# Return a "dynamic" object - best we can do!
|
||||
if WrapperClass is None: WrapperClass = CDispatch
|
||||
return dynamic.Dispatch(dispatch, userName, WrapperClass, typeinfo, clsctx=clsctx)
|
||||
|
||||
|
||||
def GetObject(Pathname = None, Class = None, clsctx = None):
|
||||
"""
|
||||
Mimic VB's GetObject() function.
|
||||
|
||||
ob = GetObject(Class = "ProgID") or GetObject(Class = clsid) will
|
||||
connect to an already running instance of the COM object.
|
||||
|
||||
ob = GetObject(r"c:\blah\blah\foo.xls") (aka the COM moniker syntax)
|
||||
will return a ready to use Python wrapping of the required COM object.
|
||||
|
||||
Note: You must specifiy one or the other of these arguments. I know
|
||||
this isn't pretty, but it is what VB does. Blech. If you don't
|
||||
I'll throw ValueError at you. :)
|
||||
|
||||
This will most likely throw pythoncom.com_error if anything fails.
|
||||
"""
|
||||
if clsctx is None:
|
||||
clsctx = pythoncom.CLSCTX_ALL
|
||||
|
||||
if (Pathname is None and Class is None) or \
|
||||
(Pathname is not None and Class is not None):
|
||||
raise ValueError("You must specify a value for Pathname or Class, but not both.")
|
||||
|
||||
if Class is not None:
|
||||
return GetActiveObject(Class, clsctx)
|
||||
else:
|
||||
return Moniker(Pathname, clsctx)
|
||||
|
||||
def GetActiveObject(Class, clsctx = pythoncom.CLSCTX_ALL):
|
||||
"""
|
||||
Python friendly version of GetObject's ProgID/CLSID functionality.
|
||||
"""
|
||||
resultCLSID = pywintypes.IID(Class)
|
||||
dispatch = pythoncom.GetActiveObject(resultCLSID)
|
||||
dispatch = dispatch.QueryInterface(pythoncom.IID_IDispatch)
|
||||
return __WrapDispatch(dispatch, Class, resultCLSID = resultCLSID, clsctx = clsctx)
|
||||
|
||||
def Moniker(Pathname, clsctx = pythoncom.CLSCTX_ALL):
|
||||
"""
|
||||
Python friendly version of GetObject's moniker functionality.
|
||||
"""
|
||||
moniker, i, bindCtx = pythoncom.MkParseDisplayName(Pathname)
|
||||
dispatch = moniker.BindToObject(bindCtx, None, pythoncom.IID_IDispatch)
|
||||
return __WrapDispatch(dispatch, Pathname, clsctx=clsctx)
|
||||
|
||||
def Dispatch(dispatch, userName = None, resultCLSID = None, typeinfo = None, UnicodeToString=None, clsctx = pythoncom.CLSCTX_SERVER):
|
||||
"""Creates a Dispatch based COM object.
|
||||
"""
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
|
||||
return __WrapDispatch(dispatch, userName, resultCLSID, typeinfo, clsctx=clsctx)
|
||||
|
||||
def DispatchEx(clsid, machine=None, userName = None, resultCLSID = None, typeinfo = None, UnicodeToString=None, clsctx = None):
|
||||
"""Creates a Dispatch based COM object on a specific machine.
|
||||
"""
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
# If InProc is registered, DCOM will use it regardless of the machine name
|
||||
# (and regardless of the DCOM config for the object.) So unless the user
|
||||
# specifies otherwise, we exclude inproc apps when a remote machine is used.
|
||||
if clsctx is None:
|
||||
clsctx = pythoncom.CLSCTX_SERVER
|
||||
if machine is not None: clsctx = clsctx & ~pythoncom.CLSCTX_INPROC
|
||||
if machine is None:
|
||||
serverInfo = None
|
||||
else:
|
||||
serverInfo = (machine,)
|
||||
if userName is None: userName = clsid
|
||||
dispatch = pythoncom.CoCreateInstanceEx(clsid, None, clsctx, serverInfo, (pythoncom.IID_IDispatch,))[0]
|
||||
return Dispatch(dispatch, userName, resultCLSID, typeinfo, clsctx=clsctx)
|
||||
|
||||
class CDispatch(dynamic.CDispatch):
|
||||
"""
|
||||
The dynamic class used as a last resort.
|
||||
The purpose of this overriding of dynamic.CDispatch is to perpetuate the policy
|
||||
of using the makepy generated wrapper Python class instead of dynamic.CDispatch
|
||||
if/when possible.
|
||||
"""
|
||||
def _wrap_dispatch_(self, ob, userName = None, returnCLSID = None, UnicodeToString=None):
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
return Dispatch(ob, userName, returnCLSID,None)
|
||||
|
||||
def CastTo(ob, target, typelib = None):
|
||||
"""'Cast' a COM object to another interface"""
|
||||
# todo - should support target being an IID
|
||||
mod = None
|
||||
if typelib is not None: # caller specified target typelib (TypelibSpec). See e.g. selecttlb.EnumTlbs().
|
||||
mod = gencache.MakeModuleForTypelib(typelib.clsid, typelib.lcid, int(typelib.major, 16), int(typelib.minor, 16))
|
||||
if not hasattr(mod, target):
|
||||
raise ValueError("The interface name '%s' does not appear in the " \
|
||||
"specified library %r" % (target, typelib.ver_desc))
|
||||
|
||||
elif hasattr(target, "index"): # string like
|
||||
# for now, we assume makepy for this to work.
|
||||
if "CLSID" not in ob.__class__.__dict__:
|
||||
# Eeek - no makepy support - try and build it.
|
||||
ob = gencache.EnsureDispatch(ob)
|
||||
if "CLSID" not in ob.__class__.__dict__:
|
||||
raise ValueError("Must be a makepy-able object for this to work")
|
||||
clsid = ob.CLSID
|
||||
# Lots of hoops to support "demand-build" - ie, generating
|
||||
# code for an interface first time it is used. We assume the
|
||||
# interface name exists in the same library as the object.
|
||||
# This is generally the case - only referenced typelibs may be
|
||||
# a problem, and we can handle that later. Maybe <wink>
|
||||
# So get the generated module for the library itself, then
|
||||
# find the interface CLSID there.
|
||||
mod = gencache.GetModuleForCLSID(clsid)
|
||||
# Get the 'root' module.
|
||||
mod = gencache.GetModuleForTypelib(mod.CLSID, mod.LCID,
|
||||
mod.MajorVersion, mod.MinorVersion)
|
||||
# Find the CLSID of the target
|
||||
target_clsid = mod.NamesToIIDMap.get(target)
|
||||
if target_clsid is None:
|
||||
raise ValueError("The interface name '%s' does not appear in the " \
|
||||
"same library as object '%r'" % (target, ob))
|
||||
mod = gencache.GetModuleForCLSID(target_clsid)
|
||||
if mod is not None:
|
||||
target_class = getattr(mod, target)
|
||||
# resolve coclass to interface
|
||||
target_class = getattr(target_class, "default_interface", target_class)
|
||||
return target_class(ob) # auto QI magic happens
|
||||
raise ValueError
|
||||
|
||||
class Constants:
|
||||
"""A container for generated COM constants.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.__dicts__ = [] # A list of dictionaries
|
||||
def __getattr__(self, a):
|
||||
for d in self.__dicts__:
|
||||
if a in d:
|
||||
return d[a]
|
||||
raise AttributeError(a)
|
||||
|
||||
# And create an instance.
|
||||
constants = Constants()
|
||||
|
||||
# A helpers for DispatchWithEvents - this becomes __setattr__ for the
|
||||
# temporary class.
|
||||
def _event_setattr_(self, attr, val):
|
||||
try:
|
||||
# Does the COM object have an attribute of this name?
|
||||
self.__class__.__bases__[0].__setattr__(self, attr, val)
|
||||
except AttributeError:
|
||||
# Otherwise just stash it away in the instance.
|
||||
self.__dict__[attr] = val
|
||||
|
||||
# An instance of this "proxy" is created to break the COM circular references
|
||||
# that exist (ie, when we connect to the COM events, COM keeps a reference
|
||||
# to the object. Thus, the Event connection must be manually broken before
|
||||
# our object can die. This solves the problem by manually breaking the connection
|
||||
# to the real object as the proxy dies.
|
||||
class EventsProxy:
|
||||
def __init__(self, ob):
|
||||
self.__dict__['_obj_'] = ob
|
||||
def __del__(self):
|
||||
try:
|
||||
# If there is a COM error on disconnection we should
|
||||
# just ignore it - object probably already shut down...
|
||||
self._obj_.close()
|
||||
except pythoncom.com_error:
|
||||
pass
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self._obj_, attr)
|
||||
def __setattr__(self, attr, val):
|
||||
setattr(self._obj_, attr, val)
|
||||
|
||||
def DispatchWithEvents(clsid, user_event_class):
|
||||
"""Create a COM object that can fire events to a user defined class.
|
||||
clsid -- The ProgID or CLSID of the object to create.
|
||||
user_event_class -- A Python class object that responds to the events.
|
||||
|
||||
This requires makepy support for the COM object being created. If
|
||||
this support does not exist it will be automatically generated by
|
||||
this function. If the object does not support makepy, a TypeError
|
||||
exception will be raised.
|
||||
|
||||
The result is a class instance that both represents the COM object
|
||||
and handles events from the COM object.
|
||||
|
||||
It is important to note that the returned instance is not a direct
|
||||
instance of the user_event_class, but an instance of a temporary
|
||||
class object that derives from three classes:
|
||||
* The makepy generated class for the COM object
|
||||
* The makepy generated class for the COM events
|
||||
* The user_event_class as passed to this function.
|
||||
|
||||
If this is not suitable, see the getevents function for an alternative
|
||||
technique of handling events.
|
||||
|
||||
Object Lifetimes: Whenever the object returned from this function is
|
||||
cleaned-up by Python, the events will be disconnected from
|
||||
the COM object. This is almost always what should happen,
|
||||
but see the documentation for getevents() for more details.
|
||||
|
||||
Example:
|
||||
|
||||
>>> class IEEvents:
|
||||
... def OnVisible(self, visible):
|
||||
... print "Visible changed:", visible
|
||||
...
|
||||
>>> ie = DispatchWithEvents("InternetExplorer.Application", IEEvents)
|
||||
>>> ie.Visible = 1
|
||||
Visible changed: 1
|
||||
>>>
|
||||
"""
|
||||
# Create/Get the object.
|
||||
disp = Dispatch(clsid)
|
||||
if not disp.__class__.__dict__.get("CLSID"): # Eeek - no makepy support - try and build it.
|
||||
try:
|
||||
ti = disp._oleobj_.GetTypeInfo()
|
||||
disp_clsid = ti.GetTypeAttr()[0]
|
||||
tlb, index = ti.GetContainingTypeLib()
|
||||
tla = tlb.GetLibAttr()
|
||||
gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4], bValidateFile=0)
|
||||
# Get the class from the module.
|
||||
disp_class = gencache.GetClassForProgID(str(disp_clsid))
|
||||
except pythoncom.com_error:
|
||||
raise TypeError("This COM object can not automate the makepy process - please run makepy manually for this object")
|
||||
else:
|
||||
disp_class = disp.__class__
|
||||
# If the clsid was an object, get the clsid
|
||||
clsid = disp_class.CLSID
|
||||
# Create a new class that derives from 3 classes - the dispatch class, the event sink class and the user class.
|
||||
# XXX - we are still "classic style" classes in py2x, so we need can't yet
|
||||
# use 'type()' everywhere - revisit soon, as py2x will move to new-style too...
|
||||
try:
|
||||
from types import ClassType as new_type
|
||||
except ImportError:
|
||||
new_type = type # py3k
|
||||
events_class = getevents(clsid)
|
||||
if events_class is None:
|
||||
raise ValueError("This COM object does not support events.")
|
||||
result_class = new_type("COMEventClass", (disp_class, events_class, user_event_class), {"__setattr__" : _event_setattr_})
|
||||
instance = result_class(disp._oleobj_) # This only calls the first base class __init__.
|
||||
events_class.__init__(instance, instance)
|
||||
if hasattr(user_event_class, "__init__"):
|
||||
user_event_class.__init__(instance)
|
||||
return EventsProxy(instance)
|
||||
|
||||
def WithEvents(disp, user_event_class):
|
||||
"""Similar to DispatchWithEvents - except that the returned
|
||||
object is *not* also usable as the original Dispatch object - that is
|
||||
the returned object is not dispatchable.
|
||||
|
||||
The difference is best summarised by example.
|
||||
|
||||
>>> class IEEvents:
|
||||
... def OnVisible(self, visible):
|
||||
... print "Visible changed:", visible
|
||||
...
|
||||
>>> ie = Dispatch("InternetExplorer.Application")
|
||||
>>> ie_events = WithEvents(ie, IEEvents)
|
||||
>>> ie.Visible = 1
|
||||
Visible changed: 1
|
||||
|
||||
Compare with the code sample for DispatchWithEvents, where you get a
|
||||
single object that is both the interface and the event handler. Note that
|
||||
the event handler instance will *not* be able to use 'self.' to refer to
|
||||
IE's methods and properties.
|
||||
|
||||
This is mainly useful where using DispatchWithEvents causes
|
||||
circular reference problems that the simple proxy doesn't deal with
|
||||
"""
|
||||
disp = Dispatch(disp)
|
||||
if not disp.__class__.__dict__.get("CLSID"): # Eeek - no makepy support - try and build it.
|
||||
try:
|
||||
ti = disp._oleobj_.GetTypeInfo()
|
||||
disp_clsid = ti.GetTypeAttr()[0]
|
||||
tlb, index = ti.GetContainingTypeLib()
|
||||
tla = tlb.GetLibAttr()
|
||||
gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4], bValidateFile=0)
|
||||
# Get the class from the module.
|
||||
disp_class = gencache.GetClassForProgID(str(disp_clsid))
|
||||
except pythoncom.com_error:
|
||||
raise TypeError("This COM object can not automate the makepy process - please run makepy manually for this object")
|
||||
else:
|
||||
disp_class = disp.__class__
|
||||
# Get the clsid
|
||||
clsid = disp_class.CLSID
|
||||
# Create a new class that derives from 2 classes - the event sink
|
||||
# class and the user class.
|
||||
try:
|
||||
from types import ClassType as new_type
|
||||
except ImportError:
|
||||
new_type = type # py3k
|
||||
events_class = getevents(clsid)
|
||||
if events_class is None:
|
||||
raise ValueError("This COM object does not support events.")
|
||||
result_class = new_type("COMEventClass", (events_class, user_event_class), {})
|
||||
instance = result_class(disp) # This only calls the first base class __init__.
|
||||
if hasattr(user_event_class, "__init__"):
|
||||
user_event_class.__init__(instance)
|
||||
return instance
|
||||
|
||||
def getevents(clsid):
|
||||
"""Determine the default outgoing interface for a class, given
|
||||
either a clsid or progid. It returns a class - you can
|
||||
conveniently derive your own handler from this class and implement
|
||||
the appropriate methods.
|
||||
|
||||
This method relies on the classes produced by makepy. You must use
|
||||
either makepy or the gencache module to ensure that the
|
||||
appropriate support classes have been generated for the com server
|
||||
that you will be handling events from.
|
||||
|
||||
Beware of COM circular references. When the Events class is connected
|
||||
to the COM object, the COM object itself keeps a reference to the Python
|
||||
events class. Thus, neither the Events instance or the COM object will
|
||||
ever die by themselves. The 'close' method on the events instance
|
||||
must be called to break this chain and allow standard Python collection
|
||||
rules to manage object lifetimes. Note that DispatchWithEvents() does
|
||||
work around this problem by the use of a proxy object, but if you use
|
||||
the getevents() function yourself, you must make your own arrangements
|
||||
to manage this circular reference issue.
|
||||
|
||||
Beware of creating Python circular references: this will happen if your
|
||||
handler has a reference to an object that has a reference back to
|
||||
the event source. Call the 'close' method to break the chain.
|
||||
|
||||
Example:
|
||||
|
||||
>>>win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}',0,1,1)
|
||||
<module 'win32com.gen_py.....
|
||||
>>>
|
||||
>>> class InternetExplorerEvents(win32com.client.getevents("InternetExplorer.Application.1")):
|
||||
... def OnVisible(self, Visible):
|
||||
... print "Visibility changed: ", Visible
|
||||
...
|
||||
>>>
|
||||
>>> ie=win32com.client.Dispatch("InternetExplorer.Application.1")
|
||||
>>> events=InternetExplorerEvents(ie)
|
||||
>>> ie.Visible=1
|
||||
Visibility changed: 1
|
||||
>>>
|
||||
"""
|
||||
|
||||
# find clsid given progid or clsid
|
||||
clsid=str(pywintypes.IID(clsid))
|
||||
# return default outgoing interface for that class
|
||||
klass = gencache.GetClassForCLSID(clsid)
|
||||
try:
|
||||
return klass.default_source
|
||||
except AttributeError:
|
||||
# See if we have a coclass for the interfaces.
|
||||
try:
|
||||
return gencache.GetClassForCLSID(klass.coclass_clsid).default_source
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
# A Record object, as used by the COM struct support
|
||||
def Record(name, object):
|
||||
"""Creates a new record object, given the name of the record,
|
||||
and an object from the same type library.
|
||||
|
||||
Example usage would be:
|
||||
app = win32com.client.Dispatch("Some.Application")
|
||||
point = win32com.client.Record("SomeAppPoint", app)
|
||||
point.x = 0
|
||||
point.y = 0
|
||||
app.MoveTo(point)
|
||||
"""
|
||||
# XXX - to do - probably should allow "object" to already be a module object.
|
||||
from . import gencache
|
||||
object = gencache.EnsureDispatch(object)
|
||||
module = sys.modules[object.__class__.__module__]
|
||||
# to allow us to work correctly with "demand generated" code,
|
||||
# we must use the typelib CLSID to obtain the module
|
||||
# (otherwise we get the sub-module for the object, which
|
||||
# does not hold the records)
|
||||
# thus, package may be module, or may be module's parent if demand generated.
|
||||
package = gencache.GetModuleForTypelib(module.CLSID, module.LCID, module.MajorVersion, module.MinorVersion)
|
||||
try:
|
||||
struct_guid = package.RecordMap[name]
|
||||
except KeyError:
|
||||
raise ValueError("The structure '%s' is not defined in module '%s'" % (name, package))
|
||||
return pythoncom.GetRecordFromGuids(module.CLSID, module.MajorVersion, module.MinorVersion, module.LCID, struct_guid)
|
||||
|
||||
|
||||
############################################
|
||||
# The base of all makepy generated classes
|
||||
############################################
|
||||
class DispatchBaseClass:
|
||||
def __init__(self, oobj=None):
|
||||
if oobj is None:
|
||||
oobj = pythoncom.new(self.CLSID)
|
||||
elif isinstance(oobj, DispatchBaseClass):
|
||||
try:
|
||||
oobj = oobj._oleobj_.QueryInterface(self.CLSID, pythoncom.IID_IDispatch) # Must be a valid COM instance
|
||||
except pythoncom.com_error as details:
|
||||
import winerror
|
||||
# Some stupid objects fail here, even tho it is _already_ IDispatch!!??
|
||||
# Eg, Lotus notes.
|
||||
# So just let it use the existing object if E_NOINTERFACE
|
||||
if details.hresult != winerror.E_NOINTERFACE:
|
||||
raise
|
||||
oobj = oobj._oleobj_
|
||||
self.__dict__["_oleobj_"] = oobj # so we dont call __setattr__
|
||||
# Provide a prettier name than the CLSID
|
||||
def __repr__(self):
|
||||
# Need to get the docstring for the module for this class.
|
||||
try:
|
||||
mod_doc = sys.modules[self.__class__.__module__].__doc__
|
||||
if mod_doc:
|
||||
mod_name = "win32com.gen_py." + mod_doc
|
||||
else:
|
||||
mod_name = sys.modules[self.__class__.__module__].__name__
|
||||
except KeyError:
|
||||
mod_name = "win32com.gen_py.unknown"
|
||||
return "<%s.%s instance at 0x%s>" % (mod_name, self.__class__.__name__, id(self))
|
||||
# Delegate comparison to the oleobjs, as they know how to do identity.
|
||||
def __eq__(self, other):
|
||||
other = getattr(other, "_oleobj_", other)
|
||||
return self._oleobj_ == other
|
||||
|
||||
def __ne__(self, other):
|
||||
other = getattr(other, "_oleobj_", other)
|
||||
return self._oleobj_ != other
|
||||
|
||||
def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user, resultCLSID, *args):
|
||||
return self._get_good_object_(
|
||||
self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args),
|
||||
user, resultCLSID)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
args=self._prop_map_get_.get(attr)
|
||||
if args is None:
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % (repr(self), attr))
|
||||
return self._ApplyTypes_(*args)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in self.__dict__: self.__dict__[attr] = value; return
|
||||
try:
|
||||
args, defArgs=self._prop_map_put_[attr]
|
||||
except KeyError:
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % (repr(self), attr))
|
||||
self._oleobj_.Invoke(*(args + (value,) + defArgs))
|
||||
def _get_good_single_object_(self, obj, obUserName=None, resultCLSID=None):
|
||||
return _get_good_single_object_(obj, obUserName, resultCLSID)
|
||||
def _get_good_object_(self, obj, obUserName=None, resultCLSID=None):
|
||||
return _get_good_object_(obj, obUserName, resultCLSID)
|
||||
|
||||
# XXX - These should be consolidated with dynamic.py versions.
|
||||
def _get_good_single_object_(obj, obUserName=None, resultCLSID=None):
|
||||
if _PyIDispatchType==type(obj):
|
||||
return Dispatch(obj, obUserName, resultCLSID)
|
||||
return obj
|
||||
|
||||
def _get_good_object_(obj, obUserName=None, resultCLSID=None):
|
||||
if obj is None:
|
||||
return None
|
||||
elif isinstance(obj, tuple):
|
||||
obUserNameTuple = (obUserName,) * len(obj)
|
||||
resultCLSIDTuple = (resultCLSID,) * len(obj)
|
||||
return tuple(map(_get_good_object_, obj, obUserNameTuple, resultCLSIDTuple))
|
||||
else:
|
||||
return _get_good_single_object_(obj, obUserName, resultCLSID)
|
||||
|
||||
class CoClassBaseClass:
|
||||
def __init__(self, oobj=None):
|
||||
if oobj is None: oobj = pythoncom.new(self.CLSID)
|
||||
self.__dict__["_dispobj_"] = self.default_interface(oobj)
|
||||
def __repr__(self):
|
||||
return "<win32com.gen_py.%s.%s>" % (__doc__, self.__class__.__name__)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
d=self.__dict__["_dispobj_"]
|
||||
if d is not None: return getattr(d, attr)
|
||||
raise AttributeError(attr)
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in self.__dict__: self.__dict__[attr] = value; return
|
||||
try:
|
||||
d=self.__dict__["_dispobj_"]
|
||||
if d is not None:
|
||||
d.__setattr__(attr, value)
|
||||
return
|
||||
except AttributeError:
|
||||
pass
|
||||
self.__dict__[attr] = value
|
||||
|
||||
# A very simple VARIANT class. Only to be used with poorly-implemented COM
|
||||
# objects. If an object accepts an arg which is a simple "VARIANT", but still
|
||||
# is very pickly about the actual variant type (eg, isn't happy with a VT_I4,
|
||||
# which it would get from a Python integer), you can use this to force a
|
||||
# particular VT.
|
||||
class VARIANT(object):
|
||||
def __init__(self, vt, value):
|
||||
self.varianttype = vt
|
||||
self._value = value
|
||||
|
||||
# 'value' is a property so when set by pythoncom it gets any magic wrapping
|
||||
# which normally happens for result objects
|
||||
def _get_value(self):
|
||||
return self._value
|
||||
def _set_value(self, newval):
|
||||
self._value = _get_good_object_(newval)
|
||||
def _del_value(self):
|
||||
del self._value
|
||||
value = property(_get_value, _set_value, _del_value)
|
||||
|
||||
def __repr__(self):
|
||||
return "win32com.client.VARIANT(%r, %r)" % (self.varianttype, self._value)
|
630
venv/Lib/site-packages/win32com/client/build.py
Normal file
|
@ -0,0 +1,630 @@
|
|||
"""Contains knowledge to build a COM object definition.
|
||||
|
||||
This module is used by both the @dynamic@ and @makepy@ modules to build
|
||||
all knowledge of a COM object.
|
||||
|
||||
This module contains classes which contain the actual knowledge of the object.
|
||||
This include parameter and return type information, the COM dispid and CLSID, etc.
|
||||
|
||||
Other modules may use this information to generate .py files, use the information
|
||||
dynamically, or possibly even generate .html documentation for objects.
|
||||
"""
|
||||
|
||||
#
|
||||
# NOTES: DispatchItem and MapEntry used by dynamic.py.
|
||||
# the rest is used by makepy.py
|
||||
#
|
||||
# OleItem, DispatchItem, MapEntry, BuildCallList() is used by makepy
|
||||
|
||||
import sys
|
||||
import string
|
||||
from keyword import iskeyword
|
||||
|
||||
import pythoncom
|
||||
from pywintypes import TimeType
|
||||
import winerror
|
||||
import datetime
|
||||
|
||||
# It isn't really clear what the quoting rules are in a C/IDL string and
|
||||
# literals like a quote char and backslashes makes life a little painful to
|
||||
# always render the string perfectly - so just punt and fall-back to a repr()
|
||||
def _makeDocString(s):
|
||||
if sys.version_info < (3,):
|
||||
s = s.encode("mbcs")
|
||||
return repr(s)
|
||||
|
||||
error = "PythonCOM.Client.Build error"
|
||||
class NotSupportedException(Exception): pass # Raised when we cant support a param type.
|
||||
DropIndirection="DropIndirection"
|
||||
|
||||
NoTranslateTypes = [
|
||||
pythoncom.VT_BOOL, pythoncom.VT_CLSID, pythoncom.VT_CY,
|
||||
pythoncom.VT_DATE, pythoncom.VT_DECIMAL, pythoncom.VT_EMPTY,
|
||||
pythoncom.VT_ERROR, pythoncom.VT_FILETIME, pythoncom.VT_HRESULT,
|
||||
pythoncom.VT_I1, pythoncom.VT_I2, pythoncom.VT_I4,
|
||||
pythoncom.VT_I8, pythoncom.VT_INT, pythoncom.VT_NULL,
|
||||
pythoncom.VT_R4, pythoncom.VT_R8, pythoncom.VT_NULL,
|
||||
pythoncom.VT_STREAM,
|
||||
pythoncom.VT_UI1, pythoncom.VT_UI2, pythoncom.VT_UI4,
|
||||
pythoncom.VT_UI8, pythoncom.VT_UINT, pythoncom.VT_VOID,
|
||||
]
|
||||
|
||||
NoTranslateMap = {}
|
||||
for v in NoTranslateTypes:
|
||||
NoTranslateMap[v] = None
|
||||
|
||||
class MapEntry:
|
||||
"Simple holder for named attibutes - items in a map."
|
||||
def __init__(self, desc_or_id, names=None, doc=None, resultCLSID=pythoncom.IID_NULL, resultDoc = None, hidden=0):
|
||||
if type(desc_or_id)==type(0):
|
||||
self.dispid = desc_or_id
|
||||
self.desc = None
|
||||
else:
|
||||
self.dispid = desc_or_id[0]
|
||||
self.desc = desc_or_id
|
||||
|
||||
self.names = names
|
||||
self.doc = doc
|
||||
self.resultCLSID = resultCLSID
|
||||
self.resultDocumentation = resultDoc
|
||||
self.wasProperty = 0 # Have I been transformed into a function so I can pass args?
|
||||
self.hidden = hidden
|
||||
def GetResultCLSID(self):
|
||||
rc = self.resultCLSID
|
||||
if rc == pythoncom.IID_NULL: return None
|
||||
return rc
|
||||
# Return a string, suitable for output - either "'{...}'" or "None"
|
||||
def GetResultCLSIDStr(self):
|
||||
rc = self.GetResultCLSID()
|
||||
if rc is None: return "None"
|
||||
return repr(str(rc)) # Convert the IID object to a string, then to a string in a string.
|
||||
|
||||
def GetResultName(self):
|
||||
if self.resultDocumentation is None:
|
||||
return None
|
||||
return self.resultDocumentation[0]
|
||||
|
||||
class OleItem:
|
||||
typename = "OleItem"
|
||||
|
||||
def __init__(self, doc=None):
|
||||
self.doc = doc
|
||||
if self.doc:
|
||||
self.python_name = MakePublicAttributeName(self.doc[0])
|
||||
else:
|
||||
self.python_name = None
|
||||
self.bWritten = 0
|
||||
self.bIsDispatch = 0
|
||||
self.bIsSink = 0
|
||||
self.clsid = None
|
||||
self.co_class = None
|
||||
|
||||
class DispatchItem(OleItem):
|
||||
typename = "DispatchItem"
|
||||
|
||||
def __init__(self, typeinfo=None, attr=None, doc=None, bForUser=1):
|
||||
OleItem.__init__(self,doc)
|
||||
self.propMap = {}
|
||||
self.propMapGet = {}
|
||||
self.propMapPut = {}
|
||||
self.mapFuncs = {}
|
||||
self.defaultDispatchName = None
|
||||
self.hidden = 0
|
||||
|
||||
if typeinfo:
|
||||
self.Build(typeinfo, attr, bForUser)
|
||||
|
||||
def _propMapPutCheck_(self,key,item):
|
||||
ins, outs, opts = self.CountInOutOptArgs(item.desc[2])
|
||||
if ins>1: # if a Put property takes more than 1 arg:
|
||||
if opts+1==ins or ins==item.desc[6]+1:
|
||||
newKey = "Set" + key
|
||||
deleteExisting = 0 # This one is still OK
|
||||
else:
|
||||
deleteExisting = 1 # No good to us
|
||||
if key in self.mapFuncs or key in self.propMapGet:
|
||||
newKey = "Set" + key
|
||||
else:
|
||||
newKey = key
|
||||
item.wasProperty = 1
|
||||
self.mapFuncs[newKey] = item
|
||||
if deleteExisting:
|
||||
del self.propMapPut[key]
|
||||
|
||||
def _propMapGetCheck_(self,key,item):
|
||||
ins, outs, opts = self.CountInOutOptArgs(item.desc[2])
|
||||
if ins > 0: # if a Get property takes _any_ in args:
|
||||
if item.desc[6]==ins or ins==opts:
|
||||
newKey = "Get" + key
|
||||
deleteExisting = 0 # This one is still OK
|
||||
else:
|
||||
deleteExisting = 1 # No good to us
|
||||
if key in self.mapFuncs:
|
||||
newKey = "Get" + key
|
||||
else:
|
||||
newKey = key
|
||||
item.wasProperty = 1
|
||||
self.mapFuncs[newKey] = item
|
||||
if deleteExisting:
|
||||
del self.propMapGet[key]
|
||||
|
||||
def _AddFunc_(self,typeinfo,fdesc,bForUser):
|
||||
id = fdesc.memid
|
||||
funcflags = fdesc.wFuncFlags
|
||||
try:
|
||||
names = typeinfo.GetNames(id)
|
||||
name=names[0]
|
||||
except pythoncom.ole_error:
|
||||
name = ""
|
||||
names = None
|
||||
|
||||
doc = None
|
||||
try:
|
||||
if bForUser:
|
||||
doc = typeinfo.GetDocumentation(id)
|
||||
except pythoncom.ole_error:
|
||||
pass
|
||||
|
||||
if id==0 and name:
|
||||
self.defaultDispatchName = name
|
||||
|
||||
invkind = fdesc.invkind
|
||||
|
||||
# We need to translate any Alias', Enums, structs etc in result and args
|
||||
typerepr, flag, defval = fdesc.rettype
|
||||
# sys.stderr.write("%s result - %s -> " % (name, typerepr))
|
||||
typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
|
||||
# sys.stderr.write("%s\n" % (typerepr,))
|
||||
fdesc.rettype = typerepr, flag, defval, resultCLSID
|
||||
# Translate any Alias or Enums in argument list.
|
||||
argList = []
|
||||
for argDesc in fdesc.args:
|
||||
typerepr, flag, defval = argDesc
|
||||
# sys.stderr.write("%s arg - %s -> " % (name, typerepr))
|
||||
arg_type, arg_clsid, arg_doc = _ResolveType(typerepr, typeinfo)
|
||||
argDesc = arg_type, flag, defval, arg_clsid
|
||||
# sys.stderr.write("%s\n" % (argDesc[0],))
|
||||
argList.append(argDesc)
|
||||
fdesc.args = tuple(argList)
|
||||
|
||||
hidden = (funcflags & pythoncom.FUNCFLAG_FHIDDEN) != 0
|
||||
if invkind == pythoncom.INVOKE_PROPERTYGET:
|
||||
map = self.propMapGet
|
||||
# This is not the best solution, but I dont think there is
|
||||
# one without specific "set" syntax.
|
||||
# If there is a single PUT or PUTREF, it will function as a property.
|
||||
# If there are both, then the PUT remains a property, and the PUTREF
|
||||
# gets transformed into a function.
|
||||
# (in vb, PUT=="obj=other_obj", PUTREF="set obj=other_obj
|
||||
elif invkind in (pythoncom.INVOKE_PROPERTYPUT, pythoncom.INVOKE_PROPERTYPUTREF):
|
||||
# Special case
|
||||
existing = self.propMapPut.get(name, None)
|
||||
if existing is not None:
|
||||
if existing.desc[4]==pythoncom.INVOKE_PROPERTYPUT: # Keep this one
|
||||
map = self.mapFuncs
|
||||
name = "Set"+name
|
||||
else: # Existing becomes a func.
|
||||
existing.wasProperty = 1
|
||||
self.mapFuncs["Set"+name]=existing
|
||||
map = self.propMapPut # existing gets overwritten below.
|
||||
else:
|
||||
map = self.propMapPut # first time weve seen it.
|
||||
|
||||
elif invkind == pythoncom.INVOKE_FUNC:
|
||||
map = self.mapFuncs
|
||||
else:
|
||||
map = None
|
||||
if not map is None:
|
||||
# if map.has_key(name):
|
||||
# sys.stderr.write("Warning - overwriting existing method/attribute %s\n" % name)
|
||||
map[name] = MapEntry(tuple(fdesc), names, doc, resultCLSID, resultDoc, hidden)
|
||||
# any methods that can't be reached via DISPATCH we return None
|
||||
# for, so dynamic dispatch doesnt see it.
|
||||
if fdesc.funckind != pythoncom.FUNC_DISPATCH:
|
||||
return None
|
||||
return (name,map)
|
||||
return None
|
||||
|
||||
def _AddVar_(self,typeinfo,fdesc,bForUser):
|
||||
### need pythoncom.VARFLAG_FRESTRICTED ...
|
||||
### then check it
|
||||
|
||||
if fdesc.varkind == pythoncom.VAR_DISPATCH:
|
||||
id = fdesc.memid
|
||||
names = typeinfo.GetNames(id)
|
||||
# Translate any Alias or Enums in result.
|
||||
typerepr, flags, defval = fdesc.elemdescVar
|
||||
typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
|
||||
fdesc.elemdescVar = typerepr, flags, defval
|
||||
doc = None
|
||||
try:
|
||||
if bForUser: doc = typeinfo.GetDocumentation(id)
|
||||
except pythoncom.ole_error:
|
||||
pass
|
||||
|
||||
# handle the enumerator specially
|
||||
map = self.propMap
|
||||
# Check if the element is hidden.
|
||||
hidden = 0
|
||||
if hasattr(fdesc,"wVarFlags"):
|
||||
hidden = (fdesc.wVarFlags & 0x40) != 0 # VARFLAG_FHIDDEN
|
||||
map[names[0]] = MapEntry(tuple(fdesc), names, doc, resultCLSID, resultDoc, hidden)
|
||||
return (names[0],map)
|
||||
else:
|
||||
return None
|
||||
|
||||
def Build(self, typeinfo, attr, bForUser = 1):
|
||||
self.clsid = attr[0]
|
||||
self.bIsDispatch = (attr.wTypeFlags & pythoncom.TYPEFLAG_FDISPATCHABLE) != 0
|
||||
if typeinfo is None: return
|
||||
# Loop over all methods
|
||||
for j in range(attr[6]):
|
||||
fdesc = typeinfo.GetFuncDesc(j)
|
||||
self._AddFunc_(typeinfo,fdesc,bForUser)
|
||||
|
||||
# Loop over all variables (ie, properties)
|
||||
for j in range(attr[7]):
|
||||
fdesc = typeinfo.GetVarDesc(j)
|
||||
self._AddVar_(typeinfo,fdesc,bForUser)
|
||||
|
||||
# Now post-process the maps. For any "Get" or "Set" properties
|
||||
# that have arguments, we must turn them into methods. If a method
|
||||
# of the same name already exists, change the name.
|
||||
for key, item in list(self.propMapGet.items()):
|
||||
self._propMapGetCheck_(key,item)
|
||||
|
||||
for key, item in list(self.propMapPut.items()):
|
||||
self._propMapPutCheck_(key,item)
|
||||
|
||||
def CountInOutOptArgs(self, argTuple):
|
||||
"Return tuple counting in/outs/OPTS. Sum of result may not be len(argTuple), as some args may be in/out."
|
||||
ins = out = opts = 0
|
||||
for argCheck in argTuple:
|
||||
inOut = argCheck[1]
|
||||
if inOut==0:
|
||||
ins = ins + 1
|
||||
out = out + 1
|
||||
else:
|
||||
if inOut & pythoncom.PARAMFLAG_FIN:
|
||||
ins = ins + 1
|
||||
if inOut & pythoncom.PARAMFLAG_FOPT:
|
||||
opts = opts + 1
|
||||
if inOut & pythoncom.PARAMFLAG_FOUT:
|
||||
out = out + 1
|
||||
return ins, out, opts
|
||||
|
||||
def MakeFuncMethod(self, entry, name, bMakeClass = 1):
|
||||
# If we have a type description, and not varargs...
|
||||
if entry.desc is not None and (len(entry.desc) < 6 or entry.desc[6]!=-1):
|
||||
return self.MakeDispatchFuncMethod(entry, name, bMakeClass)
|
||||
else:
|
||||
return self.MakeVarArgsFuncMethod(entry, name, bMakeClass)
|
||||
|
||||
def MakeDispatchFuncMethod(self, entry, name, bMakeClass = 1):
|
||||
fdesc = entry.desc
|
||||
doc = entry.doc
|
||||
names = entry.names
|
||||
ret = []
|
||||
if bMakeClass:
|
||||
linePrefix = "\t"
|
||||
defNamedOptArg = "defaultNamedOptArg"
|
||||
defNamedNotOptArg = "defaultNamedNotOptArg"
|
||||
defUnnamedArg = "defaultUnnamedArg"
|
||||
else:
|
||||
linePrefix = ""
|
||||
defNamedOptArg = "pythoncom.Missing"
|
||||
defNamedNotOptArg = "pythoncom.Missing"
|
||||
defUnnamedArg = "pythoncom.Missing"
|
||||
defOutArg = "pythoncom.Missing"
|
||||
id = fdesc[0]
|
||||
|
||||
s = linePrefix + 'def ' + name + '(self' + BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg) + '):'
|
||||
ret.append(s)
|
||||
if doc and doc[1]:
|
||||
ret.append(linePrefix + '\t' + _makeDocString(doc[1]))
|
||||
|
||||
# print "fdesc is ", fdesc
|
||||
|
||||
resclsid = entry.GetResultCLSID()
|
||||
if resclsid:
|
||||
resclsid = "'%s'" % resclsid
|
||||
else:
|
||||
resclsid = 'None'
|
||||
# Strip the default values from the arg desc
|
||||
retDesc = fdesc[8][:2]
|
||||
argsDesc = tuple([what[:2] for what in fdesc[2]])
|
||||
# The runtime translation of the return types is expensive, so when we know the
|
||||
# return type of the function, there is no need to check the type at runtime.
|
||||
# To qualify, this function must return a "simple" type, and have no byref args.
|
||||
# Check if we have byrefs or anything in the args which mean we still need a translate.
|
||||
param_flags = [what[1] for what in fdesc[2]]
|
||||
bad_params = [flag for flag in param_flags if flag & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FRETVAL)!=0]
|
||||
s = None
|
||||
if len(bad_params)==0 and len(retDesc)==2 and retDesc[1]==0:
|
||||
rd = retDesc[0]
|
||||
if rd in NoTranslateMap:
|
||||
s = '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, argsDesc, _BuildArgList(fdesc, names))
|
||||
elif rd in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN]:
|
||||
s = '%s\tret = self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)\n' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc), _BuildArgList(fdesc, names))
|
||||
s = s + '%s\tif ret is not None:\n' % (linePrefix,)
|
||||
if rd == pythoncom.VT_UNKNOWN:
|
||||
s = s + "%s\t\t# See if this IUnknown is really an IDispatch\n" % (linePrefix,)
|
||||
s = s + "%s\t\ttry:\n" % (linePrefix,)
|
||||
s = s + "%s\t\t\tret = ret.QueryInterface(pythoncom.IID_IDispatch)\n" % (linePrefix,)
|
||||
s = s + "%s\t\texcept pythoncom.error:\n" % (linePrefix,)
|
||||
s = s + "%s\t\t\treturn ret\n" % (linePrefix,)
|
||||
s = s + '%s\t\tret = Dispatch(ret, %s, %s)\n' % (linePrefix,repr(name), resclsid)
|
||||
s = s + '%s\treturn ret' % (linePrefix)
|
||||
elif rd == pythoncom.VT_BSTR:
|
||||
s = "%s\t# Result is a Unicode object\n" % (linePrefix,)
|
||||
s = s + '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc), _BuildArgList(fdesc, names))
|
||||
# else s remains None
|
||||
if s is None:
|
||||
s = '%s\treturn self._ApplyTypes_(%d, %s, %s, %s, %s, %s%s)' % (linePrefix, id, fdesc[4], retDesc, argsDesc, repr(name), resclsid, _BuildArgList(fdesc, names))
|
||||
|
||||
ret.append(s)
|
||||
ret.append("")
|
||||
return ret
|
||||
|
||||
def MakeVarArgsFuncMethod(self, entry, name, bMakeClass = 1):
|
||||
fdesc = entry.desc
|
||||
names = entry.names
|
||||
doc = entry.doc
|
||||
ret = []
|
||||
argPrefix = "self"
|
||||
if bMakeClass:
|
||||
linePrefix = "\t"
|
||||
else:
|
||||
linePrefix = ""
|
||||
ret.append(linePrefix + 'def ' + name + '(' + argPrefix + ', *args):')
|
||||
if doc and doc[1]: ret.append(linePrefix + '\t' + _makeDocString(doc[1]))
|
||||
if fdesc:
|
||||
invoketype = fdesc[4]
|
||||
else:
|
||||
invoketype = pythoncom.DISPATCH_METHOD
|
||||
s = linePrefix + '\treturn self._get_good_object_(self._oleobj_.Invoke(*(('
|
||||
ret.append(s + str(entry.dispid) + ",0,%d,1)+args)),'%s')" % (invoketype, names[0]))
|
||||
ret.append("")
|
||||
return ret
|
||||
|
||||
# Note - "DispatchItem" poorly named - need a new intermediate class.
|
||||
class VTableItem(DispatchItem):
|
||||
def Build(self, typeinfo, attr, bForUser = 1):
|
||||
DispatchItem.Build(self, typeinfo, attr, bForUser)
|
||||
assert typeinfo is not None, "Cant build vtables without type info!"
|
||||
|
||||
meth_list = list(self.mapFuncs.values()) + list(self.propMapGet.values()) + list(self.propMapPut.values())
|
||||
meth_list.sort(key=lambda m: m.desc[7])
|
||||
|
||||
# Now turn this list into the run-time representation
|
||||
# (ready for immediate use or writing to gencache)
|
||||
self.vtableFuncs = []
|
||||
for entry in meth_list:
|
||||
self.vtableFuncs.append( (entry.names, entry.dispid, entry.desc) )
|
||||
|
||||
# A Lazy dispatch item - builds an item on request using info from
|
||||
# an ITypeComp. The dynamic module makes the called to build each item,
|
||||
# and also holds the references to the typeinfo and typecomp.
|
||||
class LazyDispatchItem(DispatchItem):
|
||||
typename = "LazyDispatchItem"
|
||||
def __init__(self, attr, doc):
|
||||
self.clsid = attr[0]
|
||||
DispatchItem.__init__(self, None, attr, doc, 0)
|
||||
|
||||
typeSubstMap = {
|
||||
pythoncom.VT_INT: pythoncom.VT_I4,
|
||||
pythoncom.VT_UINT: pythoncom.VT_UI4,
|
||||
pythoncom.VT_HRESULT: pythoncom.VT_I4,
|
||||
}
|
||||
|
||||
def _ResolveType(typerepr, itypeinfo):
|
||||
# Resolve VT_USERDEFINED (often aliases or typed IDispatches)
|
||||
|
||||
if type(typerepr)==tuple:
|
||||
indir_vt, subrepr = typerepr
|
||||
if indir_vt == pythoncom.VT_PTR:
|
||||
# If it is a VT_PTR to a VT_USERDEFINED that is an IDispatch/IUnknown,
|
||||
# then it resolves to simply the object.
|
||||
# Otherwise, it becomes a ByRef of the resolved type
|
||||
# We need to drop an indirection level on pointer to user defined interfaces.
|
||||
# eg, (VT_PTR, (VT_USERDEFINED, somehandle)) needs to become VT_DISPATCH
|
||||
# only when "somehandle" is an object.
|
||||
# but (VT_PTR, (VT_USERDEFINED, otherhandle)) doesnt get the indirection dropped.
|
||||
was_user = type(subrepr)==tuple and subrepr[0]==pythoncom.VT_USERDEFINED
|
||||
subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)
|
||||
if was_user and subrepr in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN, pythoncom.VT_RECORD]:
|
||||
# Drop the VT_PTR indirection
|
||||
return subrepr, sub_clsid, sub_doc
|
||||
# Change PTR indirection to byref
|
||||
return subrepr | pythoncom.VT_BYREF, sub_clsid, sub_doc
|
||||
if indir_vt == pythoncom.VT_SAFEARRAY:
|
||||
# resolve the array element, and convert to VT_ARRAY
|
||||
subrepr, sub_clsid, sub_doc = _ResolveType(subrepr, itypeinfo)
|
||||
return pythoncom.VT_ARRAY | subrepr, sub_clsid, sub_doc
|
||||
if indir_vt == pythoncom.VT_CARRAY: # runtime has no support for this yet.
|
||||
# resolve the array element, and convert to VT_CARRAY
|
||||
# sheesh - return _something_
|
||||
return pythoncom.VT_CARRAY, None, None
|
||||
if indir_vt == pythoncom.VT_USERDEFINED:
|
||||
try:
|
||||
resultTypeInfo = itypeinfo.GetRefTypeInfo(subrepr)
|
||||
except pythoncom.com_error as details:
|
||||
if details.hresult in [winerror.TYPE_E_CANTLOADLIBRARY, winerror.TYPE_E_LIBNOTREGISTERED]:
|
||||
# an unregistered interface
|
||||
return pythoncom.VT_UNKNOWN, None, None
|
||||
raise
|
||||
|
||||
resultAttr = resultTypeInfo.GetTypeAttr()
|
||||
typeKind = resultAttr.typekind
|
||||
if typeKind == pythoncom.TKIND_ALIAS:
|
||||
tdesc = resultAttr.tdescAlias
|
||||
return _ResolveType(tdesc, resultTypeInfo)
|
||||
elif typeKind in [pythoncom.TKIND_ENUM, pythoncom.TKIND_MODULE]:
|
||||
# For now, assume Long
|
||||
return pythoncom.VT_I4, None, None
|
||||
|
||||
elif typeKind == pythoncom.TKIND_DISPATCH:
|
||||
clsid = resultTypeInfo.GetTypeAttr()[0]
|
||||
retdoc = resultTypeInfo.GetDocumentation(-1)
|
||||
return pythoncom.VT_DISPATCH, clsid, retdoc
|
||||
|
||||
elif typeKind in [pythoncom.TKIND_INTERFACE,
|
||||
pythoncom.TKIND_COCLASS]:
|
||||
# XXX - should probably get default interface for CO_CLASS???
|
||||
clsid = resultTypeInfo.GetTypeAttr()[0]
|
||||
retdoc = resultTypeInfo.GetDocumentation(-1)
|
||||
return pythoncom.VT_UNKNOWN, clsid, retdoc
|
||||
|
||||
elif typeKind == pythoncom.TKIND_RECORD:
|
||||
return pythoncom.VT_RECORD, None, None
|
||||
raise NotSupportedException("Can not resolve alias or user-defined type")
|
||||
return typeSubstMap.get(typerepr,typerepr), None, None
|
||||
|
||||
def _BuildArgList(fdesc, names):
|
||||
"Builds list of args to the underlying Invoke method."
|
||||
# Word has TypeInfo for Insert() method, but says "no args"
|
||||
numArgs = max(fdesc[6], len(fdesc[2]))
|
||||
names = list(names)
|
||||
while None in names:
|
||||
i = names.index(None)
|
||||
names[i] = "arg%d" % (i,)
|
||||
# We've seen 'source safe' libraries offer the name of 'ret' params in
|
||||
# 'names' - although we can't reproduce this, it would be insane to offer
|
||||
# more args than we have arg infos for - hence the upper limit on names...
|
||||
names = list(map(MakePublicAttributeName, names[1:(numArgs + 1)]))
|
||||
name_num = 0
|
||||
while len(names) < numArgs:
|
||||
names.append("arg%d" % (len(names),))
|
||||
# As per BuildCallList(), avoid huge lines.
|
||||
# Hack a "\n" at the end of every 5th name - "strides" would be handy
|
||||
# here but don't exist in 2.2
|
||||
for i in range(0, len(names), 5):
|
||||
names[i] = names[i] + "\n\t\t\t"
|
||||
return "," + ", ".join(names)
|
||||
|
||||
valid_identifier_chars = string.ascii_letters + string.digits + "_"
|
||||
|
||||
def demunge_leading_underscores(className):
|
||||
i = 0
|
||||
while className[i] == "_":
|
||||
i += 1
|
||||
assert i >= 2, "Should only be here with names starting with '__'"
|
||||
return className[i-1:] + className[:i-1]
|
||||
|
||||
# Given a "public name" (eg, the name of a class, function, etc)
|
||||
# make sure it is a legal (and reasonable!) Python name.
|
||||
def MakePublicAttributeName(className, is_global = False):
|
||||
# Given a class attribute that needs to be public, convert it to a
|
||||
# reasonable name.
|
||||
# Also need to be careful that the munging doesnt
|
||||
# create duplicates - eg, just removing a leading "_" is likely to cause
|
||||
# a clash.
|
||||
# if is_global is True, then the name is a global variable that may
|
||||
# overwrite a builtin - eg, "None"
|
||||
if className[:2]=='__':
|
||||
return demunge_leading_underscores(className)
|
||||
elif className == 'None':
|
||||
# assign to None is evil (and SyntaxError in 2.4, even though
|
||||
# iskeyword says False there) - note that if it was a global
|
||||
# it would get picked up below
|
||||
className = 'NONE'
|
||||
elif iskeyword(className):
|
||||
# most keywords are lower case (except True, False etc in py3k)
|
||||
ret = className.capitalize()
|
||||
# but those which aren't get forced upper.
|
||||
if ret == className:
|
||||
ret = ret.upper()
|
||||
return ret
|
||||
elif is_global and hasattr(__builtins__, className):
|
||||
# builtins may be mixed case. If capitalizing it doesn't change it,
|
||||
# force to all uppercase (eg, "None", "True" become "NONE", "TRUE"
|
||||
ret = className.capitalize()
|
||||
if ret==className: # didn't change - force all uppercase.
|
||||
ret = ret.upper()
|
||||
return ret
|
||||
# Strip non printable chars
|
||||
return ''.join([char for char in className if char in valid_identifier_chars])
|
||||
|
||||
# Given a default value passed by a type library, return a string with
|
||||
# an appropriate repr() for the type.
|
||||
# Takes a raw ELEMDESC and returns a repr string, or None
|
||||
# (NOTE: The string itself may be '"None"', which is valid, and different to None.
|
||||
# XXX - To do: Dates are probably screwed, but can they come in?
|
||||
def MakeDefaultArgRepr(defArgVal):
|
||||
try:
|
||||
inOut = defArgVal[1]
|
||||
except IndexError:
|
||||
# something strange - assume is in param.
|
||||
inOut = pythoncom.PARAMFLAG_FIN
|
||||
|
||||
if inOut & pythoncom.PARAMFLAG_FHASDEFAULT:
|
||||
# times need special handling...
|
||||
val = defArgVal[2]
|
||||
if isinstance(val, datetime.datetime):
|
||||
# VARIANT <-> SYSTEMTIME conversions always lose any sub-second
|
||||
# resolution, so just use a 'timetuple' here.
|
||||
return repr(tuple(val.utctimetuple()))
|
||||
if type(val) is TimeType:
|
||||
# must be the 'old' pywintypes time object...
|
||||
year=val.year; month=val.month; day=val.day; hour=val.hour; minute=val.minute; second=val.second; msec=val.msec
|
||||
return "pywintypes.Time((%(year)d, %(month)d, %(day)d, %(hour)d, %(minute)d, %(second)d,0,0,0,%(msec)d))" % locals()
|
||||
return repr(val)
|
||||
return None
|
||||
|
||||
def BuildCallList(fdesc, names, defNamedOptArg, defNamedNotOptArg, defUnnamedArg, defOutArg, is_comment = False):
|
||||
"Builds a Python declaration for a method."
|
||||
# Names[0] is the func name - param names are from 1.
|
||||
numArgs = len(fdesc[2])
|
||||
numOptArgs = fdesc[6]
|
||||
strval = ''
|
||||
if numOptArgs==-1: # Special value that says "var args after here"
|
||||
firstOptArg = numArgs
|
||||
numArgs = numArgs - 1
|
||||
else:
|
||||
firstOptArg = numArgs - numOptArgs
|
||||
for arg in range(numArgs):
|
||||
try:
|
||||
argName = names[arg+1]
|
||||
namedArg = argName is not None
|
||||
except IndexError:
|
||||
namedArg = 0
|
||||
if not namedArg: argName = "arg%d" % (arg)
|
||||
thisdesc = fdesc[2][arg]
|
||||
# See if the IDL specified a default value
|
||||
defArgVal = MakeDefaultArgRepr(thisdesc)
|
||||
if defArgVal is None:
|
||||
# Out params always get their special default
|
||||
if thisdesc[1] & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FIN) == pythoncom.PARAMFLAG_FOUT:
|
||||
defArgVal = defOutArg
|
||||
else:
|
||||
# Unnamed arg - always allow default values.
|
||||
if namedArg:
|
||||
# Is a named argument
|
||||
if arg >= firstOptArg:
|
||||
defArgVal = defNamedOptArg
|
||||
else:
|
||||
defArgVal = defNamedNotOptArg
|
||||
else:
|
||||
defArgVal = defUnnamedArg
|
||||
|
||||
argName = MakePublicAttributeName(argName)
|
||||
# insanely long lines with an 'encoding' flag crashes python 2.4.0
|
||||
# keep 5 args per line
|
||||
# This may still fail if the arg names are insane, but that seems
|
||||
# unlikely. See also _BuildArgList()
|
||||
if (arg+1) % 5 == 0:
|
||||
strval = strval + "\n"
|
||||
if is_comment:
|
||||
strval = strval + "#"
|
||||
strval = strval + "\t\t\t"
|
||||
strval = strval + ", " + argName
|
||||
if defArgVal:
|
||||
strval = strval + "=" + defArgVal
|
||||
if numOptArgs==-1:
|
||||
strval = strval + ", *" + names[-1]
|
||||
|
||||
return strval
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
print("Use 'makepy.py' to generate Python code - this module is just a helper")
|
540
venv/Lib/site-packages/win32com/client/combrowse.py
Normal file
|
@ -0,0 +1,540 @@
|
|||
"""A utility for browsing COM objects.
|
||||
|
||||
Usage:
|
||||
|
||||
Command Prompt
|
||||
|
||||
Use the command *"python.exe catbrowse.py"*. This will display
|
||||
display a fairly small, modal dialog.
|
||||
|
||||
Pythonwin
|
||||
|
||||
Use the "Run Script" menu item, and this will create the browser in an
|
||||
MDI window. This window can be fully resized.
|
||||
|
||||
Details
|
||||
|
||||
This module allows browsing of registered Type Libraries, COM categories,
|
||||
and running COM objects. The display is similar to the Pythonwin object
|
||||
browser, and displays the objects in a hierarchical window.
|
||||
|
||||
Note that this module requires the win32ui (ie, Pythonwin) distribution to
|
||||
work.
|
||||
|
||||
"""
|
||||
import win32con
|
||||
import win32api, win32ui
|
||||
import sys
|
||||
import pythoncom
|
||||
from win32com.client import util
|
||||
from pywin.tools import browser
|
||||
|
||||
class HLIRoot(browser.HLIPythonObject):
|
||||
def __init__(self, title):
|
||||
self.name = title
|
||||
def GetSubList(self):
|
||||
return [HLIHeadingCategory(), HLI_IEnumMoniker(pythoncom.GetRunningObjectTable().EnumRunning(), "Running Objects"), HLIHeadingRegisterdTypeLibs()]
|
||||
def __cmp__(self, other):
|
||||
return cmp(self.name, other.name)
|
||||
|
||||
class HLICOM(browser.HLIPythonObject):
|
||||
def GetText(self):
|
||||
return self.name
|
||||
def CalculateIsExpandable(self):
|
||||
return 1
|
||||
|
||||
class HLICLSID(HLICOM):
|
||||
def __init__(self, myobject, name=None ):
|
||||
if type(myobject)==type(''):
|
||||
myobject = pythoncom.MakeIID(myobject)
|
||||
if name is None:
|
||||
try:
|
||||
name = pythoncom.ProgIDFromCLSID(myobject)
|
||||
except pythoncom.com_error:
|
||||
name = str(myobject)
|
||||
name = "IID: " + name
|
||||
HLICOM.__init__(self, myobject, name)
|
||||
def CalculateIsExpandable(self):
|
||||
return 0
|
||||
def GetSubList(self):
|
||||
return []
|
||||
|
||||
class HLI_Interface(HLICOM):
|
||||
pass
|
||||
|
||||
class HLI_Enum(HLI_Interface):
|
||||
def GetBitmapColumn(self):
|
||||
return 0 # Always a folder.
|
||||
def CalculateIsExpandable(self):
|
||||
if self.myobject is not None:
|
||||
rc = len(self.myobject.Next(1))>0
|
||||
self.myobject.Reset()
|
||||
else:
|
||||
rc = 0
|
||||
return rc
|
||||
pass
|
||||
|
||||
class HLI_IEnumMoniker(HLI_Enum):
|
||||
def GetSubList(self):
|
||||
ctx = pythoncom.CreateBindCtx()
|
||||
ret = []
|
||||
for mon in util.Enumerator(self.myobject):
|
||||
ret.append(HLI_IMoniker(mon, mon.GetDisplayName(ctx, None)))
|
||||
return ret
|
||||
|
||||
class HLI_IMoniker(HLI_Interface):
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
ret.append(browser.MakeHLI(self.myobject.Hash(), "Hash Value"))
|
||||
subenum = self.myobject.Enum(1)
|
||||
ret.append(HLI_IEnumMoniker(subenum, "Sub Monikers"))
|
||||
return ret
|
||||
|
||||
class HLIHeadingCategory(HLICOM):
|
||||
"A tree heading for registered categories"
|
||||
def GetText(self):
|
||||
return "Registered Categories"
|
||||
def GetSubList(self):
|
||||
catinf=pythoncom.CoCreateInstance(pythoncom.CLSID_StdComponentCategoriesMgr,None,pythoncom.CLSCTX_INPROC,pythoncom.IID_ICatInformation)
|
||||
enum=util.Enumerator(catinf.EnumCategories())
|
||||
ret = []
|
||||
try:
|
||||
for catid, lcid, desc in enum:
|
||||
ret.append(HLICategory((catid, lcid, desc)))
|
||||
except pythoncom.com_error:
|
||||
# Registered categories occasionally seem to give spurious errors.
|
||||
pass # Use what we already have.
|
||||
return ret
|
||||
|
||||
class HLICategory(HLICOM):
|
||||
"An actual Registered Category"
|
||||
def GetText(self):
|
||||
desc = self.myobject[2]
|
||||
if not desc: desc = "(unnamed category)"
|
||||
return desc
|
||||
def GetSubList(self):
|
||||
win32ui.DoWaitCursor(1)
|
||||
catid, lcid, desc = self.myobject
|
||||
catinf=pythoncom.CoCreateInstance(pythoncom.CLSID_StdComponentCategoriesMgr,None,pythoncom.CLSCTX_INPROC,pythoncom.IID_ICatInformation)
|
||||
ret = []
|
||||
for clsid in util.Enumerator(catinf.EnumClassesOfCategories((catid,),())):
|
||||
ret.append(HLICLSID(clsid))
|
||||
win32ui.DoWaitCursor(0)
|
||||
|
||||
return ret
|
||||
|
||||
class HLIHelpFile(HLICOM):
|
||||
def CalculateIsExpandable(self):
|
||||
return 0
|
||||
def GetText(self):
|
||||
import os
|
||||
fname, ctx = self.myobject
|
||||
base = os.path.split(fname)[1]
|
||||
return "Help reference in %s" %( base)
|
||||
|
||||
def TakeDefaultAction(self):
|
||||
fname, ctx = self.myobject
|
||||
if ctx:
|
||||
cmd = win32con.HELP_CONTEXT
|
||||
else:
|
||||
cmd = win32con.HELP_FINDER
|
||||
win32api.WinHelp(win32ui.GetMainFrame().GetSafeHwnd(), fname, cmd, ctx)
|
||||
def GetBitmapColumn(self):
|
||||
return 6
|
||||
|
||||
class HLIRegisteredTypeLibrary(HLICOM):
|
||||
def GetSubList(self):
|
||||
import os
|
||||
clsidstr, versionStr = self.myobject
|
||||
collected = []
|
||||
helpPath = ""
|
||||
key = win32api.RegOpenKey(win32con.HKEY_CLASSES_ROOT, "TypeLib\\%s\\%s" % (clsidstr, versionStr))
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
num = 0
|
||||
while 1:
|
||||
try:
|
||||
subKey = win32api.RegEnumKey(key, num)
|
||||
except win32api.error:
|
||||
break
|
||||
hSubKey = win32api.RegOpenKey(key, subKey)
|
||||
try:
|
||||
value, typ = win32api.RegQueryValueEx(hSubKey, None)
|
||||
if typ == win32con.REG_EXPAND_SZ:
|
||||
value = win32api.ExpandEnvironmentStrings(value)
|
||||
except win32api.error:
|
||||
value = ""
|
||||
if subKey=="HELPDIR":
|
||||
helpPath = value
|
||||
elif subKey=="Flags":
|
||||
flags = value
|
||||
else:
|
||||
try:
|
||||
lcid = int(subKey)
|
||||
lcidkey = win32api.RegOpenKey(key, subKey)
|
||||
# Enumerate the platforms
|
||||
lcidnum = 0
|
||||
while 1:
|
||||
try:
|
||||
platform = win32api.RegEnumKey(lcidkey, lcidnum)
|
||||
except win32api.error:
|
||||
break
|
||||
try:
|
||||
hplatform = win32api.RegOpenKey(lcidkey, platform)
|
||||
fname, typ = win32api.RegQueryValueEx(hplatform, None)
|
||||
if typ == win32con.REG_EXPAND_SZ:
|
||||
fname = win32api.ExpandEnvironmentStrings(fname)
|
||||
except win32api.error:
|
||||
fname = ""
|
||||
collected.append((lcid, platform, fname))
|
||||
lcidnum = lcidnum + 1
|
||||
win32api.RegCloseKey(lcidkey)
|
||||
except ValueError:
|
||||
pass
|
||||
num = num + 1
|
||||
finally:
|
||||
win32ui.DoWaitCursor(0)
|
||||
win32api.RegCloseKey(key)
|
||||
# Now, loop over my collected objects, adding a TypeLib and a HelpFile
|
||||
ret = []
|
||||
# if helpPath: ret.append(browser.MakeHLI(helpPath, "Help Path"))
|
||||
ret.append(HLICLSID(clsidstr))
|
||||
for lcid, platform, fname in collected:
|
||||
extraDescs = []
|
||||
if platform!="win32":
|
||||
extraDescs.append(platform)
|
||||
if lcid:
|
||||
extraDescs.append("locale=%s"%lcid)
|
||||
extraDesc = ""
|
||||
if extraDescs: extraDesc = " (%s)" % ", ".join(extraDescs)
|
||||
ret.append(HLITypeLib(fname, "Type Library" + extraDesc))
|
||||
ret.sort()
|
||||
return ret
|
||||
|
||||
class HLITypeLibEntry(HLICOM):
|
||||
def GetText(self):
|
||||
tlb, index = self.myobject
|
||||
name, doc, ctx, helpFile = tlb.GetDocumentation(index)
|
||||
try:
|
||||
typedesc = HLITypeKinds[tlb.GetTypeInfoType(index)][1]
|
||||
except KeyError:
|
||||
typedesc = "Unknown!"
|
||||
return name + " - " + typedesc
|
||||
def GetSubList(self):
|
||||
tlb, index = self.myobject
|
||||
name, doc, ctx, helpFile = tlb.GetDocumentation(index)
|
||||
ret = []
|
||||
if doc: ret.append(browser.HLIDocString(doc, "Doc"))
|
||||
if helpFile: ret.append(HLIHelpFile( (helpFile, ctx) ))
|
||||
return ret
|
||||
|
||||
class HLICoClass(HLITypeLibEntry):
|
||||
def GetSubList(self):
|
||||
ret = HLITypeLibEntry.GetSubList(self)
|
||||
tlb, index = self.myobject
|
||||
typeinfo = tlb.GetTypeInfo(index)
|
||||
attr = typeinfo.GetTypeAttr()
|
||||
for j in range(attr[8]):
|
||||
flags = typeinfo.GetImplTypeFlags(j)
|
||||
refType = typeinfo.GetRefTypeInfo(typeinfo.GetRefTypeOfImplType(j))
|
||||
refAttr = refType.GetTypeAttr()
|
||||
ret.append(browser.MakeHLI(refAttr[0], "Name=%s, Flags = %d" % (refAttr[0], flags)))
|
||||
return ret
|
||||
|
||||
|
||||
class HLITypeLibMethod(HLITypeLibEntry):
|
||||
def __init__(self, ob, name = None):
|
||||
self.entry_type = "Method"
|
||||
HLITypeLibEntry.__init__(self, ob, name)
|
||||
def GetSubList(self):
|
||||
ret = HLITypeLibEntry.GetSubList(self)
|
||||
tlb, index = self.myobject
|
||||
typeinfo = tlb.GetTypeInfo(index)
|
||||
attr = typeinfo.GetTypeAttr()
|
||||
for i in range(attr[7]):
|
||||
ret.append(HLITypeLibProperty((typeinfo, i)))
|
||||
for i in range(attr[6]):
|
||||
ret.append(HLITypeLibFunction((typeinfo, i)))
|
||||
return ret
|
||||
|
||||
class HLITypeLibEnum(HLITypeLibEntry):
|
||||
def __init__(self, myitem):
|
||||
typelib, index = myitem
|
||||
typeinfo = typelib.GetTypeInfo(index)
|
||||
self.id = typeinfo.GetVarDesc(index)[0]
|
||||
name = typeinfo.GetNames(self.id)[0]
|
||||
HLITypeLibEntry.__init__(self, myitem, name)
|
||||
def GetText(self):
|
||||
return self.name + " - Enum/Module"
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
typelib, index = self.myobject
|
||||
typeinfo = typelib.GetTypeInfo(index)
|
||||
attr = typeinfo.GetTypeAttr()
|
||||
for j in range(attr[7]):
|
||||
vdesc = typeinfo.GetVarDesc(j)
|
||||
name = typeinfo.GetNames(vdesc[0])[0]
|
||||
ret.append(browser.MakeHLI(vdesc[1], name))
|
||||
return ret
|
||||
|
||||
class HLITypeLibProperty(HLICOM):
|
||||
def __init__(self, myitem):
|
||||
typeinfo, index = myitem
|
||||
self.id = typeinfo.GetVarDesc(index)[0]
|
||||
name = typeinfo.GetNames(self.id)[0]
|
||||
HLICOM.__init__(self, myitem, name)
|
||||
def GetText(self):
|
||||
return self.name + " - Property"
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
typeinfo, index = self.myobject
|
||||
names = typeinfo.GetNames(self.id)
|
||||
if len(names)>1:
|
||||
ret.append(browser.MakeHLI(names[1:], "Named Params"))
|
||||
vd = typeinfo.GetVarDesc(index)
|
||||
ret.append(browser.MakeHLI(self.id, "Dispatch ID"))
|
||||
ret.append(browser.MakeHLI(vd[1], "Value"))
|
||||
ret.append(browser.MakeHLI(vd[2], "Elem Desc"))
|
||||
ret.append(browser.MakeHLI(vd[3], "Var Flags"))
|
||||
ret.append(browser.MakeHLI(vd[4], "Var Kind"))
|
||||
return ret
|
||||
|
||||
class HLITypeLibFunction(HLICOM):
|
||||
funckinds = {pythoncom.FUNC_VIRTUAL : "Virtual",
|
||||
pythoncom.FUNC_PUREVIRTUAL : "Pure Virtual",
|
||||
pythoncom.FUNC_STATIC : "Static",
|
||||
pythoncom.FUNC_DISPATCH : "Dispatch",
|
||||
}
|
||||
invokekinds = {pythoncom.INVOKE_FUNC: "Function",
|
||||
pythoncom.INVOKE_PROPERTYGET : "Property Get",
|
||||
pythoncom.INVOKE_PROPERTYPUT : "Property Put",
|
||||
pythoncom.INVOKE_PROPERTYPUTREF : "Property Put by reference",
|
||||
}
|
||||
funcflags = [(pythoncom.FUNCFLAG_FRESTRICTED, "Restricted"),
|
||||
(pythoncom.FUNCFLAG_FSOURCE, "Source"),
|
||||
(pythoncom.FUNCFLAG_FBINDABLE, "Bindable"),
|
||||
(pythoncom.FUNCFLAG_FREQUESTEDIT, "Request Edit"),
|
||||
(pythoncom.FUNCFLAG_FDISPLAYBIND, "Display Bind"),
|
||||
(pythoncom.FUNCFLAG_FDEFAULTBIND, "Default Bind"),
|
||||
(pythoncom.FUNCFLAG_FHIDDEN, "Hidden"),
|
||||
(pythoncom.FUNCFLAG_FUSESGETLASTERROR, "Uses GetLastError"),
|
||||
]
|
||||
|
||||
vartypes = {pythoncom.VT_EMPTY: "Empty",
|
||||
pythoncom.VT_NULL: "NULL",
|
||||
pythoncom.VT_I2: "Integer 2",
|
||||
pythoncom.VT_I4: "Integer 4",
|
||||
pythoncom.VT_R4: "Real 4",
|
||||
pythoncom.VT_R8: "Real 8",
|
||||
pythoncom.VT_CY: "CY",
|
||||
pythoncom.VT_DATE: "Date",
|
||||
pythoncom.VT_BSTR: "String",
|
||||
pythoncom.VT_DISPATCH: "IDispatch",
|
||||
pythoncom.VT_ERROR: "Error",
|
||||
pythoncom.VT_BOOL: "BOOL",
|
||||
pythoncom.VT_VARIANT: "Variant",
|
||||
pythoncom.VT_UNKNOWN: "IUnknown",
|
||||
pythoncom.VT_DECIMAL: "Decimal",
|
||||
pythoncom.VT_I1: "Integer 1",
|
||||
pythoncom.VT_UI1: "Unsigned integer 1",
|
||||
pythoncom.VT_UI2: "Unsigned integer 2",
|
||||
pythoncom.VT_UI4: "Unsigned integer 4",
|
||||
pythoncom.VT_I8: "Integer 8",
|
||||
pythoncom.VT_UI8: "Unsigned integer 8",
|
||||
pythoncom.VT_INT: "Integer",
|
||||
pythoncom.VT_UINT: "Unsigned integer",
|
||||
pythoncom.VT_VOID: "Void",
|
||||
pythoncom.VT_HRESULT: "HRESULT",
|
||||
pythoncom.VT_PTR: "Pointer",
|
||||
pythoncom.VT_SAFEARRAY: "SafeArray",
|
||||
pythoncom.VT_CARRAY: "C Array",
|
||||
pythoncom.VT_USERDEFINED: "User Defined",
|
||||
pythoncom.VT_LPSTR: "Pointer to string",
|
||||
pythoncom.VT_LPWSTR: "Pointer to Wide String",
|
||||
pythoncom.VT_FILETIME: "File time",
|
||||
pythoncom.VT_BLOB: "Blob",
|
||||
pythoncom.VT_STREAM: "IStream",
|
||||
pythoncom.VT_STORAGE: "IStorage",
|
||||
pythoncom.VT_STORED_OBJECT: "Stored object",
|
||||
pythoncom.VT_STREAMED_OBJECT: "Streamed object",
|
||||
pythoncom.VT_BLOB_OBJECT: "Blob object",
|
||||
pythoncom.VT_CF: "CF",
|
||||
pythoncom.VT_CLSID: "CLSID",
|
||||
}
|
||||
|
||||
type_flags = [ (pythoncom.VT_VECTOR, "Vector"),
|
||||
(pythoncom.VT_ARRAY, "Array"),
|
||||
(pythoncom.VT_BYREF, "ByRef"),
|
||||
(pythoncom.VT_RESERVED, "Reserved"),
|
||||
]
|
||||
|
||||
def __init__(self, myitem):
|
||||
typeinfo, index = myitem
|
||||
self.id = typeinfo.GetFuncDesc(index)[0]
|
||||
name = typeinfo.GetNames(self.id)[0]
|
||||
HLICOM.__init__(self, myitem, name)
|
||||
def GetText(self):
|
||||
return self.name + " - Function"
|
||||
def MakeReturnTypeName(self, typ):
|
||||
justtyp = typ & pythoncom.VT_TYPEMASK
|
||||
try:
|
||||
typname = self.vartypes[justtyp]
|
||||
except KeyError:
|
||||
typname = "?Bad type?"
|
||||
for (flag, desc) in self.type_flags:
|
||||
if flag & typ:
|
||||
typname = "%s(%s)" % (desc, typname)
|
||||
return typname
|
||||
def MakeReturnType(self, returnTypeDesc):
|
||||
if type(returnTypeDesc)==type(()):
|
||||
first = returnTypeDesc[0]
|
||||
result = self.MakeReturnType(first)
|
||||
if first != pythoncom.VT_USERDEFINED:
|
||||
result = result + " " + self.MakeReturnType(returnTypeDesc[1])
|
||||
return result
|
||||
else:
|
||||
return self.MakeReturnTypeName(returnTypeDesc)
|
||||
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
typeinfo, index = self.myobject
|
||||
names = typeinfo.GetNames(self.id)
|
||||
ret.append(browser.MakeHLI(self.id, "Dispatch ID"))
|
||||
if len(names)>1:
|
||||
ret.append(browser.MakeHLI(", ".join(names[1:]), "Named Params"))
|
||||
fd = typeinfo.GetFuncDesc(index)
|
||||
if fd[1]:
|
||||
ret.append(browser.MakeHLI(fd[1], "Possible result values"))
|
||||
if fd[8]:
|
||||
typ, flags, default = fd[8]
|
||||
val = self.MakeReturnType(typ)
|
||||
if flags:
|
||||
val = "%s (Flags=%d, default=%s)" % (val, flags, default)
|
||||
ret.append(browser.MakeHLI(val, "Return Type"))
|
||||
|
||||
for argDesc in fd[2]:
|
||||
typ, flags, default = argDesc
|
||||
val = self.MakeReturnType(typ)
|
||||
if flags:
|
||||
val = "%s (Flags=%d)" % (val, flags)
|
||||
if default is not None:
|
||||
val = "%s (Default=%s)" % (val, default)
|
||||
ret.append(browser.MakeHLI(val, "Argument"))
|
||||
|
||||
try:
|
||||
fkind = self.funckinds[fd[3]]
|
||||
except KeyError:
|
||||
fkind = "Unknown"
|
||||
ret.append(browser.MakeHLI(fkind, "Function Kind"))
|
||||
try:
|
||||
ikind = self.invokekinds[fd[4]]
|
||||
except KeyError:
|
||||
ikind = "Unknown"
|
||||
ret.append(browser.MakeHLI(ikind, "Invoke Kind"))
|
||||
# 5 = call conv
|
||||
# 5 = offset vtbl
|
||||
ret.append(browser.MakeHLI(fd[6], "Number Optional Params"))
|
||||
flagDescs = []
|
||||
for flag, desc in self.funcflags:
|
||||
if flag & fd[9]:
|
||||
flagDescs.append(desc)
|
||||
if flagDescs:
|
||||
ret.append(browser.MakeHLI(", ".join(flagDescs), "Function Flags"))
|
||||
return ret
|
||||
|
||||
HLITypeKinds = {
|
||||
pythoncom.TKIND_ENUM : (HLITypeLibEnum, 'Enumeration'),
|
||||
pythoncom.TKIND_RECORD : (HLITypeLibEntry, 'Record'),
|
||||
pythoncom.TKIND_MODULE : (HLITypeLibEnum, 'Module'),
|
||||
pythoncom.TKIND_INTERFACE : (HLITypeLibMethod, 'Interface'),
|
||||
pythoncom.TKIND_DISPATCH : (HLITypeLibMethod, 'Dispatch'),
|
||||
pythoncom.TKIND_COCLASS : (HLICoClass, 'CoClass'),
|
||||
pythoncom.TKIND_ALIAS : (HLITypeLibEntry, 'Alias'),
|
||||
pythoncom.TKIND_UNION : (HLITypeLibEntry, 'Union')
|
||||
}
|
||||
|
||||
class HLITypeLib(HLICOM):
|
||||
def GetSubList(self):
|
||||
ret = []
|
||||
ret.append(browser.MakeHLI(self.myobject, "Filename"))
|
||||
try:
|
||||
tlb = pythoncom.LoadTypeLib(self.myobject)
|
||||
except pythoncom.com_error:
|
||||
return [browser.MakeHLI("%s can not be loaded" % self.myobject)]
|
||||
|
||||
for i in range(tlb.GetTypeInfoCount()):
|
||||
try:
|
||||
ret.append(HLITypeKinds[tlb.GetTypeInfoType(i)][0]( (tlb, i) ) )
|
||||
except pythoncom.com_error:
|
||||
ret.append(browser.MakeHLI("The type info can not be loaded!"))
|
||||
ret.sort()
|
||||
return ret
|
||||
|
||||
class HLIHeadingRegisterdTypeLibs(HLICOM):
|
||||
"A tree heading for registered type libraries"
|
||||
def GetText(self):
|
||||
return "Registered Type Libraries"
|
||||
def GetSubList(self):
|
||||
# Explicit lookup in the registry.
|
||||
ret = []
|
||||
key = win32api.RegOpenKey(win32con.HKEY_CLASSES_ROOT, "TypeLib")
|
||||
win32ui.DoWaitCursor(1)
|
||||
try:
|
||||
num = 0
|
||||
while 1:
|
||||
try:
|
||||
keyName = win32api.RegEnumKey(key, num)
|
||||
except win32api.error:
|
||||
break
|
||||
# Enumerate all version info
|
||||
subKey = win32api.RegOpenKey(key, keyName)
|
||||
name = None
|
||||
try:
|
||||
subNum = 0
|
||||
bestVersion = 0.0
|
||||
while 1:
|
||||
try:
|
||||
versionStr = win32api.RegEnumKey(subKey, subNum)
|
||||
except win32api.error:
|
||||
break
|
||||
try:
|
||||
versionFlt = float(versionStr)
|
||||
except ValueError:
|
||||
versionFlt = 0 # ????
|
||||
if versionFlt > bestVersion:
|
||||
bestVersion = versionFlt
|
||||
name = win32api.RegQueryValue(subKey, versionStr)
|
||||
subNum = subNum + 1
|
||||
finally:
|
||||
win32api.RegCloseKey(subKey)
|
||||
if name is not None:
|
||||
ret.append(HLIRegisteredTypeLibrary((keyName, versionStr), name))
|
||||
num = num + 1
|
||||
finally:
|
||||
win32api.RegCloseKey(key)
|
||||
win32ui.DoWaitCursor(0)
|
||||
ret.sort()
|
||||
return ret
|
||||
|
||||
def main():
|
||||
from pywin.tools import hierlist
|
||||
root = HLIRoot("COM Browser")
|
||||
if "app" in sys.modules:
|
||||
# do it in a window
|
||||
browser.MakeTemplate()
|
||||
browser.template.OpenObject(root)
|
||||
else:
|
||||
# list=hierlist.HierListWithItems( root, win32ui.IDB_BROWSER_HIER )
|
||||
# dlg=hierlist.HierDialog("COM Browser",list)
|
||||
dlg = browser.dynamic_browser(root)
|
||||
dlg.DoModal()
|
||||
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
|
||||
ni = pythoncom._GetInterfaceCount()
|
||||
ng = pythoncom._GetGatewayCount()
|
||||
if ni or ng:
|
||||
print("Warning - exiting with %d/%d objects alive" % (ni,ng))
|
43
venv/Lib/site-packages/win32com/client/connect.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
"""Utilities for working with Connections"""
|
||||
import win32com.server.util, pythoncom
|
||||
|
||||
class SimpleConnection:
|
||||
"A simple, single connection object"
|
||||
def __init__(self, coInstance = None, eventInstance = None, eventCLSID = None, debug = 0):
|
||||
self.cp = None
|
||||
self.cookie = None
|
||||
self.debug = debug
|
||||
if not coInstance is None:
|
||||
self.Connect(coInstance , eventInstance, eventCLSID)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
self.Disconnect()
|
||||
except pythoncom.error:
|
||||
# Ignore disconnection as we are torn down.
|
||||
pass
|
||||
|
||||
def _wrap(self, obj):
|
||||
useDispatcher = None
|
||||
if self.debug:
|
||||
from win32com.server import dispatcher
|
||||
useDispatcher = dispatcher.DefaultDebugDispatcher
|
||||
return win32com.server.util.wrap(obj, useDispatcher=useDispatcher)
|
||||
|
||||
def Connect(self, coInstance, eventInstance, eventCLSID = None):
|
||||
try:
|
||||
oleobj = coInstance._oleobj_
|
||||
except AttributeError:
|
||||
oleobj = coInstance
|
||||
cpc=oleobj.QueryInterface(pythoncom.IID_IConnectionPointContainer)
|
||||
if eventCLSID is None: eventCLSID = eventInstance.CLSID
|
||||
comEventInstance = self._wrap(eventInstance)
|
||||
self.cp=cpc.FindConnectionPoint(eventCLSID)
|
||||
self.cookie = self.cp.Advise(comEventInstance)
|
||||
|
||||
def Disconnect(self):
|
||||
if not self.cp is None:
|
||||
if self.cookie:
|
||||
self.cp.Unadvise(self.cookie)
|
||||
self.cookie = None
|
||||
self.cp = None
|
581
venv/Lib/site-packages/win32com/client/dynamic.py
Normal file
|
@ -0,0 +1,581 @@
|
|||
"""Support for dynamic COM client support.
|
||||
|
||||
Introduction
|
||||
Dynamic COM client support is the ability to use a COM server without
|
||||
prior knowledge of the server. This can be used to talk to almost all
|
||||
COM servers, including much of MS Office.
|
||||
|
||||
In general, you should not use this module directly - see below.
|
||||
|
||||
Example
|
||||
>>> import win32com.client
|
||||
>>> xl = win32com.client.Dispatch("Excel.Application")
|
||||
# The line above invokes the functionality of this class.
|
||||
# xl is now an object we can use to talk to Excel.
|
||||
>>> xl.Visible = 1 # The Excel window becomes visible.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import traceback
|
||||
import types
|
||||
|
||||
import pythoncom
|
||||
import winerror
|
||||
from . import build
|
||||
|
||||
from pywintypes import IIDType
|
||||
|
||||
import win32com.client # Needed as code we eval() references it.
|
||||
|
||||
debugging=0 # General debugging
|
||||
debugging_attr=0 # Debugging dynamic attribute lookups.
|
||||
|
||||
LCID = 0x0
|
||||
|
||||
# These errors generally mean the property or method exists,
|
||||
# but can't be used in this context - eg, property instead of a method, etc.
|
||||
# Used to determine if we have a real error or not.
|
||||
ERRORS_BAD_CONTEXT = [
|
||||
winerror.DISP_E_MEMBERNOTFOUND,
|
||||
winerror.DISP_E_BADPARAMCOUNT,
|
||||
winerror.DISP_E_PARAMNOTOPTIONAL,
|
||||
winerror.DISP_E_TYPEMISMATCH,
|
||||
winerror.E_INVALIDARG,
|
||||
]
|
||||
|
||||
ALL_INVOKE_TYPES = [
|
||||
pythoncom.INVOKE_PROPERTYGET,
|
||||
pythoncom.INVOKE_PROPERTYPUT,
|
||||
pythoncom.INVOKE_PROPERTYPUTREF,
|
||||
pythoncom.INVOKE_FUNC
|
||||
]
|
||||
|
||||
def debug_print(*args):
|
||||
if debugging:
|
||||
for arg in args:
|
||||
print(arg, end=' ')
|
||||
print()
|
||||
|
||||
def debug_attr_print(*args):
|
||||
if debugging_attr:
|
||||
for arg in args:
|
||||
print(arg, end=' ')
|
||||
print()
|
||||
|
||||
# A helper to create method objects on the fly
|
||||
py3k = sys.version_info > (3,0)
|
||||
if py3k:
|
||||
def MakeMethod(func, inst, cls):
|
||||
return types.MethodType(func, inst) # class not needed in py3k
|
||||
else:
|
||||
MakeMethod = types.MethodType # all args used in py2k.
|
||||
|
||||
# get the type objects for IDispatch and IUnknown
|
||||
PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
|
||||
PyIUnknownType = pythoncom.TypeIIDs[pythoncom.IID_IUnknown]
|
||||
|
||||
if py3k:
|
||||
_GoodDispatchTypes=(str, IIDType)
|
||||
else:
|
||||
_GoodDispatchTypes=(str, IIDType, str)
|
||||
_defaultDispatchItem=build.DispatchItem
|
||||
|
||||
def _GetGoodDispatch(IDispatch, clsctx = pythoncom.CLSCTX_SERVER):
|
||||
# quick return for most common case
|
||||
if isinstance(IDispatch, PyIDispatchType):
|
||||
return IDispatch
|
||||
if isinstance(IDispatch, _GoodDispatchTypes):
|
||||
try:
|
||||
IDispatch = pythoncom.connect(IDispatch)
|
||||
except pythoncom.ole_error:
|
||||
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
|
||||
else:
|
||||
# may already be a wrapped class.
|
||||
IDispatch = getattr(IDispatch, "_oleobj_", IDispatch)
|
||||
return IDispatch
|
||||
|
||||
def _GetGoodDispatchAndUserName(IDispatch, userName, clsctx):
|
||||
# Get a dispatch object, and a 'user name' (ie, the name as
|
||||
# displayed to the user in repr() etc.
|
||||
if userName is None:
|
||||
# Displayed name should be a plain string in py2k, and unicode in py3k
|
||||
if isinstance(IDispatch, str):
|
||||
userName = IDispatch
|
||||
elif not py3k and isinstance(IDispatch, str):
|
||||
# 2to3 converts the above 'unicode' to 'str', but this will never be executed in py3k
|
||||
userName = IDispatch.encode("ascii", "replace")
|
||||
## ??? else userName remains None ???
|
||||
elif not py3k and isinstance(userName, str):
|
||||
# 2to3 converts the above 'unicode' to 'str', but this will never be executed in py3k
|
||||
# As above - always a plain string in py2k
|
||||
userName = userName.encode("ascii", "replace")
|
||||
else:
|
||||
userName = str(userName)
|
||||
return (_GetGoodDispatch(IDispatch, clsctx), userName)
|
||||
|
||||
def _GetDescInvokeType(entry, invoke_type):
|
||||
# determine the wFlags argument passed as input to IDispatch::Invoke
|
||||
if not entry or not entry.desc: return invoke_type
|
||||
varkind = entry.desc[4] # from VARDESC struct returned by ITypeComp::Bind
|
||||
if varkind == pythoncom.VAR_DISPATCH and invoke_type == pythoncom.INVOKE_PROPERTYGET:
|
||||
return pythoncom.INVOKE_FUNC | invoke_type # DISPATCH_METHOD & DISPATCH_PROPERTYGET can be combined in IDispatch::Invoke
|
||||
else:
|
||||
return varkind
|
||||
|
||||
def Dispatch(IDispatch, userName = None, createClass = None, typeinfo = None, UnicodeToString=None, clsctx = pythoncom.CLSCTX_SERVER):
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
IDispatch, userName = _GetGoodDispatchAndUserName(IDispatch,userName,clsctx)
|
||||
if createClass is None:
|
||||
createClass = CDispatch
|
||||
lazydata = None
|
||||
try:
|
||||
if typeinfo is None:
|
||||
typeinfo = IDispatch.GetTypeInfo()
|
||||
if typeinfo is not None:
|
||||
try:
|
||||
#try for a typecomp
|
||||
typecomp = typeinfo.GetTypeComp()
|
||||
lazydata = typeinfo, typecomp
|
||||
except pythoncom.com_error:
|
||||
pass
|
||||
except pythoncom.com_error:
|
||||
typeinfo = None
|
||||
olerepr = MakeOleRepr(IDispatch, typeinfo, lazydata)
|
||||
return createClass(IDispatch, olerepr, userName, lazydata=lazydata)
|
||||
|
||||
def MakeOleRepr(IDispatch, typeinfo, typecomp):
|
||||
olerepr = None
|
||||
if typeinfo is not None:
|
||||
try:
|
||||
attr = typeinfo.GetTypeAttr()
|
||||
# If the type info is a special DUAL interface, magically turn it into
|
||||
# a DISPATCH typeinfo.
|
||||
if attr[5] == pythoncom.TKIND_INTERFACE and attr[11] & pythoncom.TYPEFLAG_FDUAL:
|
||||
# Get corresponding Disp interface;
|
||||
# -1 is a special value which does this for us.
|
||||
href = typeinfo.GetRefTypeOfImplType(-1);
|
||||
typeinfo = typeinfo.GetRefTypeInfo(href)
|
||||
attr = typeinfo.GetTypeAttr()
|
||||
if typecomp is None:
|
||||
olerepr = build.DispatchItem(typeinfo, attr, None, 0)
|
||||
else:
|
||||
olerepr = build.LazyDispatchItem(attr, None)
|
||||
except pythoncom.ole_error:
|
||||
pass
|
||||
if olerepr is None: olerepr = build.DispatchItem()
|
||||
return olerepr
|
||||
|
||||
def DumbDispatch(IDispatch, userName = None, createClass = None,UnicodeToString=None, clsctx=pythoncom.CLSCTX_SERVER):
|
||||
"Dispatch with no type info"
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
IDispatch, userName = _GetGoodDispatchAndUserName(IDispatch,userName,clsctx)
|
||||
if createClass is None:
|
||||
createClass = CDispatch
|
||||
return createClass(IDispatch, build.DispatchItem(), userName)
|
||||
|
||||
class CDispatch:
|
||||
def __init__(self, IDispatch, olerepr, userName=None, UnicodeToString=None, lazydata=None):
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
if userName is None: userName = "<unknown>"
|
||||
self.__dict__['_oleobj_'] = IDispatch
|
||||
self.__dict__['_username_'] = userName
|
||||
self.__dict__['_olerepr_'] = olerepr
|
||||
self.__dict__['_mapCachedItems_'] = {}
|
||||
self.__dict__['_builtMethods_'] = {}
|
||||
self.__dict__['_enum_'] = None
|
||||
self.__dict__['_unicode_to_string_'] = None
|
||||
self.__dict__['_lazydata_'] = lazydata
|
||||
|
||||
def __call__(self, *args):
|
||||
"Provide 'default dispatch' COM functionality - allow instance to be called"
|
||||
if self._olerepr_.defaultDispatchName:
|
||||
invkind, dispid = self._find_dispatch_type_(self._olerepr_.defaultDispatchName)
|
||||
else:
|
||||
invkind, dispid = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET, pythoncom.DISPID_VALUE
|
||||
if invkind is not None:
|
||||
allArgs = (dispid,LCID,invkind,1) + args
|
||||
return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None)
|
||||
raise TypeError("This dispatch object does not define a default method")
|
||||
|
||||
def __bool__(self):
|
||||
return True # ie "if object:" should always be "true" - without this, __len__ is tried.
|
||||
# _Possibly_ want to defer to __len__ if available, but Im not sure this is
|
||||
# desirable???
|
||||
|
||||
def __repr__(self):
|
||||
return "<COMObject %s>" % (self._username_)
|
||||
|
||||
def __str__(self):
|
||||
# __str__ is used when the user does "print object", so we gracefully
|
||||
# fall back to the __repr__ if the object has no default method.
|
||||
try:
|
||||
return str(self.__call__())
|
||||
except pythoncom.com_error as details:
|
||||
if details.hresult not in ERRORS_BAD_CONTEXT:
|
||||
raise
|
||||
return self.__repr__()
|
||||
|
||||
# Delegate comparison to the oleobjs, as they know how to do identity.
|
||||
def __eq__(self, other):
|
||||
other = getattr(other, "_oleobj_", other)
|
||||
return self._oleobj_ == other
|
||||
|
||||
def __ne__(self, other):
|
||||
other = getattr(other, "_oleobj_", other)
|
||||
return self._oleobj_ != other
|
||||
|
||||
def __int__(self):
|
||||
return int(self.__call__())
|
||||
|
||||
def __len__(self):
|
||||
invkind, dispid = self._find_dispatch_type_("Count")
|
||||
if invkind:
|
||||
return self._oleobj_.Invoke(dispid, LCID, invkind, 1)
|
||||
raise TypeError("This dispatch object does not define a Count method")
|
||||
|
||||
def _NewEnum(self):
|
||||
try:
|
||||
invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET
|
||||
enum = self._oleobj_.InvokeTypes(pythoncom.DISPID_NEWENUM,LCID,invkind,(13, 10),())
|
||||
except pythoncom.com_error:
|
||||
return None # no enumerator for this object.
|
||||
from . import util
|
||||
return util.WrapEnum(enum, None)
|
||||
|
||||
def __getitem__(self, index): # syver modified
|
||||
# Improved __getitem__ courtesy Syver Enstad
|
||||
# Must check _NewEnum before Item, to ensure b/w compat.
|
||||
if isinstance(index, int):
|
||||
if self.__dict__['_enum_'] is None:
|
||||
self.__dict__['_enum_'] = self._NewEnum()
|
||||
if self.__dict__['_enum_'] is not None:
|
||||
return self._get_good_object_(self._enum_.__getitem__(index))
|
||||
# See if we have an "Item" method/property we can use (goes hand in hand with Count() above!)
|
||||
invkind, dispid = self._find_dispatch_type_("Item")
|
||||
if invkind is not None:
|
||||
return self._get_good_object_(self._oleobj_.Invoke(dispid, LCID, invkind, 1, index))
|
||||
raise TypeError("This object does not support enumeration")
|
||||
|
||||
def __setitem__(self, index, *args):
|
||||
# XXX - todo - We should support calling Item() here too!
|
||||
# print "__setitem__ with", index, args
|
||||
if self._olerepr_.defaultDispatchName:
|
||||
invkind, dispid = self._find_dispatch_type_(self._olerepr_.defaultDispatchName)
|
||||
else:
|
||||
invkind, dispid = pythoncom.DISPATCH_PROPERTYPUT | pythoncom.DISPATCH_PROPERTYPUTREF, pythoncom.DISPID_VALUE
|
||||
if invkind is not None:
|
||||
allArgs = (dispid,LCID,invkind,0,index) + args
|
||||
return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None)
|
||||
raise TypeError("This dispatch object does not define a default method")
|
||||
|
||||
def _find_dispatch_type_(self, methodName):
|
||||
if methodName in self._olerepr_.mapFuncs:
|
||||
item = self._olerepr_.mapFuncs[methodName]
|
||||
return item.desc[4], item.dispid
|
||||
|
||||
if methodName in self._olerepr_.propMapGet:
|
||||
item = self._olerepr_.propMapGet[methodName]
|
||||
return item.desc[4], item.dispid
|
||||
|
||||
try:
|
||||
dispid = self._oleobj_.GetIDsOfNames(0,methodName)
|
||||
except: ### what error?
|
||||
return None, None
|
||||
return pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET, dispid
|
||||
|
||||
def _ApplyTypes_(self, dispid, wFlags, retType, argTypes, user, resultCLSID, *args):
|
||||
result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
|
||||
return self._get_good_object_(result, user, resultCLSID)
|
||||
|
||||
def _wrap_dispatch_(self, ob, userName = None, returnCLSID = None, UnicodeToString=None):
|
||||
# Given a dispatch object, wrap it in a class
|
||||
assert UnicodeToString is None, "this is deprecated and will go away"
|
||||
return Dispatch(ob, userName)
|
||||
|
||||
def _get_good_single_object_(self,ob,userName = None, ReturnCLSID=None):
|
||||
if isinstance(ob, PyIDispatchType):
|
||||
# make a new instance of (probably this) class.
|
||||
return self._wrap_dispatch_(ob, userName, ReturnCLSID)
|
||||
if isinstance(ob, PyIUnknownType):
|
||||
try:
|
||||
ob = ob.QueryInterface(pythoncom.IID_IDispatch)
|
||||
except pythoncom.com_error:
|
||||
# It is an IUnknown, but not an IDispatch, so just let it through.
|
||||
return ob
|
||||
return self._wrap_dispatch_(ob, userName, ReturnCLSID)
|
||||
return ob
|
||||
|
||||
def _get_good_object_(self,ob,userName = None, ReturnCLSID=None):
|
||||
"""Given an object (usually the retval from a method), make it a good object to return.
|
||||
Basically checks if it is a COM object, and wraps it up.
|
||||
Also handles the fact that a retval may be a tuple of retvals"""
|
||||
if ob is None: # Quick exit!
|
||||
return None
|
||||
elif isinstance(ob, tuple):
|
||||
return tuple(map(lambda o, s=self, oun=userName, rc=ReturnCLSID: s._get_good_single_object_(o, oun, rc), ob))
|
||||
else:
|
||||
return self._get_good_single_object_(ob)
|
||||
|
||||
def _make_method_(self, name):
|
||||
"Make a method object - Assumes in olerepr funcmap"
|
||||
methodName = build.MakePublicAttributeName(name) # translate keywords etc.
|
||||
methodCodeList = self._olerepr_.MakeFuncMethod(self._olerepr_.mapFuncs[name], methodName,0)
|
||||
methodCode = "\n".join(methodCodeList)
|
||||
try:
|
||||
# print "Method code for %s is:\n" % self._username_, methodCode
|
||||
# self._print_details_()
|
||||
codeObject = compile(methodCode, "<COMObject %s>" % self._username_,"exec")
|
||||
# Exec the code object
|
||||
tempNameSpace = {}
|
||||
# "Dispatch" in the exec'd code is win32com.client.Dispatch, not ours.
|
||||
globNameSpace = globals().copy()
|
||||
globNameSpace["Dispatch"] = win32com.client.Dispatch
|
||||
exec(codeObject, globNameSpace, tempNameSpace) # self.__dict__, self.__dict__
|
||||
name = methodName
|
||||
# Save the function in map.
|
||||
fn = self._builtMethods_[name] = tempNameSpace[name]
|
||||
newMeth = MakeMethod(fn, self, self.__class__)
|
||||
return newMeth
|
||||
except:
|
||||
debug_print("Error building OLE definition for code ", methodCode)
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def _Release_(self):
|
||||
"""Cleanup object - like a close - to force cleanup when you dont
|
||||
want to rely on Python's reference counting."""
|
||||
for childCont in self._mapCachedItems_.values():
|
||||
childCont._Release_()
|
||||
self._mapCachedItems_ = {}
|
||||
if self._oleobj_:
|
||||
self._oleobj_.Release()
|
||||
self.__dict__['_oleobj_'] = None
|
||||
if self._olerepr_:
|
||||
self.__dict__['_olerepr_'] = None
|
||||
self._enum_ = None
|
||||
|
||||
def _proc_(self, name, *args):
|
||||
"""Call the named method as a procedure, rather than function.
|
||||
Mainly used by Word.Basic, which whinges about such things."""
|
||||
try:
|
||||
item = self._olerepr_.mapFuncs[name]
|
||||
dispId = item.dispid
|
||||
return self._get_good_object_(self._oleobj_.Invoke(*(dispId, LCID, item.desc[4], 0) + (args) ))
|
||||
except KeyError:
|
||||
raise AttributeError(name)
|
||||
|
||||
def _print_details_(self):
|
||||
"Debug routine - dumps what it knows about an object."
|
||||
print("AxDispatch container",self._username_)
|
||||
try:
|
||||
print("Methods:")
|
||||
for method in self._olerepr_.mapFuncs.keys():
|
||||
print("\t", method)
|
||||
print("Props:")
|
||||
for prop, entry in self._olerepr_.propMap.items():
|
||||
print("\t%s = 0x%x - %s" % (prop, entry.dispid, repr(entry)))
|
||||
print("Get Props:")
|
||||
for prop, entry in self._olerepr_.propMapGet.items():
|
||||
print("\t%s = 0x%x - %s" % (prop, entry.dispid, repr(entry)))
|
||||
print("Put Props:")
|
||||
for prop, entry in self._olerepr_.propMapPut.items():
|
||||
print("\t%s = 0x%x - %s" % (prop, entry.dispid, repr(entry)))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def __LazyMap__(self, attr):
|
||||
try:
|
||||
if self._LazyAddAttr_(attr):
|
||||
debug_attr_print("%s.__LazyMap__(%s) added something" % (self._username_,attr))
|
||||
return 1
|
||||
except AttributeError:
|
||||
return 0
|
||||
|
||||
# Using the typecomp, lazily create a new attribute definition.
|
||||
def _LazyAddAttr_(self,attr):
|
||||
if self._lazydata_ is None: return 0
|
||||
res = 0
|
||||
typeinfo, typecomp = self._lazydata_
|
||||
olerepr = self._olerepr_
|
||||
# We need to explicitly check each invoke type individually - simply
|
||||
# specifying '0' will bind to "any member", which may not be the one
|
||||
# we are actually after (ie, we may be after prop_get, but returned
|
||||
# the info for the prop_put.)
|
||||
for i in ALL_INVOKE_TYPES:
|
||||
try:
|
||||
x,t = typecomp.Bind(attr,i)
|
||||
# Support 'Get' and 'Set' properties - see
|
||||
# bug 1587023
|
||||
if x==0 and attr[:3] in ('Set', 'Get'):
|
||||
x,t = typecomp.Bind(attr[3:], i)
|
||||
if x==1: #it's a FUNCDESC
|
||||
r = olerepr._AddFunc_(typeinfo,t,0)
|
||||
elif x==2: #it's a VARDESC
|
||||
r = olerepr._AddVar_(typeinfo,t,0)
|
||||
else: #not found or TYPEDESC/IMPLICITAPP
|
||||
r=None
|
||||
if not r is None:
|
||||
key, map = r[0],r[1]
|
||||
item = map[key]
|
||||
if map==olerepr.propMapPut:
|
||||
olerepr._propMapPutCheck_(key,item)
|
||||
elif map==olerepr.propMapGet:
|
||||
olerepr._propMapGetCheck_(key,item)
|
||||
res = 1
|
||||
except:
|
||||
pass
|
||||
return res
|
||||
|
||||
def _FlagAsMethod(self, *methodNames):
|
||||
"""Flag these attribute names as being methods.
|
||||
Some objects do not correctly differentiate methods and
|
||||
properties, leading to problems when calling these methods.
|
||||
|
||||
Specifically, trying to say: ob.SomeFunc()
|
||||
may yield an exception "None object is not callable"
|
||||
In this case, an attempt to fetch the *property*has worked
|
||||
and returned None, rather than indicating it is really a method.
|
||||
Calling: ob._FlagAsMethod("SomeFunc")
|
||||
should then allow this to work.
|
||||
"""
|
||||
for name in methodNames:
|
||||
details = build.MapEntry(self.__AttrToID__(name), (name,))
|
||||
self._olerepr_.mapFuncs[name] = details
|
||||
|
||||
def __AttrToID__(self,attr):
|
||||
debug_attr_print("Calling GetIDsOfNames for property %s in Dispatch container %s" % (attr, self._username_))
|
||||
return self._oleobj_.GetIDsOfNames(0,attr)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr=='__iter__':
|
||||
# We can't handle this as a normal method, as if the attribute
|
||||
# exists, then it must return an iterable object.
|
||||
try:
|
||||
invkind = pythoncom.DISPATCH_METHOD | pythoncom.DISPATCH_PROPERTYGET
|
||||
enum = self._oleobj_.InvokeTypes(pythoncom.DISPID_NEWENUM,LCID,invkind,(13, 10),())
|
||||
except pythoncom.com_error:
|
||||
raise AttributeError("This object can not function as an iterator")
|
||||
# We must return a callable object.
|
||||
class Factory:
|
||||
def __init__(self, ob):
|
||||
self.ob = ob
|
||||
def __call__(self):
|
||||
import win32com.client.util
|
||||
return win32com.client.util.Iterator(self.ob)
|
||||
return Factory(enum)
|
||||
|
||||
if attr.startswith('_') and attr.endswith('_'): # Fast-track.
|
||||
raise AttributeError(attr)
|
||||
# If a known method, create new instance and return.
|
||||
try:
|
||||
return MakeMethod(self._builtMethods_[attr], self, self.__class__)
|
||||
except KeyError:
|
||||
pass
|
||||
# XXX - Note that we current are case sensitive in the method.
|
||||
#debug_attr_print("GetAttr called for %s on DispatchContainer %s" % (attr,self._username_))
|
||||
# First check if it is in the method map. Note that an actual method
|
||||
# must not yet exist, (otherwise we would not be here). This
|
||||
# means we create the actual method object - which also means
|
||||
# this code will never be asked for that method name again.
|
||||
if attr in self._olerepr_.mapFuncs:
|
||||
return self._make_method_(attr)
|
||||
|
||||
# Delegate to property maps/cached items
|
||||
retEntry = None
|
||||
if self._olerepr_ and self._oleobj_:
|
||||
# first check general property map, then specific "put" map.
|
||||
retEntry = self._olerepr_.propMap.get(attr)
|
||||
if retEntry is None:
|
||||
retEntry = self._olerepr_.propMapGet.get(attr)
|
||||
# Not found so far - See what COM says.
|
||||
if retEntry is None:
|
||||
try:
|
||||
if self.__LazyMap__(attr):
|
||||
if attr in self._olerepr_.mapFuncs: return self._make_method_(attr)
|
||||
retEntry = self._olerepr_.propMap.get(attr)
|
||||
if retEntry is None:
|
||||
retEntry = self._olerepr_.propMapGet.get(attr)
|
||||
if retEntry is None:
|
||||
retEntry = build.MapEntry(self.__AttrToID__(attr), (attr,))
|
||||
except pythoncom.ole_error:
|
||||
pass # No prop by that name - retEntry remains None.
|
||||
|
||||
if not retEntry is None: # see if in my cache
|
||||
try:
|
||||
ret = self._mapCachedItems_[retEntry.dispid]
|
||||
debug_attr_print ("Cached items has attribute!", ret)
|
||||
return ret
|
||||
except (KeyError, AttributeError):
|
||||
debug_attr_print("Attribute %s not in cache" % attr)
|
||||
|
||||
# If we are still here, and have a retEntry, get the OLE item
|
||||
if not retEntry is None:
|
||||
invoke_type = _GetDescInvokeType(retEntry, pythoncom.INVOKE_PROPERTYGET)
|
||||
debug_attr_print("Getting property Id 0x%x from OLE object" % retEntry.dispid)
|
||||
try:
|
||||
ret = self._oleobj_.Invoke(retEntry.dispid,0,invoke_type,1)
|
||||
except pythoncom.com_error as details:
|
||||
if details.hresult in ERRORS_BAD_CONTEXT:
|
||||
# May be a method.
|
||||
self._olerepr_.mapFuncs[attr] = retEntry
|
||||
return self._make_method_(attr)
|
||||
raise
|
||||
debug_attr_print("OLE returned ", ret)
|
||||
return self._get_good_object_(ret)
|
||||
|
||||
# no where else to look.
|
||||
raise AttributeError("%s.%s" % (self._username_, attr))
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in self.__dict__: # Fast-track - if already in our dict, just make the assignment.
|
||||
# XXX - should maybe check method map - if someone assigns to a method,
|
||||
# it could mean something special (not sure what, tho!)
|
||||
self.__dict__[attr] = value
|
||||
return
|
||||
# Allow property assignment.
|
||||
debug_attr_print("SetAttr called for %s.%s=%s on DispatchContainer" % (self._username_, attr, repr(value)))
|
||||
|
||||
if self._olerepr_:
|
||||
# Check the "general" property map.
|
||||
if attr in self._olerepr_.propMap:
|
||||
entry = self._olerepr_.propMap[attr]
|
||||
invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)
|
||||
self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
|
||||
return
|
||||
# Check the specific "put" map.
|
||||
if attr in self._olerepr_.propMapPut:
|
||||
entry = self._olerepr_.propMapPut[attr]
|
||||
invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)
|
||||
self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
|
||||
return
|
||||
|
||||
# Try the OLE Object
|
||||
if self._oleobj_:
|
||||
if self.__LazyMap__(attr):
|
||||
# Check the "general" property map.
|
||||
if attr in self._olerepr_.propMap:
|
||||
entry = self._olerepr_.propMap[attr]
|
||||
invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)
|
||||
self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
|
||||
return
|
||||
# Check the specific "put" map.
|
||||
if attr in self._olerepr_.propMapPut:
|
||||
entry = self._olerepr_.propMapPut[attr]
|
||||
invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)
|
||||
self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
|
||||
return
|
||||
try:
|
||||
entry = build.MapEntry(self.__AttrToID__(attr),(attr,))
|
||||
except pythoncom.com_error:
|
||||
# No attribute of that name
|
||||
entry = None
|
||||
if entry is not None:
|
||||
try:
|
||||
invoke_type = _GetDescInvokeType(entry, pythoncom.INVOKE_PROPERTYPUT)
|
||||
self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
|
||||
self._olerepr_.propMap[attr] = entry
|
||||
debug_attr_print("__setattr__ property %s (id=0x%x) in Dispatch container %s" % (attr, entry.dispid, self._username_))
|
||||
return
|
||||
except pythoncom.com_error:
|
||||
pass
|
||||
raise AttributeError("Property '%s.%s' can not be set." % (self._username_, attr))
|
692
venv/Lib/site-packages/win32com/client/gencache.py
Normal file
|
@ -0,0 +1,692 @@
|
|||
"""Manages the cache of generated Python code.
|
||||
|
||||
Description
|
||||
This file manages the cache of generated Python code. When run from the
|
||||
command line, it also provides a number of options for managing that cache.
|
||||
|
||||
Implementation
|
||||
Each typelib is generated into a filename of format "{guid}x{lcid}x{major}x{minor}.py"
|
||||
|
||||
An external persistant dictionary maps from all known IIDs in all known type libraries
|
||||
to the type library itself.
|
||||
|
||||
Thus, whenever Python code knows the IID of an object, it can find the IID, LCID and version of
|
||||
the type library which supports it. Given this information, it can find the Python module
|
||||
with the support.
|
||||
|
||||
If necessary, this support can be generated on the fly.
|
||||
|
||||
Hacks, to do, etc
|
||||
Currently just uses a pickled dictionary, but should used some sort of indexed file.
|
||||
Maybe an OLE2 compound file, or a bsddb file?
|
||||
"""
|
||||
import pywintypes, os, sys
|
||||
import pythoncom
|
||||
import win32com, win32com.client
|
||||
import glob
|
||||
import traceback
|
||||
from . import CLSIDToClass
|
||||
import operator
|
||||
try:
|
||||
from imp import reload # exported by the imp module in py3k.
|
||||
except:
|
||||
pass # a builtin on py2k.
|
||||
|
||||
bForDemandDefault = 0 # Default value of bForDemand - toggle this to change the world - see also makepy.py
|
||||
|
||||
# The global dictionary
|
||||
clsidToTypelib = {}
|
||||
|
||||
# If we have a different version of the typelib generated, this
|
||||
# maps the "requested version" to the "generated version".
|
||||
versionRedirectMap = {}
|
||||
|
||||
# There is no reason we *must* be readonly in a .zip, but we are now,
|
||||
# Rather than check for ".zip" or other tricks, PEP302 defines
|
||||
# a "__loader__" attribute, so we use that.
|
||||
# (Later, it may become necessary to check if the __loader__ can update files,
|
||||
# as a .zip loader potentially could - but punt all that until a need arises)
|
||||
is_readonly = is_zip = hasattr(win32com, "__loader__") and hasattr(win32com.__loader__, "archive")
|
||||
|
||||
# A dictionary of ITypeLibrary objects for demand generation explicitly handed to us
|
||||
# Keyed by usual clsid, lcid, major, minor
|
||||
demandGeneratedTypeLibraries = {}
|
||||
|
||||
import pickle as pickle
|
||||
|
||||
def __init__():
|
||||
# Initialize the module. Called once explicitly at module import below.
|
||||
try:
|
||||
_LoadDicts()
|
||||
except IOError:
|
||||
Rebuild()
|
||||
|
||||
pickleVersion = 1
|
||||
def _SaveDicts():
|
||||
if is_readonly:
|
||||
raise RuntimeError("Trying to write to a readonly gencache ('%s')!" \
|
||||
% win32com.__gen_path__)
|
||||
f = open(os.path.join(GetGeneratePath(), "dicts.dat"), "wb")
|
||||
try:
|
||||
p = pickle.Pickler(f)
|
||||
p.dump(pickleVersion)
|
||||
p.dump(clsidToTypelib)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def _LoadDicts():
|
||||
# Load the dictionary from a .zip file if that is where we live.
|
||||
if is_zip:
|
||||
import io as io
|
||||
loader = win32com.__loader__
|
||||
arc_path = loader.archive
|
||||
dicts_path = os.path.join(win32com.__gen_path__, "dicts.dat")
|
||||
if dicts_path.startswith(arc_path):
|
||||
dicts_path = dicts_path[len(arc_path)+1:]
|
||||
else:
|
||||
# Hm. See below.
|
||||
return
|
||||
try:
|
||||
data = loader.get_data(dicts_path)
|
||||
except AttributeError:
|
||||
# The __loader__ has no get_data method. See below.
|
||||
return
|
||||
except IOError:
|
||||
# Our gencache is in a .zip file (and almost certainly readonly)
|
||||
# but no dicts file. That actually needn't be fatal for a frozen
|
||||
# application. Assuming they call "EnsureModule" with the same
|
||||
# typelib IDs they have been frozen with, that EnsureModule will
|
||||
# correctly re-build the dicts on the fly. However, objects that
|
||||
# rely on the gencache but have not done an EnsureModule will
|
||||
# fail (but their apps are likely to fail running from source
|
||||
# with a clean gencache anyway, as then they would be getting
|
||||
# Dynamic objects until the cache is built - so the best answer
|
||||
# for these apps is to call EnsureModule, rather than freezing
|
||||
# the dict)
|
||||
return
|
||||
f = io.BytesIO(data)
|
||||
else:
|
||||
# NOTE: IOError on file open must be caught by caller.
|
||||
f = open(os.path.join(win32com.__gen_path__, "dicts.dat"), "rb")
|
||||
try:
|
||||
p = pickle.Unpickler(f)
|
||||
version = p.load()
|
||||
global clsidToTypelib
|
||||
clsidToTypelib = p.load()
|
||||
versionRedirectMap.clear()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def GetGeneratedFileName(clsid, lcid, major, minor):
|
||||
"""Given the clsid, lcid, major and minor for a type lib, return
|
||||
the file name (no extension) providing this support.
|
||||
"""
|
||||
return str(clsid).upper()[1:-1] + "x%sx%sx%s" % (lcid, major, minor)
|
||||
|
||||
def SplitGeneratedFileName(fname):
|
||||
"""Reverse of GetGeneratedFileName()
|
||||
"""
|
||||
return tuple(fname.split('x',4))
|
||||
|
||||
def GetGeneratePath():
|
||||
"""Returns the name of the path to generate to.
|
||||
Checks the directory is OK.
|
||||
"""
|
||||
assert not is_readonly, "Why do you want the genpath for a readonly store?"
|
||||
try:
|
||||
os.makedirs(win32com.__gen_path__)
|
||||
#os.mkdir(win32com.__gen_path__)
|
||||
except os.error:
|
||||
pass
|
||||
try:
|
||||
fname = os.path.join(win32com.__gen_path__, "__init__.py")
|
||||
os.stat(fname)
|
||||
except os.error:
|
||||
f = open(fname,"w")
|
||||
f.write('# Generated file - this directory may be deleted to reset the COM cache...\n')
|
||||
f.write('import win32com\n')
|
||||
f.write('if __path__[:-1] != win32com.__gen_path__: __path__.append(win32com.__gen_path__)\n')
|
||||
f.close()
|
||||
|
||||
return win32com.__gen_path__
|
||||
|
||||
#
|
||||
# The helpers for win32com.client.Dispatch and OCX clients.
|
||||
#
|
||||
def GetClassForProgID(progid):
|
||||
"""Get a Python class for a Program ID
|
||||
|
||||
Given a Program ID, return a Python class which wraps the COM object
|
||||
|
||||
Returns the Python class, or None if no module is available.
|
||||
|
||||
Params
|
||||
progid -- A COM ProgramID or IID (eg, "Word.Application")
|
||||
"""
|
||||
clsid = pywintypes.IID(progid) # This auto-converts named to IDs.
|
||||
return GetClassForCLSID(clsid)
|
||||
|
||||
def GetClassForCLSID(clsid):
|
||||
"""Get a Python class for a CLSID
|
||||
|
||||
Given a CLSID, return a Python class which wraps the COM object
|
||||
|
||||
Returns the Python class, or None if no module is available.
|
||||
|
||||
Params
|
||||
clsid -- A COM CLSID (or string repr of one)
|
||||
"""
|
||||
# first, take a short-cut - we may already have generated support ready-to-roll.
|
||||
clsid = str(clsid)
|
||||
if CLSIDToClass.HasClass(clsid):
|
||||
return CLSIDToClass.GetClass(clsid)
|
||||
mod = GetModuleForCLSID(clsid)
|
||||
if mod is None:
|
||||
return None
|
||||
try:
|
||||
return CLSIDToClass.GetClass(clsid)
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def GetModuleForProgID(progid):
|
||||
"""Get a Python module for a Program ID
|
||||
|
||||
Given a Program ID, return a Python module which contains the
|
||||
class which wraps the COM object.
|
||||
|
||||
Returns the Python module, or None if no module is available.
|
||||
|
||||
Params
|
||||
progid -- A COM ProgramID or IID (eg, "Word.Application")
|
||||
"""
|
||||
try:
|
||||
iid = pywintypes.IID(progid)
|
||||
except pywintypes.com_error:
|
||||
return None
|
||||
return GetModuleForCLSID(iid)
|
||||
|
||||
def GetModuleForCLSID(clsid):
|
||||
"""Get a Python module for a CLSID
|
||||
|
||||
Given a CLSID, return a Python module which contains the
|
||||
class which wraps the COM object.
|
||||
|
||||
Returns the Python module, or None if no module is available.
|
||||
|
||||
Params
|
||||
progid -- A COM CLSID (ie, not the description)
|
||||
"""
|
||||
clsid_str = str(clsid)
|
||||
try:
|
||||
typelibCLSID, lcid, major, minor = clsidToTypelib[clsid_str]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
try:
|
||||
mod = GetModuleForTypelib(typelibCLSID, lcid, major, minor)
|
||||
except ImportError:
|
||||
mod = None
|
||||
if mod is not None:
|
||||
sub_mod = mod.CLSIDToPackageMap.get(clsid_str)
|
||||
if sub_mod is None:
|
||||
sub_mod = mod.VTablesToPackageMap.get(clsid_str)
|
||||
if sub_mod is not None:
|
||||
sub_mod_name = mod.__name__ + "." + sub_mod
|
||||
try:
|
||||
__import__(sub_mod_name)
|
||||
except ImportError:
|
||||
info = typelibCLSID, lcid, major, minor
|
||||
# Force the generation. If this typelibrary has explicitly been added,
|
||||
# use it (it may not be registered, causing a lookup by clsid to fail)
|
||||
if info in demandGeneratedTypeLibraries:
|
||||
info = demandGeneratedTypeLibraries[info]
|
||||
from . import makepy
|
||||
makepy.GenerateChildFromTypeLibSpec(sub_mod, info)
|
||||
# Generate does an import...
|
||||
mod = sys.modules[sub_mod_name]
|
||||
return mod
|
||||
|
||||
def GetModuleForTypelib(typelibCLSID, lcid, major, minor):
|
||||
"""Get a Python module for a type library ID
|
||||
|
||||
Given the CLSID of a typelibrary, return an imported Python module,
|
||||
else None
|
||||
|
||||
Params
|
||||
typelibCLSID -- IID of the type library.
|
||||
major -- Integer major version.
|
||||
minor -- Integer minor version
|
||||
lcid -- Integer LCID for the library.
|
||||
"""
|
||||
modName = GetGeneratedFileName(typelibCLSID, lcid, major, minor)
|
||||
mod = _GetModule(modName)
|
||||
# If the import worked, it doesn't mean we have actually added this
|
||||
# module to our cache though - check that here.
|
||||
if "_in_gencache_" not in mod.__dict__:
|
||||
AddModuleToCache(typelibCLSID, lcid, major, minor)
|
||||
assert "_in_gencache_" in mod.__dict__
|
||||
return mod
|
||||
|
||||
def MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance = None, bForDemand = bForDemandDefault, bBuildHidden = 1):
|
||||
"""Generate support for a type library.
|
||||
|
||||
Given the IID, LCID and version information for a type library, generate
|
||||
and import the necessary support files.
|
||||
|
||||
Returns the Python module. No exceptions are caught.
|
||||
|
||||
Params
|
||||
typelibCLSID -- IID of the type library.
|
||||
major -- Integer major version.
|
||||
minor -- Integer minor version.
|
||||
lcid -- Integer LCID for the library.
|
||||
progressInstance -- Instance to use as progress indicator, or None to
|
||||
use the GUI progress bar.
|
||||
"""
|
||||
from . import makepy
|
||||
makepy.GenerateFromTypeLibSpec( (typelibCLSID, lcid, major, minor), progressInstance=progressInstance, bForDemand = bForDemand, bBuildHidden = bBuildHidden)
|
||||
return GetModuleForTypelib(typelibCLSID, lcid, major, minor)
|
||||
|
||||
def MakeModuleForTypelibInterface(typelib_ob, progressInstance = None, bForDemand = bForDemandDefault, bBuildHidden = 1):
|
||||
"""Generate support for a type library.
|
||||
|
||||
Given a PyITypeLib interface generate and import the necessary support files. This is useful
|
||||
for getting makepy support for a typelibrary that is not registered - the caller can locate
|
||||
and load the type library itself, rather than relying on COM to find it.
|
||||
|
||||
Returns the Python module.
|
||||
|
||||
Params
|
||||
typelib_ob -- The type library itself
|
||||
progressInstance -- Instance to use as progress indicator, or None to
|
||||
use the GUI progress bar.
|
||||
"""
|
||||
from . import makepy
|
||||
try:
|
||||
makepy.GenerateFromTypeLibSpec( typelib_ob, progressInstance=progressInstance, bForDemand = bForDemandDefault, bBuildHidden = bBuildHidden)
|
||||
except pywintypes.com_error:
|
||||
return None
|
||||
tla = typelib_ob.GetLibAttr()
|
||||
guid = tla[0]
|
||||
lcid = tla[1]
|
||||
major = tla[3]
|
||||
minor = tla[4]
|
||||
return GetModuleForTypelib(guid, lcid, major, minor)
|
||||
|
||||
def EnsureModuleForTypelibInterface(typelib_ob, progressInstance = None, bForDemand = bForDemandDefault, bBuildHidden = 1):
|
||||
"""Check we have support for a type library, generating if not.
|
||||
|
||||
Given a PyITypeLib interface generate and import the necessary
|
||||
support files if necessary. This is useful for getting makepy support
|
||||
for a typelibrary that is not registered - the caller can locate and
|
||||
load the type library itself, rather than relying on COM to find it.
|
||||
|
||||
Returns the Python module.
|
||||
|
||||
Params
|
||||
typelib_ob -- The type library itself
|
||||
progressInstance -- Instance to use as progress indicator, or None to
|
||||
use the GUI progress bar.
|
||||
"""
|
||||
tla = typelib_ob.GetLibAttr()
|
||||
guid = tla[0]
|
||||
lcid = tla[1]
|
||||
major = tla[3]
|
||||
minor = tla[4]
|
||||
|
||||
#If demand generated, save the typelib interface away for later use
|
||||
if bForDemand:
|
||||
demandGeneratedTypeLibraries[(str(guid), lcid, major, minor)] = typelib_ob
|
||||
|
||||
try:
|
||||
return GetModuleForTypelib(guid, lcid, major, minor)
|
||||
except ImportError:
|
||||
pass
|
||||
# Generate it.
|
||||
return MakeModuleForTypelibInterface(typelib_ob, progressInstance, bForDemand, bBuildHidden)
|
||||
|
||||
def ForgetAboutTypelibInterface(typelib_ob):
|
||||
"""Drop any references to a typelib previously added with EnsureModuleForTypelibInterface and forDemand"""
|
||||
tla = typelib_ob.GetLibAttr()
|
||||
guid = tla[0]
|
||||
lcid = tla[1]
|
||||
major = tla[3]
|
||||
minor = tla[4]
|
||||
info = str(guid), lcid, major, minor
|
||||
try:
|
||||
del demandGeneratedTypeLibraries[info]
|
||||
except KeyError:
|
||||
# Not worth raising an exception - maybe they dont know we only remember for demand generated, etc.
|
||||
print("ForgetAboutTypelibInterface:: Warning - type library with info %s is not being remembered!" % (info,))
|
||||
# and drop any version redirects to it
|
||||
for key, val in list(versionRedirectMap.items()):
|
||||
if val==info:
|
||||
del versionRedirectMap[key]
|
||||
|
||||
def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance = None, bValidateFile=not is_readonly, bForDemand = bForDemandDefault, bBuildHidden = 1):
|
||||
"""Ensure Python support is loaded for a type library, generating if necessary.
|
||||
|
||||
Given the IID, LCID and version information for a type library, check and if
|
||||
necessary (re)generate, then import the necessary support files. If we regenerate the file, there
|
||||
is no way to totally snuff out all instances of the old module in Python, and thus we will regenerate the file more than necessary,
|
||||
unless makepy/genpy is modified accordingly.
|
||||
|
||||
|
||||
Returns the Python module. No exceptions are caught during the generate process.
|
||||
|
||||
Params
|
||||
typelibCLSID -- IID of the type library.
|
||||
major -- Integer major version.
|
||||
minor -- Integer minor version
|
||||
lcid -- Integer LCID for the library.
|
||||
progressInstance -- Instance to use as progress indicator, or None to
|
||||
use the GUI progress bar.
|
||||
bValidateFile -- Whether or not to perform cache validation or not
|
||||
bForDemand -- Should a complete generation happen now, or on demand?
|
||||
bBuildHidden -- Should hidden members/attributes etc be generated?
|
||||
"""
|
||||
bReloadNeeded = 0
|
||||
try:
|
||||
try:
|
||||
module = GetModuleForTypelib(typelibCLSID, lcid, major, minor)
|
||||
except ImportError:
|
||||
# If we get an ImportError
|
||||
# We may still find a valid cache file under a different MinorVersion #
|
||||
# (which windows will search out for us)
|
||||
#print "Loading reg typelib", typelibCLSID, major, minor, lcid
|
||||
module = None
|
||||
try:
|
||||
tlbAttr = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr()
|
||||
# if the above line doesn't throw a pythoncom.com_error, check if
|
||||
# it is actually a different lib than we requested, and if so, suck it in
|
||||
if tlbAttr[1] != lcid or tlbAttr[4]!=minor:
|
||||
#print "Trying 2nd minor #", tlbAttr[1], tlbAttr[3], tlbAttr[4]
|
||||
try:
|
||||
module = GetModuleForTypelib(typelibCLSID, tlbAttr[1], tlbAttr[3], tlbAttr[4])
|
||||
except ImportError:
|
||||
# We don't have a module, but we do have a better minor
|
||||
# version - remember that.
|
||||
minor = tlbAttr[4]
|
||||
# else module remains None
|
||||
except pythoncom.com_error:
|
||||
# couldn't load any typelib - mod remains None
|
||||
pass
|
||||
if module is not None and bValidateFile:
|
||||
assert not is_readonly, "Can't validate in a read-only gencache"
|
||||
try:
|
||||
typLibPath = pythoncom.QueryPathOfRegTypeLib(typelibCLSID, major, minor, lcid)
|
||||
# windows seems to add an extra \0 (via the underlying BSTR)
|
||||
# The mainwin toolkit does not add this erroneous \0
|
||||
if typLibPath[-1]=='\0':
|
||||
typLibPath=typLibPath[:-1]
|
||||
suf = getattr(os.path, "supports_unicode_filenames", 0)
|
||||
if not suf:
|
||||
# can't pass unicode filenames directly - convert
|
||||
try:
|
||||
typLibPath=typLibPath.encode(sys.getfilesystemencoding())
|
||||
except AttributeError: # no sys.getfilesystemencoding
|
||||
typLibPath=str(typLibPath)
|
||||
tlbAttributes = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid).GetLibAttr()
|
||||
except pythoncom.com_error:
|
||||
# We have a module, but no type lib - we should still
|
||||
# run with what we have though - the typelib may not be
|
||||
# deployed here.
|
||||
bValidateFile = 0
|
||||
if module is not None and bValidateFile:
|
||||
assert not is_readonly, "Can't validate in a read-only gencache"
|
||||
filePathPrefix = "%s\\%s" % (GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor))
|
||||
filePath = filePathPrefix + ".py"
|
||||
filePathPyc = filePathPrefix + ".py"
|
||||
if __debug__:
|
||||
filePathPyc = filePathPyc + "c"
|
||||
else:
|
||||
filePathPyc = filePathPyc + "o"
|
||||
# Verify that type library is up to date.
|
||||
# If we have a differing MinorVersion or genpy has bumped versions, update the file
|
||||
from . import genpy
|
||||
if module.MinorVersion != tlbAttributes[4] or genpy.makepy_version != module.makepy_version:
|
||||
#print "Version skew: %d, %d" % (module.MinorVersion, tlbAttributes[4])
|
||||
# try to erase the bad file from the cache
|
||||
try:
|
||||
os.unlink(filePath)
|
||||
except os.error:
|
||||
pass
|
||||
try:
|
||||
os.unlink(filePathPyc)
|
||||
except os.error:
|
||||
pass
|
||||
if os.path.isdir(filePathPrefix):
|
||||
import shutil
|
||||
shutil.rmtree(filePathPrefix)
|
||||
minor = tlbAttributes[4]
|
||||
module = None
|
||||
bReloadNeeded = 1
|
||||
else:
|
||||
minor = module.MinorVersion
|
||||
filePathPrefix = "%s\\%s" % (GetGeneratePath(), GetGeneratedFileName(typelibCLSID, lcid, major, minor))
|
||||
filePath = filePathPrefix + ".py"
|
||||
filePathPyc = filePathPrefix + ".pyc"
|
||||
#print "Trying py stat: ", filePath
|
||||
fModTimeSet = 0
|
||||
try:
|
||||
pyModTime = os.stat(filePath)[8]
|
||||
fModTimeSet = 1
|
||||
except os.error as e:
|
||||
# If .py file fails, try .pyc file
|
||||
#print "Trying pyc stat", filePathPyc
|
||||
try:
|
||||
pyModTime = os.stat(filePathPyc)[8]
|
||||
fModTimeSet = 1
|
||||
except os.error as e:
|
||||
pass
|
||||
#print "Trying stat typelib", pyModTime
|
||||
#print str(typLibPath)
|
||||
typLibModTime = os.stat(typLibPath)[8]
|
||||
if fModTimeSet and (typLibModTime > pyModTime):
|
||||
bReloadNeeded = 1
|
||||
module = None
|
||||
except (ImportError, os.error):
|
||||
module = None
|
||||
if module is None:
|
||||
# We need to build an item. If we are in a read-only cache, we
|
||||
# can't/don't want to do this - so before giving up, check for
|
||||
# a different minor version in our cache - according to COM, this is OK
|
||||
if is_readonly:
|
||||
key = str(typelibCLSID), lcid, major, minor
|
||||
# If we have been asked before, get last result.
|
||||
try:
|
||||
return versionRedirectMap[key]
|
||||
except KeyError:
|
||||
pass
|
||||
# Find other candidates.
|
||||
items = []
|
||||
for desc in GetGeneratedInfos():
|
||||
if key[0]==desc[0] and key[1]==desc[1] and key[2]==desc[2]:
|
||||
items.append(desc)
|
||||
if items:
|
||||
# Items are all identical, except for last tuple element
|
||||
# We want the latest minor version we have - so just sort and grab last
|
||||
items.sort()
|
||||
new_minor = items[-1][3]
|
||||
ret = GetModuleForTypelib(typelibCLSID, lcid, major, new_minor)
|
||||
else:
|
||||
ret = None
|
||||
# remember and return
|
||||
versionRedirectMap[key] = ret
|
||||
return ret
|
||||
#print "Rebuilding: ", major, minor
|
||||
module = MakeModuleForTypelib(typelibCLSID, lcid, major, minor, progressInstance, bForDemand = bForDemand, bBuildHidden = bBuildHidden)
|
||||
# If we replaced something, reload it
|
||||
if bReloadNeeded:
|
||||
module = reload(module)
|
||||
AddModuleToCache(typelibCLSID, lcid, major, minor)
|
||||
return module
|
||||
|
||||
def EnsureDispatch(prog_id, bForDemand = 1): # New fn, so we default the new demand feature to on!
|
||||
"""Given a COM prog_id, return an object that is using makepy support, building if necessary"""
|
||||
disp = win32com.client.Dispatch(prog_id)
|
||||
if not disp.__dict__.get("CLSID"): # Eeek - no makepy support - try and build it.
|
||||
try:
|
||||
ti = disp._oleobj_.GetTypeInfo()
|
||||
disp_clsid = ti.GetTypeAttr()[0]
|
||||
tlb, index = ti.GetContainingTypeLib()
|
||||
tla = tlb.GetLibAttr()
|
||||
mod = EnsureModule(tla[0], tla[1], tla[3], tla[4], bForDemand=bForDemand)
|
||||
GetModuleForCLSID(disp_clsid)
|
||||
# Get the class from the module.
|
||||
from . import CLSIDToClass
|
||||
disp_class = CLSIDToClass.GetClass(str(disp_clsid))
|
||||
disp = disp_class(disp._oleobj_)
|
||||
except pythoncom.com_error:
|
||||
raise TypeError("This COM object can not automate the makepy process - please run makepy manually for this object")
|
||||
return disp
|
||||
|
||||
def AddModuleToCache(typelibclsid, lcid, major, minor, verbose = 1, bFlushNow = not is_readonly):
|
||||
"""Add a newly generated file to the cache dictionary.
|
||||
"""
|
||||
fname = GetGeneratedFileName(typelibclsid, lcid, major, minor)
|
||||
mod = _GetModule(fname)
|
||||
# if mod._in_gencache_ is already true, then we are reloading this
|
||||
# module - this doesn't mean anything special though!
|
||||
mod._in_gencache_ = 1
|
||||
dict = mod.CLSIDToClassMap
|
||||
info = str(typelibclsid), lcid, major, minor
|
||||
for clsid, cls in dict.items():
|
||||
clsidToTypelib[clsid] = info
|
||||
|
||||
dict = mod.CLSIDToPackageMap
|
||||
for clsid, name in dict.items():
|
||||
clsidToTypelib[clsid] = info
|
||||
|
||||
dict = mod.VTablesToClassMap
|
||||
for clsid, cls in dict.items():
|
||||
clsidToTypelib[clsid] = info
|
||||
|
||||
dict = mod.VTablesToPackageMap
|
||||
for clsid, cls in dict.items():
|
||||
clsidToTypelib[clsid] = info
|
||||
|
||||
# If this lib was previously redirected, drop it
|
||||
if info in versionRedirectMap:
|
||||
del versionRedirectMap[info]
|
||||
if bFlushNow:
|
||||
_SaveDicts()
|
||||
|
||||
def GetGeneratedInfos():
|
||||
zip_pos = win32com.__gen_path__.find(".zip\\")
|
||||
if zip_pos >= 0:
|
||||
import zipfile
|
||||
zip_file = win32com.__gen_path__[:zip_pos+4]
|
||||
zip_path = win32com.__gen_path__[zip_pos+5:].replace("\\", "/")
|
||||
zf = zipfile.ZipFile(zip_file)
|
||||
infos = {}
|
||||
for n in zf.namelist():
|
||||
if not n.startswith(zip_path):
|
||||
continue
|
||||
base = n[len(zip_path)+1:].split("/")[0]
|
||||
try:
|
||||
iid, lcid, major, minor = base.split("x")
|
||||
lcid = int(lcid)
|
||||
major = int(major)
|
||||
minor = int(minor)
|
||||
iid = pywintypes.IID("{" + iid + "}")
|
||||
except ValueError:
|
||||
continue
|
||||
except pywintypes.com_error:
|
||||
# invalid IID
|
||||
continue
|
||||
infos[(iid, lcid, major, minor)] = 1
|
||||
zf.close()
|
||||
return list(infos.keys())
|
||||
else:
|
||||
# on the file system
|
||||
files = glob.glob(win32com.__gen_path__+ "\\*")
|
||||
ret = []
|
||||
for file in files:
|
||||
if not os.path.isdir(file) and not os.path.splitext(file)[1]==".py":
|
||||
continue
|
||||
name = os.path.splitext(os.path.split(file)[1])[0]
|
||||
try:
|
||||
iid, lcid, major, minor = name.split("x")
|
||||
iid = pywintypes.IID("{" + iid + "}")
|
||||
lcid = int(lcid)
|
||||
major = int(major)
|
||||
minor = int(minor)
|
||||
except ValueError:
|
||||
continue
|
||||
except pywintypes.com_error:
|
||||
# invalid IID
|
||||
continue
|
||||
ret.append((iid, lcid, major, minor))
|
||||
return ret
|
||||
|
||||
def _GetModule(fname):
|
||||
"""Given the name of a module in the gen_py directory, import and return it.
|
||||
"""
|
||||
mod_name = "win32com.gen_py.%s" % fname
|
||||
mod = __import__(mod_name)
|
||||
return sys.modules[mod_name]
|
||||
|
||||
def Rebuild(verbose = 1):
|
||||
"""Rebuild the cache indexes from the file system.
|
||||
"""
|
||||
clsidToTypelib.clear()
|
||||
infos = GetGeneratedInfos()
|
||||
if verbose and len(infos): # Dont bother reporting this when directory is empty!
|
||||
print("Rebuilding cache of generated files for COM support...")
|
||||
for info in infos:
|
||||
iid, lcid, major, minor = info
|
||||
if verbose:
|
||||
print("Checking", GetGeneratedFileName(*info))
|
||||
try:
|
||||
AddModuleToCache(iid, lcid, major, minor, verbose, 0)
|
||||
except:
|
||||
print("Could not add module %s - %s: %s" % (info, sys.exc_info()[0],sys.exc_info()[1]))
|
||||
if verbose and len(infos): # Dont bother reporting this when directory is empty!
|
||||
print("Done.")
|
||||
_SaveDicts()
|
||||
|
||||
def _Dump():
|
||||
print("Cache is in directory", win32com.__gen_path__)
|
||||
# Build a unique dir
|
||||
d = {}
|
||||
for clsid, (typelibCLSID, lcid, major, minor) in clsidToTypelib.items():
|
||||
d[typelibCLSID, lcid, major, minor] = None
|
||||
for typelibCLSID, lcid, major, minor in d.keys():
|
||||
mod = GetModuleForTypelib(typelibCLSID, lcid, major, minor)
|
||||
print("%s - %s" % (mod.__doc__, typelibCLSID))
|
||||
|
||||
# Boot up
|
||||
__init__()
|
||||
|
||||
def usage():
|
||||
usageString = """\
|
||||
Usage: gencache [-q] [-d] [-r]
|
||||
|
||||
-q - Quiet
|
||||
-d - Dump the cache (typelibrary description and filename).
|
||||
-r - Rebuild the cache dictionary from the existing .py files
|
||||
"""
|
||||
print(usageString)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__=='__main__':
|
||||
import getopt
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "qrd")
|
||||
except getopt.error as message:
|
||||
print(message)
|
||||
usage()
|
||||
|
||||
# we only have options - complain about real args, or none at all!
|
||||
if len(sys.argv)==1 or args:
|
||||
print(usage())
|
||||
|
||||
verbose = 1
|
||||
for opt, val in opts:
|
||||
if opt=='-d': # Dump
|
||||
_Dump()
|
||||
if opt=='-r':
|
||||
Rebuild(verbose)
|
||||
if opt=='-q':
|
||||
verbose = 0
|
1074
venv/Lib/site-packages/win32com/client/genpy.py
Normal file
390
venv/Lib/site-packages/win32com/client/makepy.py
Normal file
|
@ -0,0 +1,390 @@
|
|||
# Originally written by Curt Hagenlocher, and various bits
|
||||
# and pieces by Mark Hammond (and now Greg Stein has had
|
||||
# a go too :-)
|
||||
|
||||
# Note that the main worker code has been moved to genpy.py
|
||||
# As this is normally run from the command line, it reparses the code each time.
|
||||
# Now this is nothing more than the command line handler and public interface.
|
||||
|
||||
# XXX - TO DO
|
||||
# XXX - Greg and Mark have some ideas for a revamp - just no
|
||||
# time - if you want to help, contact us for details.
|
||||
# Main idea is to drop the classes exported and move to a more
|
||||
# traditional data driven model.
|
||||
|
||||
"""Generate a .py file from an OLE TypeLibrary file.
|
||||
|
||||
|
||||
This module is concerned only with the actual writing of
|
||||
a .py file. It draws on the @build@ module, which builds
|
||||
the knowledge of a COM interface.
|
||||
|
||||
"""
|
||||
usageHelp = """ \
|
||||
|
||||
Usage:
|
||||
|
||||
makepy.py [-i] [-v|q] [-h] [-u] [-o output_file] [-d] [typelib, ...]
|
||||
|
||||
-i -- Show information for the specified typelib.
|
||||
|
||||
-v -- Verbose output.
|
||||
|
||||
-q -- Quiet output.
|
||||
|
||||
-h -- Do not generate hidden methods.
|
||||
|
||||
-u -- Python 1.5 and earlier: Do NOT convert all Unicode objects to
|
||||
strings.
|
||||
|
||||
Python 1.6 and later: Convert all Unicode objects to strings.
|
||||
|
||||
-o -- Create output in a specified output file. If the path leading
|
||||
to the file does not exist, any missing directories will be
|
||||
created.
|
||||
NOTE: -o cannot be used with -d. This will generate an error.
|
||||
|
||||
-d -- Generate the base code now and the class code on demand.
|
||||
Recommended for large type libraries.
|
||||
|
||||
typelib -- A TLB, DLL, OCX or anything containing COM type information.
|
||||
If a typelib is not specified, a window containing a textbox
|
||||
will open from which you can select a registered type
|
||||
library.
|
||||
|
||||
Examples:
|
||||
|
||||
makepy.py -d
|
||||
|
||||
Presents a list of registered type libraries from which you can make
|
||||
a selection.
|
||||
|
||||
makepy.py -d "Microsoft Excel 8.0 Object Library"
|
||||
|
||||
Generate support for the type library with the specified description
|
||||
(in this case, the MS Excel object model).
|
||||
|
||||
"""
|
||||
|
||||
import sys, os, pythoncom
|
||||
from win32com.client import genpy, selecttlb, gencache
|
||||
from win32com.client import Dispatch
|
||||
|
||||
bForDemandDefault = 0 # Default value of bForDemand - toggle this to change the world - see also gencache.py
|
||||
|
||||
error = "makepy.error"
|
||||
|
||||
def usage():
|
||||
sys.stderr.write (usageHelp)
|
||||
sys.exit(2)
|
||||
|
||||
def ShowInfo(spec):
|
||||
if not spec:
|
||||
tlbSpec = selecttlb.SelectTlb(excludeFlags=selecttlb.FLAG_HIDDEN)
|
||||
if tlbSpec is None:
|
||||
return
|
||||
try:
|
||||
tlb = pythoncom.LoadRegTypeLib(tlbSpec.clsid, tlbSpec.major, tlbSpec.minor, tlbSpec.lcid)
|
||||
except pythoncom.com_error: # May be badly registered.
|
||||
sys.stderr.write("Warning - could not load registered typelib '%s'\n" % (tlbSpec.clsid))
|
||||
tlb = None
|
||||
|
||||
infos = [(tlb, tlbSpec)]
|
||||
else:
|
||||
infos = GetTypeLibsForSpec(spec)
|
||||
for (tlb, tlbSpec) in infos:
|
||||
desc = tlbSpec.desc
|
||||
if desc is None:
|
||||
if tlb is None:
|
||||
desc = "<Could not load typelib %s>" % (tlbSpec.dll)
|
||||
else:
|
||||
desc = tlb.GetDocumentation(-1)[0]
|
||||
print(desc)
|
||||
print(" %s, lcid=%s, major=%s, minor=%s" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor))
|
||||
print(" >>> # Use these commands in Python code to auto generate .py support")
|
||||
print(" >>> from win32com.client import gencache")
|
||||
print(" >>> gencache.EnsureModule('%s', %s, %s, %s)" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor))
|
||||
|
||||
class SimpleProgress(genpy.GeneratorProgress):
|
||||
"""A simple progress class prints its output to stderr
|
||||
"""
|
||||
def __init__(self, verboseLevel):
|
||||
self.verboseLevel = verboseLevel
|
||||
def Close(self):
|
||||
pass
|
||||
def Finished(self):
|
||||
if self.verboseLevel>1:
|
||||
sys.stderr.write("Generation complete..\n")
|
||||
def SetDescription(self, desc, maxticks = None):
|
||||
if self.verboseLevel:
|
||||
sys.stderr.write(desc + "\n")
|
||||
def Tick(self, desc = None):
|
||||
pass
|
||||
|
||||
def VerboseProgress(self, desc, verboseLevel = 2):
|
||||
if self.verboseLevel >= verboseLevel:
|
||||
sys.stderr.write(desc + "\n")
|
||||
|
||||
def LogBeginGenerate(self, filename):
|
||||
self.VerboseProgress("Generating to %s" % filename, 1)
|
||||
|
||||
def LogWarning(self, desc):
|
||||
self.VerboseProgress("WARNING: " + desc, 1)
|
||||
|
||||
class GUIProgress(SimpleProgress):
|
||||
def __init__(self, verboseLevel):
|
||||
# Import some modules we need to we can trap failure now.
|
||||
import win32ui, pywin
|
||||
SimpleProgress.__init__(self, verboseLevel)
|
||||
self.dialog = None
|
||||
|
||||
def Close(self):
|
||||
if self.dialog is not None:
|
||||
self.dialog.Close()
|
||||
self.dialog = None
|
||||
|
||||
def Starting(self, tlb_desc):
|
||||
SimpleProgress.Starting(self, tlb_desc)
|
||||
if self.dialog is None:
|
||||
from pywin.dialogs import status
|
||||
self.dialog=status.ThreadedStatusProgressDialog(tlb_desc)
|
||||
else:
|
||||
self.dialog.SetTitle(tlb_desc)
|
||||
|
||||
def SetDescription(self, desc, maxticks = None):
|
||||
self.dialog.SetText(desc)
|
||||
if maxticks:
|
||||
self.dialog.SetMaxTicks(maxticks)
|
||||
|
||||
def Tick(self, desc = None):
|
||||
self.dialog.Tick()
|
||||
if desc is not None:
|
||||
self.dialog.SetText(desc)
|
||||
|
||||
def GetTypeLibsForSpec(arg):
|
||||
"""Given an argument on the command line (either a file name, library
|
||||
description, or ProgID of an object) return a list of actual typelibs
|
||||
to use. """
|
||||
typelibs = []
|
||||
try:
|
||||
try:
|
||||
tlb = pythoncom.LoadTypeLib(arg)
|
||||
spec = selecttlb.TypelibSpec(None, 0,0,0)
|
||||
spec.FromTypelib(tlb, arg)
|
||||
typelibs.append((tlb, spec))
|
||||
except pythoncom.com_error:
|
||||
# See if it is a description
|
||||
tlbs = selecttlb.FindTlbsWithDescription(arg)
|
||||
if len(tlbs)==0:
|
||||
# Maybe it is the name of a COM object?
|
||||
try:
|
||||
ob = Dispatch(arg)
|
||||
# and if so, it must support typelib info
|
||||
tlb, index = ob._oleobj_.GetTypeInfo().GetContainingTypeLib()
|
||||
spec = selecttlb.TypelibSpec(None, 0,0,0)
|
||||
spec.FromTypelib(tlb)
|
||||
tlbs.append(spec)
|
||||
except pythoncom.com_error:
|
||||
pass
|
||||
if len(tlbs)==0:
|
||||
print("Could not locate a type library matching '%s'" % (arg))
|
||||
for spec in tlbs:
|
||||
# Version numbers not always reliable if enumerated from registry.
|
||||
# (as some libs use hex, other's dont. Both examples from MS, of course.)
|
||||
if spec.dll is None:
|
||||
tlb = pythoncom.LoadRegTypeLib(spec.clsid, spec.major, spec.minor, spec.lcid)
|
||||
else:
|
||||
tlb = pythoncom.LoadTypeLib(spec.dll)
|
||||
|
||||
# We have a typelib, but it may not be exactly what we specified
|
||||
# (due to automatic version matching of COM). So we query what we really have!
|
||||
attr = tlb.GetLibAttr()
|
||||
spec.major = attr[3]
|
||||
spec.minor = attr[4]
|
||||
spec.lcid = attr[1]
|
||||
typelibs.append((tlb, spec))
|
||||
return typelibs
|
||||
except pythoncom.com_error:
|
||||
t,v,tb=sys.exc_info()
|
||||
sys.stderr.write ("Unable to load type library from '%s' - %s\n" % (arg, v))
|
||||
tb = None # Storing tb in a local is a cycle!
|
||||
sys.exit(1)
|
||||
|
||||
def GenerateFromTypeLibSpec(typelibInfo, file = None, verboseLevel = None, progressInstance = None, bUnicodeToString=None, bForDemand = bForDemandDefault, bBuildHidden = 1):
|
||||
assert bUnicodeToString is None, "this is deprecated and will go away"
|
||||
if verboseLevel is None:
|
||||
verboseLevel = 0 # By default, we use no gui and no verbose level!
|
||||
|
||||
if bForDemand and file is not None:
|
||||
raise RuntimeError("You can only perform a demand-build when the output goes to the gen_py directory")
|
||||
if isinstance(typelibInfo, tuple):
|
||||
# Tuple
|
||||
typelibCLSID, lcid, major, minor = typelibInfo
|
||||
tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid)
|
||||
spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor)
|
||||
spec.FromTypelib(tlb, str(typelibCLSID))
|
||||
typelibs = [(tlb, spec)]
|
||||
elif isinstance(typelibInfo, selecttlb.TypelibSpec):
|
||||
if typelibInfo.dll is None:
|
||||
# Version numbers not always reliable if enumerated from registry.
|
||||
tlb = pythoncom.LoadRegTypeLib(typelibInfo.clsid, typelibInfo.major, typelibInfo.minor, typelibInfo.lcid)
|
||||
else:
|
||||
tlb = pythoncom.LoadTypeLib(typelibInfo.dll)
|
||||
typelibs = [(tlb, typelibInfo)]
|
||||
elif hasattr(typelibInfo, "GetLibAttr"):
|
||||
# A real typelib object!
|
||||
# Could also use isinstance(typelibInfo, PyITypeLib) instead, but PyITypeLib is not directly exposed by pythoncom.
|
||||
# pythoncom.TypeIIDs[pythoncom.IID_ITypeLib] seems to work
|
||||
tla = typelibInfo.GetLibAttr()
|
||||
guid = tla[0]
|
||||
lcid = tla[1]
|
||||
major = tla[3]
|
||||
minor = tla[4]
|
||||
spec = selecttlb.TypelibSpec(guid, lcid, major, minor)
|
||||
typelibs = [(typelibInfo, spec)]
|
||||
else:
|
||||
typelibs = GetTypeLibsForSpec(typelibInfo)
|
||||
|
||||
if progressInstance is None:
|
||||
progressInstance = SimpleProgress(verboseLevel)
|
||||
progress = progressInstance
|
||||
|
||||
bToGenDir = (file is None)
|
||||
|
||||
for typelib, info in typelibs:
|
||||
gen = genpy.Generator(typelib, info.dll, progress, bBuildHidden=bBuildHidden)
|
||||
|
||||
if file is None:
|
||||
this_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor)
|
||||
full_name = os.path.join(gencache.GetGeneratePath(), this_name)
|
||||
if bForDemand:
|
||||
try: os.unlink(full_name + ".py")
|
||||
except os.error: pass
|
||||
try: os.unlink(full_name + ".pyc")
|
||||
except os.error: pass
|
||||
try: os.unlink(full_name + ".pyo")
|
||||
except os.error: pass
|
||||
if not os.path.isdir(full_name):
|
||||
os.mkdir(full_name)
|
||||
outputName = os.path.join(full_name, "__init__.py")
|
||||
else:
|
||||
outputName = full_name + ".py"
|
||||
fileUse = gen.open_writer(outputName)
|
||||
progress.LogBeginGenerate(outputName)
|
||||
else:
|
||||
fileUse = file
|
||||
|
||||
worked = False
|
||||
try:
|
||||
gen.generate(fileUse, bForDemand)
|
||||
worked = True
|
||||
finally:
|
||||
if file is None:
|
||||
gen.finish_writer(outputName, fileUse, worked)
|
||||
if bToGenDir:
|
||||
progress.SetDescription("Importing module")
|
||||
gencache.AddModuleToCache(info.clsid, info.lcid, info.major, info.minor)
|
||||
|
||||
progress.Close()
|
||||
|
||||
def GenerateChildFromTypeLibSpec(child, typelibInfo, verboseLevel = None, progressInstance = None, bUnicodeToString=None):
|
||||
assert bUnicodeToString is None, "this is deprecated and will go away"
|
||||
if verboseLevel is None:
|
||||
verboseLevel = 0 # By default, we use no gui, and no verbose level for the children.
|
||||
if type(typelibInfo)==type(()):
|
||||
typelibCLSID, lcid, major, minor = typelibInfo
|
||||
tlb = pythoncom.LoadRegTypeLib(typelibCLSID, major, minor, lcid)
|
||||
else:
|
||||
tlb = typelibInfo
|
||||
tla = typelibInfo.GetLibAttr()
|
||||
typelibCLSID = tla[0]
|
||||
lcid = tla[1]
|
||||
major = tla[3]
|
||||
minor = tla[4]
|
||||
spec = selecttlb.TypelibSpec(typelibCLSID, lcid, major, minor)
|
||||
spec.FromTypelib(tlb, str(typelibCLSID))
|
||||
typelibs = [(tlb, spec)]
|
||||
|
||||
if progressInstance is None:
|
||||
progressInstance = SimpleProgress(verboseLevel)
|
||||
progress = progressInstance
|
||||
|
||||
for typelib, info in typelibs:
|
||||
dir_name = gencache.GetGeneratedFileName(info.clsid, info.lcid, info.major, info.minor)
|
||||
dir_path_name = os.path.join(gencache.GetGeneratePath(), dir_name)
|
||||
progress.LogBeginGenerate(dir_path_name)
|
||||
|
||||
gen = genpy.Generator(typelib, info.dll, progress)
|
||||
gen.generate_child(child, dir_path_name)
|
||||
progress.SetDescription("Importing module")
|
||||
__import__("win32com.gen_py." + dir_name + "." + child)
|
||||
progress.Close()
|
||||
|
||||
def main():
|
||||
import getopt
|
||||
hiddenSpec = 1
|
||||
outputName = None
|
||||
verboseLevel = 1
|
||||
doit = 1
|
||||
bForDemand = bForDemandDefault
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'vo:huiqd')
|
||||
for o,v in opts:
|
||||
if o=='-h':
|
||||
hiddenSpec = 0
|
||||
elif o=='-o':
|
||||
outputName = v
|
||||
elif o=='-v':
|
||||
verboseLevel = verboseLevel + 1
|
||||
elif o=='-q':
|
||||
verboseLevel = verboseLevel - 1
|
||||
elif o=='-i':
|
||||
if len(args)==0:
|
||||
ShowInfo(None)
|
||||
else:
|
||||
for arg in args:
|
||||
ShowInfo(arg)
|
||||
doit = 0
|
||||
elif o=='-d':
|
||||
bForDemand = not bForDemand
|
||||
|
||||
except (getopt.error, error) as msg:
|
||||
sys.stderr.write (str(msg) + "\n")
|
||||
usage()
|
||||
|
||||
if bForDemand and outputName is not None:
|
||||
sys.stderr.write("Can not use -d and -o together\n")
|
||||
usage()
|
||||
|
||||
if not doit:
|
||||
return 0
|
||||
if len(args)==0:
|
||||
rc = selecttlb.SelectTlb()
|
||||
if rc is None:
|
||||
sys.exit(1)
|
||||
args = [ rc ]
|
||||
|
||||
if outputName is not None:
|
||||
path = os.path.dirname(outputName)
|
||||
if path != '' and not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
if sys.version_info > (3,0):
|
||||
f = open(outputName, "wt", encoding="mbcs")
|
||||
else:
|
||||
import codecs # not available in py3k.
|
||||
f = codecs.open(outputName, "w", "mbcs")
|
||||
else:
|
||||
f = None
|
||||
|
||||
for arg in args:
|
||||
GenerateFromTypeLibSpec(arg, f, verboseLevel = verboseLevel, bForDemand = bForDemand, bBuildHidden = hiddenSpec)
|
||||
|
||||
if f:
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
rc = main()
|
||||
if rc:
|
||||
sys.exit(rc)
|
||||
sys.exit(0)
|
160
venv/Lib/site-packages/win32com/client/selecttlb.py
Normal file
|
@ -0,0 +1,160 @@
|
|||
"""Utilities for selecting and enumerating the Type Libraries installed on the system
|
||||
"""
|
||||
|
||||
import win32api, win32con, pythoncom
|
||||
|
||||
class TypelibSpec:
|
||||
def __init__(self, clsid, lcid, major, minor, flags=0):
|
||||
self.clsid = str(clsid)
|
||||
self.lcid = int(lcid)
|
||||
# We avoid assuming 'major' or 'minor' are integers - when
|
||||
# read from the registry there is some confusion about if
|
||||
# they are base 10 or base 16 (they *should* be base 16, but
|
||||
# how they are written is beyond our control.)
|
||||
self.major = major
|
||||
self.minor = minor
|
||||
self.dll = None
|
||||
self.desc = None
|
||||
self.ver_desc = None
|
||||
self.flags = flags
|
||||
# For the SelectList
|
||||
def __getitem__(self, item):
|
||||
if item==0:
|
||||
return self.ver_desc
|
||||
raise IndexError("Cant index me!")
|
||||
|
||||
def __lt__(self, other): # rich-cmp/py3k-friendly version
|
||||
me = (self.ver_desc or "").lower(), (self.desc or "").lower(), self.major, self.minor
|
||||
them = (other.ver_desc or "").lower(), (other.desc or "").lower(), other.major, other.minor
|
||||
return me < them
|
||||
|
||||
def __eq__(self, other): # rich-cmp/py3k-friendly version
|
||||
return ((self.ver_desc or "").lower() == (other.ver_desc or "").lower() and
|
||||
(self.desc or "").lower() == (other.desc or "").lower() and
|
||||
self.major == other.major and
|
||||
self.minor == other.minor)
|
||||
|
||||
def Resolve(self):
|
||||
if self.dll is None:
|
||||
return 0
|
||||
tlb = pythoncom.LoadTypeLib(self.dll)
|
||||
self.FromTypelib(tlb, None)
|
||||
return 1
|
||||
|
||||
def FromTypelib(self, typelib, dllName = None):
|
||||
la = typelib.GetLibAttr()
|
||||
self.clsid = str(la[0])
|
||||
self.lcid = la[1]
|
||||
self.major = la[3]
|
||||
self.minor = la[4]
|
||||
if dllName:
|
||||
self.dll = dllName
|
||||
|
||||
def EnumKeys(root):
|
||||
index = 0
|
||||
ret = []
|
||||
while 1:
|
||||
try:
|
||||
item = win32api.RegEnumKey(root, index)
|
||||
except win32api.error:
|
||||
break
|
||||
try:
|
||||
# Note this doesn't handle REG_EXPAND_SZ, but the implementation
|
||||
# here doesn't need to - that is handled as the data is read.
|
||||
val = win32api.RegQueryValue(root, item)
|
||||
except win32api.error:
|
||||
val = "" # code using this assumes a string.
|
||||
|
||||
ret.append((item, val))
|
||||
index = index + 1
|
||||
return ret
|
||||
|
||||
FLAG_RESTRICTED=1
|
||||
FLAG_CONTROL=2
|
||||
FLAG_HIDDEN=4
|
||||
|
||||
def EnumTlbs(excludeFlags = 0):
|
||||
"""Return a list of TypelibSpec objects, one for each registered library.
|
||||
"""
|
||||
key = win32api.RegOpenKey(win32con.HKEY_CLASSES_ROOT, "Typelib")
|
||||
iids = EnumKeys(key)
|
||||
results = []
|
||||
for iid, crap in iids:
|
||||
try:
|
||||
key2 = win32api.RegOpenKey(key, str(iid))
|
||||
except win32api.error:
|
||||
# A few good reasons for this, including "access denied".
|
||||
continue
|
||||
for version, tlbdesc in EnumKeys(key2):
|
||||
major_minor = version.split('.', 1)
|
||||
if len(major_minor) < 2:
|
||||
major_minor.append('0')
|
||||
# For some reason, this code used to assume the values were hex.
|
||||
# This seems to not be true - particularly for CDO 1.21
|
||||
# *sigh* - it appears there are no rules here at all, so when we need
|
||||
# to know the info, we must load the tlb by filename and request it.
|
||||
# The Resolve() method on the TypelibSpec does this.
|
||||
# For this reason, keep the version numbers as strings - that
|
||||
# way we can't be wrong! Let code that really needs an int to work
|
||||
# out what to do. FWIW, http://support.microsoft.com/kb/816970 is
|
||||
# pretty clear that they *should* be hex.
|
||||
major = major_minor[0]
|
||||
minor = major_minor[1]
|
||||
key3 = win32api.RegOpenKey(key2, str(version))
|
||||
try:
|
||||
# The "FLAGS" are at this point
|
||||
flags = int(win32api.RegQueryValue(key3, "FLAGS"))
|
||||
except (win32api.error, ValueError):
|
||||
flags = 0
|
||||
if flags & excludeFlags==0:
|
||||
for lcid, crap in EnumKeys(key3):
|
||||
try:
|
||||
lcid = int(lcid)
|
||||
except ValueError: # not an LCID entry
|
||||
continue
|
||||
# Only care about "{lcid}\win32" key - jump straight there.
|
||||
try:
|
||||
key4 = win32api.RegOpenKey(key3, "%s\\win32" % (lcid,))
|
||||
except win32api.error:
|
||||
continue
|
||||
try:
|
||||
dll, typ = win32api.RegQueryValueEx(key4, None)
|
||||
if typ==win32con.REG_EXPAND_SZ:
|
||||
dll = win32api.ExpandEnvironmentStrings(dll)
|
||||
except win32api.error:
|
||||
dll = None
|
||||
spec = TypelibSpec(iid, lcid, major, minor, flags)
|
||||
spec.dll = dll
|
||||
spec.desc = tlbdesc
|
||||
spec.ver_desc = tlbdesc + " (" + version + ")"
|
||||
results.append(spec)
|
||||
return results
|
||||
|
||||
def FindTlbsWithDescription(desc):
|
||||
"""Find all installed type libraries with the specified description
|
||||
"""
|
||||
ret = []
|
||||
items = EnumTlbs()
|
||||
for item in items:
|
||||
if item.desc==desc:
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
def SelectTlb(title="Select Library", excludeFlags = 0):
|
||||
"""Display a list of all the type libraries, and select one. Returns None if cancelled
|
||||
"""
|
||||
import pywin.dialogs.list
|
||||
items = EnumTlbs(excludeFlags)
|
||||
# fixup versions - we assume hex (see __init__ above)
|
||||
for i in items:
|
||||
i.major = int(i.major, 16)
|
||||
i.minor = int(i.minor, 16)
|
||||
items.sort()
|
||||
rc = pywin.dialogs.list.SelectFromLists(title, items, ["Type Library"])
|
||||
if rc is None:
|
||||
return None
|
||||
return items[rc]
|
||||
|
||||
# Test code.
|
||||
if __name__=='__main__':
|
||||
print(SelectTlb().__dict__)
|
243
venv/Lib/site-packages/win32com/client/tlbrowse.py
Normal file
|
@ -0,0 +1,243 @@
|
|||
import win32ui
|
||||
import win32con
|
||||
import win32api
|
||||
import commctrl
|
||||
import pythoncom
|
||||
from pywin.mfc import dialog
|
||||
|
||||
class TLBrowserException(Exception):
|
||||
"TypeLib browser internal error"
|
||||
error = TLBrowserException
|
||||
|
||||
FRAMEDLG_STD = win32con.WS_CAPTION | win32con.WS_SYSMENU
|
||||
SS_STD = win32con.WS_CHILD | win32con.WS_VISIBLE
|
||||
BS_STD = SS_STD | win32con.WS_TABSTOP
|
||||
ES_STD = BS_STD | win32con.WS_BORDER
|
||||
LBS_STD = ES_STD | win32con.LBS_NOTIFY | win32con.LBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL
|
||||
CBS_STD = ES_STD | win32con.CBS_NOINTEGRALHEIGHT | win32con.WS_VSCROLL
|
||||
|
||||
typekindmap = {
|
||||
pythoncom.TKIND_ENUM : 'Enumeration',
|
||||
pythoncom.TKIND_RECORD : 'Record',
|
||||
pythoncom.TKIND_MODULE : 'Module',
|
||||
pythoncom.TKIND_INTERFACE : 'Interface',
|
||||
pythoncom.TKIND_DISPATCH : 'Dispatch',
|
||||
pythoncom.TKIND_COCLASS : 'CoClass',
|
||||
pythoncom.TKIND_ALIAS : 'Alias',
|
||||
pythoncom.TKIND_UNION : 'Union'
|
||||
}
|
||||
|
||||
TypeBrowseDialog_Parent=dialog.Dialog
|
||||
class TypeBrowseDialog(TypeBrowseDialog_Parent):
|
||||
"Browse a type library"
|
||||
|
||||
IDC_TYPELIST = 1000
|
||||
IDC_MEMBERLIST = 1001
|
||||
IDC_PARAMLIST = 1002
|
||||
IDC_LISTVIEW = 1003
|
||||
|
||||
def __init__(self, typefile = None):
|
||||
TypeBrowseDialog_Parent.__init__(self, self.GetTemplate())
|
||||
try:
|
||||
if typefile:
|
||||
self.tlb = pythoncom.LoadTypeLib(typefile)
|
||||
else:
|
||||
self.tlb = None
|
||||
except pythoncom.ole_error:
|
||||
self.MessageBox("The file does not contain type information")
|
||||
self.tlb = None
|
||||
self.HookCommand(self.CmdTypeListbox, self.IDC_TYPELIST)
|
||||
self.HookCommand(self.CmdMemberListbox, self.IDC_MEMBERLIST)
|
||||
|
||||
def OnAttachedObjectDeath(self):
|
||||
self.tlb = None
|
||||
self.typeinfo = None
|
||||
self.attr = None
|
||||
return TypeBrowseDialog_Parent.OnAttachedObjectDeath(self)
|
||||
|
||||
def _SetupMenu(self):
|
||||
menu = win32ui.CreateMenu()
|
||||
flags=win32con.MF_STRING|win32con.MF_ENABLED
|
||||
menu.AppendMenu(flags, win32ui.ID_FILE_OPEN, "&Open...")
|
||||
menu.AppendMenu(flags, win32con.IDCANCEL, "&Close")
|
||||
mainMenu = win32ui.CreateMenu()
|
||||
mainMenu.AppendMenu(flags|win32con.MF_POPUP, menu.GetHandle(), "&File")
|
||||
self.SetMenu(mainMenu)
|
||||
self.HookCommand(self.OnFileOpen,win32ui.ID_FILE_OPEN)
|
||||
|
||||
def OnFileOpen(self, id, code):
|
||||
openFlags = win32con.OFN_OVERWRITEPROMPT | win32con.OFN_FILEMUSTEXIST
|
||||
fspec = "Type Libraries (*.tlb, *.olb)|*.tlb;*.olb|OCX Files (*.ocx)|*.ocx|DLL's (*.dll)|*.dll|All Files (*.*)|*.*||"
|
||||
dlg = win32ui.CreateFileDialog(1, None, None, openFlags, fspec)
|
||||
if dlg.DoModal() == win32con.IDOK:
|
||||
try:
|
||||
self.tlb = pythoncom.LoadTypeLib(dlg.GetPathName())
|
||||
except pythoncom.ole_error:
|
||||
self.MessageBox("The file does not contain type information")
|
||||
self.tlb = None
|
||||
self._SetupTLB()
|
||||
|
||||
def OnInitDialog(self):
|
||||
self._SetupMenu()
|
||||
self.typelb = self.GetDlgItem(self.IDC_TYPELIST)
|
||||
self.memberlb = self.GetDlgItem(self.IDC_MEMBERLIST)
|
||||
self.paramlb = self.GetDlgItem(self.IDC_PARAMLIST)
|
||||
self.listview = self.GetDlgItem(self.IDC_LISTVIEW)
|
||||
|
||||
# Setup the listview columns
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, 100, "Item", 0)
|
||||
self.listview.InsertColumn(0, itemDetails)
|
||||
itemDetails = (commctrl.LVCFMT_LEFT, 1024, "Details", 0)
|
||||
self.listview.InsertColumn(1, itemDetails)
|
||||
|
||||
if self.tlb is None:
|
||||
self.OnFileOpen(None,None)
|
||||
else:
|
||||
self._SetupTLB()
|
||||
return TypeBrowseDialog_Parent.OnInitDialog(self)
|
||||
|
||||
def _SetupTLB(self):
|
||||
self.typelb.ResetContent()
|
||||
self.memberlb.ResetContent()
|
||||
self.paramlb.ResetContent()
|
||||
self.typeinfo = None
|
||||
self.attr = None
|
||||
if self.tlb is None: return
|
||||
n = self.tlb.GetTypeInfoCount()
|
||||
for i in range(n):
|
||||
self.typelb.AddString(self.tlb.GetDocumentation(i)[0])
|
||||
|
||||
def _SetListviewTextItems(self, items):
|
||||
self.listview.DeleteAllItems()
|
||||
index = -1
|
||||
for item in items:
|
||||
index = self.listview.InsertItem(index+1,item[0])
|
||||
data = item[1]
|
||||
if data is None: data = ""
|
||||
self.listview.SetItemText(index, 1, data)
|
||||
|
||||
def SetupAllInfoTypes(self):
|
||||
infos = self._GetMainInfoTypes() + self._GetMethodInfoTypes()
|
||||
self._SetListviewTextItems(infos)
|
||||
|
||||
def _GetMainInfoTypes(self):
|
||||
pos = self.typelb.GetCurSel()
|
||||
if pos<0: return []
|
||||
docinfo = self.tlb.GetDocumentation(pos)
|
||||
infos = [('GUID', str(self.attr[0]))]
|
||||
infos.append(('Help File', docinfo[3]))
|
||||
infos.append(('Help Context', str(docinfo[2])))
|
||||
try:
|
||||
infos.append(('Type Kind', typekindmap[self.tlb.GetTypeInfoType(pos)]))
|
||||
except:
|
||||
pass
|
||||
|
||||
info = self.tlb.GetTypeInfo(pos)
|
||||
attr = info.GetTypeAttr()
|
||||
infos.append(('Attributes', str(attr)))
|
||||
|
||||
for j in range(attr[8]):
|
||||
flags = info.GetImplTypeFlags(j)
|
||||
refInfo = info.GetRefTypeInfo(info.GetRefTypeOfImplType(j))
|
||||
doc = refInfo.GetDocumentation(-1)
|
||||
attr = refInfo.GetTypeAttr()
|
||||
typeKind = attr[5]
|
||||
typeFlags = attr[11]
|
||||
|
||||
desc = doc[0]
|
||||
desc = desc + ", Flags=0x%x, typeKind=0x%x, typeFlags=0x%x" % (flags, typeKind, typeFlags)
|
||||
if flags & pythoncom.IMPLTYPEFLAG_FSOURCE:
|
||||
desc = desc + "(Source)"
|
||||
infos.append( ('Implements', desc))
|
||||
|
||||
return infos
|
||||
|
||||
def _GetMethodInfoTypes(self):
|
||||
pos = self.memberlb.GetCurSel()
|
||||
if pos<0: return []
|
||||
|
||||
realPos, isMethod = self._GetRealMemberPos(pos)
|
||||
ret = []
|
||||
if isMethod:
|
||||
funcDesc = self.typeinfo.GetFuncDesc(realPos)
|
||||
id = funcDesc[0]
|
||||
ret.append(("Func Desc", str(funcDesc)))
|
||||
else:
|
||||
id = self.typeinfo.GetVarDesc(realPos)[0]
|
||||
|
||||
docinfo = self.typeinfo.GetDocumentation(id)
|
||||
ret.append(('Help String', docinfo[1]))
|
||||
ret.append(('Help Context', str(docinfo[2])))
|
||||
return ret
|
||||
|
||||
def CmdTypeListbox(self, id, code):
|
||||
if code == win32con.LBN_SELCHANGE:
|
||||
pos = self.typelb.GetCurSel()
|
||||
if pos >= 0:
|
||||
self.memberlb.ResetContent()
|
||||
self.typeinfo = self.tlb.GetTypeInfo(pos)
|
||||
self.attr = self.typeinfo.GetTypeAttr()
|
||||
for i in range(self.attr[7]):
|
||||
id = self.typeinfo.GetVarDesc(i)[0]
|
||||
self.memberlb.AddString(self.typeinfo.GetNames(id)[0])
|
||||
for i in range(self.attr[6]):
|
||||
id = self.typeinfo.GetFuncDesc(i)[0]
|
||||
self.memberlb.AddString(self.typeinfo.GetNames(id)[0])
|
||||
self.SetupAllInfoTypes()
|
||||
return 1
|
||||
|
||||
def _GetRealMemberPos(self, pos):
|
||||
pos = self.memberlb.GetCurSel()
|
||||
if pos >= self.attr[7]:
|
||||
return pos - self.attr[7], 1
|
||||
elif pos >= 0:
|
||||
return pos, 0
|
||||
else:
|
||||
raise error("The position is not valid")
|
||||
|
||||
def CmdMemberListbox(self, id, code):
|
||||
if code == win32con.LBN_SELCHANGE:
|
||||
self.paramlb.ResetContent()
|
||||
pos = self.memberlb.GetCurSel()
|
||||
realPos, isMethod = self._GetRealMemberPos(pos)
|
||||
if isMethod:
|
||||
id = self.typeinfo.GetFuncDesc(realPos)[0]
|
||||
names = self.typeinfo.GetNames(id)
|
||||
for i in range(len(names)):
|
||||
if i > 0:
|
||||
self.paramlb.AddString(names[i])
|
||||
self.SetupAllInfoTypes()
|
||||
return 1
|
||||
|
||||
def GetTemplate(self):
|
||||
"Return the template used to create this dialog"
|
||||
|
||||
w = 272 # Dialog width
|
||||
h = 192 # Dialog height
|
||||
style = FRAMEDLG_STD | win32con.WS_VISIBLE | win32con.DS_SETFONT | win32con.WS_MINIMIZEBOX
|
||||
template = [['Type Library Browser', (0, 0, w, h), style, None, (8, 'Helv')], ]
|
||||
template.append([130, "&Type", -1, (10, 10, 62, 9), SS_STD | win32con.SS_LEFT])
|
||||
template.append([131, None, self.IDC_TYPELIST, (10, 20, 80, 80), LBS_STD])
|
||||
template.append([130, "&Members", -1, (100, 10, 62, 9), SS_STD | win32con.SS_LEFT])
|
||||
template.append([131, None, self.IDC_MEMBERLIST, (100, 20, 80, 80), LBS_STD])
|
||||
template.append([130, "&Parameters", -1, (190, 10, 62, 9), SS_STD | win32con.SS_LEFT])
|
||||
template.append([131, None, self.IDC_PARAMLIST, (190, 20, 75, 80), LBS_STD])
|
||||
|
||||
lvStyle = SS_STD | commctrl.LVS_REPORT | commctrl.LVS_AUTOARRANGE | commctrl.LVS_ALIGNLEFT | win32con.WS_BORDER | win32con.WS_TABSTOP
|
||||
template.append(["SysListView32", "", self.IDC_LISTVIEW, (10, 110, 255, 65), lvStyle])
|
||||
|
||||
return template
|
||||
|
||||
if __name__=='__main__':
|
||||
import sys
|
||||
fname = None
|
||||
try:
|
||||
fname = sys.argv[1]
|
||||
except:
|
||||
pass
|
||||
dlg = TypeBrowseDialog(fname)
|
||||
try:
|
||||
win32api.GetConsoleTitle()
|
||||
dlg.DoModal()
|
||||
except:
|
||||
dlg.CreateWindow(win32ui.GetMainFrame())
|
84
venv/Lib/site-packages/win32com/client/util.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
"""General client side utilities.
|
||||
|
||||
This module contains utility functions, used primarily by advanced COM
|
||||
programmers, or other COM modules.
|
||||
"""
|
||||
import pythoncom
|
||||
from win32com.client import Dispatch, _get_good_object_
|
||||
|
||||
PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
|
||||
|
||||
def WrapEnum(ob, resultCLSID = None):
|
||||
"""Wrap an object in a VARIANT enumerator.
|
||||
|
||||
All VT_DISPATCHs returned by the enumerator are converted to wrapper objects
|
||||
(which may be either a class instance, or a dynamic.Dispatch type object).
|
||||
|
||||
"""
|
||||
if type(ob) != pythoncom.TypeIIDs[pythoncom.IID_IEnumVARIANT]:
|
||||
ob = ob.QueryInterface(pythoncom.IID_IEnumVARIANT)
|
||||
return EnumVARIANT(ob, resultCLSID)
|
||||
|
||||
class Enumerator:
|
||||
"""A class that provides indexed access into an Enumerator
|
||||
|
||||
By wrapping a PyIEnum* object in this class, you can perform
|
||||
natural looping and indexing into the Enumerator.
|
||||
|
||||
Looping is very efficient, but it should be noted that although random
|
||||
access is supported, the underlying object is still an enumerator, so
|
||||
this will force many reset-and-seek operations to find the requested index.
|
||||
|
||||
"""
|
||||
def __init__(self, enum):
|
||||
self._oleobj_ = enum # a PyIEnumVARIANT
|
||||
self.index = -1
|
||||
def __getitem__(self, index):
|
||||
return self.__GetIndex(index)
|
||||
def __call__(self, index):
|
||||
return self.__GetIndex(index)
|
||||
|
||||
def __GetIndex(self, index):
|
||||
if type(index)!=type(0): raise TypeError("Only integer indexes are supported for enumerators")
|
||||
# NOTE
|
||||
# In this context, self.index is users purely as a flag to say
|
||||
# "am I still in sequence". The user may call Next() or Reset() if they
|
||||
# so choose, in which case self.index will not be correct (although we
|
||||
# still want to stay in sequence)
|
||||
if index != self.index + 1:
|
||||
# Index requested out of sequence.
|
||||
self._oleobj_.Reset()
|
||||
if index: self._oleobj_.Skip(index) # if asked for item 1, must skip 1, Python always zero based.
|
||||
self.index = index
|
||||
result = self._oleobj_.Next(1)
|
||||
if len(result):
|
||||
return self._make_retval_(result[0])
|
||||
raise IndexError("list index out of range")
|
||||
def Next(self, count=1):
|
||||
ret = self._oleobj_.Next(count)
|
||||
realRets = []
|
||||
for r in ret:
|
||||
realRets.append(self._make_retval_(r))
|
||||
return tuple(realRets) # Convert back to tuple.
|
||||
def Reset(self):
|
||||
return self._oleobj_.Reset()
|
||||
def Clone(self):
|
||||
return self.__class__( self._oleobj_.Clone(), self.resultCLSID)
|
||||
def _make_retval_(self, result):
|
||||
return result
|
||||
|
||||
class EnumVARIANT(Enumerator):
|
||||
def __init__(self, enum, resultCLSID = None):
|
||||
self.resultCLSID = resultCLSID
|
||||
Enumerator.__init__(self, enum)
|
||||
def _make_retval_(self, result):
|
||||
return _get_good_object_(result, resultCLSID = self.resultCLSID)
|
||||
|
||||
class Iterator:
|
||||
def __init__(self, enum, resultCLSID = None):
|
||||
self.resultCLSID = resultCLSID
|
||||
self._iter_ = iter(enum.QueryInterface(pythoncom.IID_IEnumVARIANT))
|
||||
def __iter__(self):
|
||||
return self
|
||||
def __next__(self):
|
||||
return _get_good_object_(next(self._iter_), resultCLSID = self.resultCLSID)
|
0
venv/Lib/site-packages/win32com/demos/__init__.py
Normal file
83
venv/Lib/site-packages/win32com/demos/connect.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
# Implements _both_ a connectable client, and a connectable server.
|
||||
#
|
||||
# Note that we cheat just a little - the Server in this demo is not created
|
||||
# via Normal COM - this means we can avoid registering the server.
|
||||
# However, the server _is_ accessed as a COM object - just the creation
|
||||
# is cheated on - so this is still working as a fully-fledged server.
|
||||
|
||||
import pythoncom
|
||||
import win32com.server.util
|
||||
import win32com.server.connect
|
||||
from win32com.server.exception import Exception
|
||||
from pywin32_testutil import str2bytes
|
||||
|
||||
# This is the IID of the Events interface both Client and Server support.
|
||||
IID_IConnectDemoEvents = pythoncom.MakeIID("{A4988850-49C3-11d0-AE5D-52342E000000}")
|
||||
|
||||
# The server which implements
|
||||
# Create a connectable class, that has a single public method
|
||||
# 'DoIt', which echos to a single sink 'DoneIt'
|
||||
|
||||
class ConnectableServer(win32com.server.connect.ConnectableServer):
|
||||
_public_methods_ = ["DoIt"] + win32com.server.connect.ConnectableServer._public_methods_
|
||||
_connect_interfaces_ = [IID_IConnectDemoEvents]
|
||||
# The single public method that the client can call on us
|
||||
# (ie, as a normal COM server, this exposes just this single method.
|
||||
def DoIt(self,arg):
|
||||
# Simply broadcast a notification.
|
||||
self._BroadcastNotify(self.NotifyDoneIt, (arg,))
|
||||
|
||||
def NotifyDoneIt(self, interface, arg):
|
||||
interface.Invoke(1000, 0, pythoncom.DISPATCH_METHOD, 1, arg)
|
||||
|
||||
# Here is the client side of the connection world.
|
||||
# Define a COM object which implements the methods defined by the
|
||||
# IConnectDemoEvents interface.
|
||||
class ConnectableClient:
|
||||
# This is another cheat - I _know_ the server defines the "DoneIt" event
|
||||
# as DISPID==1000 - I also know from the implementation details of COM
|
||||
# that the first method in _public_methods_ gets 1000.
|
||||
# Normally some explicit DISPID->Method mapping is required.
|
||||
_public_methods_ = ["OnDoneIt"]
|
||||
def __init__(self):
|
||||
self.last_event_arg = None
|
||||
# A client must implement QI, and respond to a query for the Event interface.
|
||||
# In addition, it must provide a COM object (which server.util.wrap) does.
|
||||
def _query_interface_(self, iid):
|
||||
import win32com.server.util
|
||||
# Note that this seems like a necessary hack. I am responding to IID_IConnectDemoEvents
|
||||
# but only creating an IDispatch gateway object.
|
||||
if iid==IID_IConnectDemoEvents: return win32com.server.util.wrap(self)
|
||||
# And here is our event method which gets called.
|
||||
def OnDoneIt(self, arg):
|
||||
self.last_event_arg = arg
|
||||
|
||||
def CheckEvent(server, client, val, verbose):
|
||||
client.last_event_arg = None
|
||||
server.DoIt(val)
|
||||
if client.last_event_arg != val:
|
||||
raise RuntimeError("Sent %r, but got back %r" % (val, client.last_event_arg))
|
||||
if verbose:
|
||||
print("Sent and received %r" % val)
|
||||
|
||||
# A simple test script for all this.
|
||||
# In the real world, it is likely that the code controlling the server
|
||||
# will be in the same class as that getting the notifications.
|
||||
def test(verbose=0):
|
||||
import win32com.client.dynamic, win32com.client.connect
|
||||
import win32com.server.policy
|
||||
server = win32com.client.dynamic.Dispatch(win32com.server.util.wrap(ConnectableServer()))
|
||||
connection = win32com.client.connect.SimpleConnection()
|
||||
client = ConnectableClient()
|
||||
connection.Connect(server, client, IID_IConnectDemoEvents)
|
||||
CheckEvent(server, client, "Hello", verbose)
|
||||
CheckEvent(server, client, str2bytes("Here is a null>\x00<"), verbose)
|
||||
CheckEvent(server, client, "Here is a null>\x00<", verbose)
|
||||
val = "test-\xe0\xf2" # 2 extended characters.
|
||||
CheckEvent(server, client, val, verbose)
|
||||
if verbose:
|
||||
print("Everything seemed to work!")
|
||||
# Aggressive memory leak checking (ie, do nothing!) :-) All should cleanup OK???
|
||||
|
||||
if __name__=='__main__':
|
||||
test(1)
|
68
venv/Lib/site-packages/win32com/demos/dump_clipboard.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
import pythoncom
|
||||
import win32con
|
||||
|
||||
formats = """CF_TEXT CF_BITMAP CF_METAFILEPICT CF_SYLK CF_DIF CF_TIFF
|
||||
CF_OEMTEXT CF_DIB CF_PALETTE CF_PENDATA CF_RIFF CF_WAVE
|
||||
CF_UNICODETEXT CF_ENHMETAFILE CF_HDROP CF_LOCALE CF_MAX
|
||||
CF_OWNERDISPLAY CF_DSPTEXT CF_DSPBITMAP CF_DSPMETAFILEPICT
|
||||
CF_DSPENHMETAFILE""".split()
|
||||
format_name_map = {}
|
||||
for f in formats:
|
||||
val = getattr(win32con, f)
|
||||
format_name_map[val]=f
|
||||
|
||||
tymeds = [attr for attr in pythoncom.__dict__.keys() if attr.startswith("TYMED_")]
|
||||
|
||||
def DumpClipboard():
|
||||
do = pythoncom.OleGetClipboard()
|
||||
print("Dumping all clipboard formats...")
|
||||
for fe in do.EnumFormatEtc():
|
||||
fmt, td, aspect, index, tymed = fe
|
||||
tymeds_this = [getattr(pythoncom, t) for t in tymeds if tymed & getattr(pythoncom, t)]
|
||||
print("Clipboard format", format_name_map.get(fmt,str(fmt)))
|
||||
for t_this in tymeds_this:
|
||||
# As we are enumerating there should be no need to call
|
||||
# QueryGetData, but we do anyway!
|
||||
fetc_query = fmt, td, aspect, index, t_this
|
||||
try:
|
||||
do.QueryGetData(fetc_query)
|
||||
except pythoncom.com_error:
|
||||
print("Eeek - QGD indicated failure for tymed", t_this)
|
||||
# now actually get it.
|
||||
try:
|
||||
medium = do.GetData(fetc_query)
|
||||
except pythoncom.com_error as exc:
|
||||
print("Failed to get the clipboard data:", exc)
|
||||
continue
|
||||
if medium.tymed==pythoncom.TYMED_GDI:
|
||||
data = "GDI handle %d" % medium.data
|
||||
elif medium.tymed==pythoncom.TYMED_MFPICT:
|
||||
data = "METAFILE handle %d" % medium.data
|
||||
elif medium.tymed==pythoncom.TYMED_ENHMF:
|
||||
data = "ENHMETAFILE handle %d" % medium.data
|
||||
elif medium.tymed==pythoncom.TYMED_HGLOBAL:
|
||||
data = "%d bytes via HGLOBAL" % len(medium.data)
|
||||
elif medium.tymed==pythoncom.TYMED_FILE:
|
||||
data = "filename '%s'" % data
|
||||
elif medium.tymed==pythoncom.TYMED_ISTREAM:
|
||||
stream = medium.data
|
||||
stream.Seek(0,0)
|
||||
bytes = 0
|
||||
while 1:
|
||||
chunk = stream.Read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
bytes += len(chunk)
|
||||
data = "%d bytes via IStream" % bytes
|
||||
elif medium.tymed==pythoncom.TYMED_ISTORAGE:
|
||||
data = "a IStorage"
|
||||
else:
|
||||
data = "*** unknown tymed!"
|
||||
print(" -> got", data)
|
||||
do = None
|
||||
|
||||
if __name__=='__main__':
|
||||
DumpClipboard()
|
||||
if pythoncom._GetInterfaceCount()+pythoncom._GetGatewayCount():
|
||||
print("XXX - Leaving with %d/%d COM objects alive" % \
|
||||
(pythoncom._GetInterfaceCount(), pythoncom._GetGatewayCount()))
|
|
@ -0,0 +1,94 @@
|
|||
# A sample originally provided by Richard Bell, and modified by Mark Hammond.
|
||||
|
||||
# This sample demonstrates how to use COM events in an aparment-threaded
|
||||
# world. In this world, COM itself ensures that all calls to and events
|
||||
# from an object happen on the same thread that created the object, even
|
||||
# if they originated from different threads. For this cross-thread
|
||||
# marshalling to work, this main thread *must* run a "message-loop" (ie,
|
||||
# a loop fetching and dispatching Windows messages). Without such message
|
||||
# processing, dead-locks can occur.
|
||||
|
||||
# See also eventsFreeThreaded.py for how to do this in a free-threaded
|
||||
# world where these marshalling considerations do not exist.
|
||||
|
||||
# NOTE: This example uses Internet Explorer, but it should not be considerd
|
||||
# a "best-practices" for writing against IE events, but for working with
|
||||
# events in general. For example:
|
||||
# * The first OnDocumentComplete event is not a reliable indicator that the
|
||||
# URL has completed loading
|
||||
# * As we are demonstrating the most efficient way of handling events, when
|
||||
# running this sample you will see an IE Windows briefly appear, but
|
||||
# vanish without ever being repainted.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import win32com.client
|
||||
import win32api
|
||||
import win32event
|
||||
# sys.coinit_flags not set, so pythoncom initializes apartment-threaded.
|
||||
import pythoncom
|
||||
import time
|
||||
|
||||
class ExplorerEvents:
|
||||
def __init__(self):
|
||||
self.event = win32event.CreateEvent(None, 0, 0, None)
|
||||
def OnDocumentComplete(self,
|
||||
pDisp=pythoncom.Empty,
|
||||
URL=pythoncom.Empty):
|
||||
thread = win32api.GetCurrentThreadId()
|
||||
print("OnDocumentComplete event processed on thread %d"%thread)
|
||||
# Set the event our main thread is waiting on.
|
||||
win32event.SetEvent(self.event)
|
||||
def OnQuit(self):
|
||||
thread = win32api.GetCurrentThreadId()
|
||||
print("OnQuit event processed on thread %d"%thread)
|
||||
win32event.SetEvent(self.event)
|
||||
|
||||
def WaitWhileProcessingMessages(event, timeout = 2):
|
||||
start = time.clock()
|
||||
while True:
|
||||
# Wake 4 times a second - we can't just specify the
|
||||
# full timeout here, as then it would reset for every
|
||||
# message we process.
|
||||
rc = win32event.MsgWaitForMultipleObjects( (event,), 0,
|
||||
250,
|
||||
win32event.QS_ALLEVENTS)
|
||||
if rc == win32event.WAIT_OBJECT_0:
|
||||
# event signalled - stop now!
|
||||
return True
|
||||
if (time.clock() - start) > timeout:
|
||||
# Timeout expired.
|
||||
return False
|
||||
# must be a message.
|
||||
pythoncom.PumpWaitingMessages()
|
||||
|
||||
def TestExplorerEvents():
|
||||
iexplore = win32com.client.DispatchWithEvents(
|
||||
"InternetExplorer.Application", ExplorerEvents)
|
||||
|
||||
thread = win32api.GetCurrentThreadId()
|
||||
print('TestExplorerEvents created IE object on thread %d'%thread)
|
||||
|
||||
iexplore.Visible = 1
|
||||
try:
|
||||
iexplore.Navigate(win32api.GetFullPathName('..\\readme.htm'))
|
||||
except pythoncom.com_error as details:
|
||||
print("Warning - could not open the test HTML file", details)
|
||||
|
||||
# Wait for the event to be signalled while pumping messages.
|
||||
if not WaitWhileProcessingMessages(iexplore.event):
|
||||
print("Document load event FAILED to fire!!!")
|
||||
|
||||
iexplore.Quit()
|
||||
#
|
||||
# Give IE a chance to shutdown, else it can get upset on fast machines.
|
||||
# Note, Quit generates events. Although this test does NOT catch them
|
||||
# it is NECESSARY to pump messages here instead of a sleep so that the Quit
|
||||
# happens properly!
|
||||
if not WaitWhileProcessingMessages(iexplore.event):
|
||||
print("OnQuit event FAILED to fire!!!")
|
||||
|
||||
iexplore = None
|
||||
|
||||
if __name__=='__main__':
|
||||
TestExplorerEvents()
|
88
venv/Lib/site-packages/win32com/demos/eventsFreeThreaded.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
# A sample originally provided by Richard Bell, and modified by Mark Hammond.
|
||||
|
||||
# This sample demonstrates how to use COM events in a free-threaded world.
|
||||
# In this world, there is no need to marshall calls across threads, so
|
||||
# no message loops are needed at all. This means regular cross-thread
|
||||
# sychronization can be used. In this sample we just wait on win32 event
|
||||
# objects.
|
||||
|
||||
# See also ieEventsApartmentThreaded.py for how to do this in an
|
||||
# aparment-threaded world, where thread-marshalling complicates things.
|
||||
|
||||
# NOTE: This example uses Internet Explorer, but it should not be considerd
|
||||
# a "best-practices" for writing against IE events, but for working with
|
||||
# events in general. For example:
|
||||
# * The first OnDocumentComplete event is not a reliable indicator that the
|
||||
# URL has completed loading
|
||||
# * As we are demonstrating the most efficient way of handling events, when
|
||||
# running this sample you will see an IE Windows briefly appear, but
|
||||
# vanish without ever being repainted.
|
||||
|
||||
import sys
|
||||
sys.coinit_flags=0 # specify free threading
|
||||
|
||||
import os
|
||||
import win32api
|
||||
import win32event
|
||||
import win32com.client
|
||||
import pythoncom
|
||||
import time
|
||||
|
||||
# The print statements indicate that COM has actually started another thread
|
||||
# and will deliver the events to that thread (ie, the events do not actually
|
||||
# fire on our main thread.
|
||||
class ExplorerEvents:
|
||||
def __init__(self):
|
||||
# We reuse this event for all events.
|
||||
self.event = win32event.CreateEvent(None, 0, 0, None)
|
||||
def OnDocumentComplete(self,
|
||||
pDisp=pythoncom.Empty,
|
||||
URL=pythoncom.Empty):
|
||||
#
|
||||
# Caution: Since the main thread and events thread(s) are different
|
||||
# it may be necessary to serialize access to shared data. Because
|
||||
# this is a simple test case, that is not required here. Your
|
||||
# situation may be different. Caveat programmer.
|
||||
#
|
||||
thread = win32api.GetCurrentThreadId()
|
||||
print("OnDocumentComplete event processed on thread %d"%thread)
|
||||
# Set the event our main thread is waiting on.
|
||||
win32event.SetEvent(self.event)
|
||||
def OnQuit(self):
|
||||
thread = win32api.GetCurrentThreadId()
|
||||
print("OnQuit event processed on thread %d"%thread)
|
||||
win32event.SetEvent(self.event)
|
||||
|
||||
def TestExplorerEvents():
|
||||
iexplore = win32com.client.DispatchWithEvents(
|
||||
"InternetExplorer.Application", ExplorerEvents)
|
||||
|
||||
thread = win32api.GetCurrentThreadId()
|
||||
print('TestExplorerEvents created IE object on thread %d'%thread)
|
||||
|
||||
iexplore.Visible = 1
|
||||
try:
|
||||
iexplore.Navigate(win32api.GetFullPathName('..\\readme.htm'))
|
||||
except pythoncom.com_error as details:
|
||||
print("Warning - could not open the test HTML file", details)
|
||||
|
||||
# In this free-threaded example, we can simply wait until an event has
|
||||
# been set - we will give it 2 seconds before giving up.
|
||||
rc = win32event.WaitForSingleObject(iexplore.event, 2000)
|
||||
if rc != win32event.WAIT_OBJECT_0:
|
||||
print("Document load event FAILED to fire!!!")
|
||||
|
||||
iexplore.Quit()
|
||||
# Now we can do the same thing to wait for exit!
|
||||
# Although Quit generates events, in this free-threaded world we
|
||||
# do *not* need to run any message pumps.
|
||||
|
||||
rc = win32event.WaitForSingleObject(iexplore.event, 2000)
|
||||
if rc != win32event.WAIT_OBJECT_0:
|
||||
print("OnQuit event FAILED to fire!!!")
|
||||
|
||||
iexplore = None
|
||||
print("Finished the IE event sample!")
|
||||
|
||||
if __name__=='__main__':
|
||||
TestExplorerEvents()
|
139
venv/Lib/site-packages/win32com/demos/excelAddin.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
# A demo plugin for Microsoft Excel
|
||||
#
|
||||
# This addin simply adds a new button to the main Excel toolbar,
|
||||
# and displays a message box when clicked. Thus, it demonstrates
|
||||
# how to plug in to Excel itself, and hook Excel events.
|
||||
#
|
||||
#
|
||||
# To register the addin, simply execute:
|
||||
# excelAddin.py
|
||||
# This will install the COM server, and write the necessary
|
||||
# AddIn key to Excel
|
||||
#
|
||||
# To unregister completely:
|
||||
# excelAddin.py --unregister
|
||||
#
|
||||
# To debug, execute:
|
||||
# excelAddin.py --debug
|
||||
#
|
||||
# Then open Pythonwin, and select "Tools->Trace Collector Debugging Tool"
|
||||
# Restart excel, and you should see some output generated.
|
||||
#
|
||||
# NOTE: If the AddIn fails with an error, Excel will re-register
|
||||
# the addin to not automatically load next time Excel starts. To
|
||||
# correct this, simply re-register the addin (see above)
|
||||
#
|
||||
# Author <ekoome@yahoo.com> Eric Koome
|
||||
# Copyright (c) 2003 Wavecom Inc. All rights reserved
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
#modification, are permitted provided that the following conditions
|
||||
#are met:
|
||||
#
|
||||
#1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL ERIC KOOME OR
|
||||
# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
|
||||
from win32com import universal
|
||||
from win32com.server.exception import COMException
|
||||
from win32com.client import gencache, DispatchWithEvents
|
||||
import winerror
|
||||
import pythoncom
|
||||
from win32com.client import constants, Dispatch
|
||||
import sys
|
||||
|
||||
# Support for COM objects we use.
|
||||
gencache.EnsureModule('{00020813-0000-0000-C000-000000000046}', 0, 1, 3, bForDemand=True) # Excel 9
|
||||
gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, bForDemand=True) # Office 9
|
||||
|
||||
# The TLB defiining the interfaces we implement
|
||||
universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"])
|
||||
class ButtonEvent:
|
||||
def OnClick(self, button, cancel):
|
||||
import win32ui # Possible, but not necessary, to use a Pythonwin GUI
|
||||
import win32con
|
||||
win32ui.MessageBox("Hello from Python", "Python Test",win32con.MB_OKCANCEL)
|
||||
return cancel
|
||||
|
||||
class ExcelAddin:
|
||||
_com_interfaces_ = ['_IDTExtensibility2']
|
||||
_public_methods_ = []
|
||||
_reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
|
||||
_reg_clsid_ = "{C5482ECA-F559-45A0-B078-B2036E6F011A}"
|
||||
_reg_progid_ = "Python.Test.ExcelAddin"
|
||||
_reg_policy_spec_ = "win32com.server.policy.EventHandlerPolicy"
|
||||
|
||||
def __init__(self):
|
||||
self.appHostApp = None
|
||||
|
||||
def OnConnection(self, application, connectMode, addin, custom):
|
||||
print("OnConnection", application, connectMode, addin, custom)
|
||||
try:
|
||||
self.appHostApp = application
|
||||
cbcMyBar = self.appHostApp.CommandBars.Add(Name="PythonBar", Position=constants.msoBarTop, MenuBar=constants.msoBarTypeNormal, Temporary=True)
|
||||
btnMyButton = cbcMyBar.Controls.Add(Type=constants.msoControlButton, Parameter="Greetings")
|
||||
btnMyButton=self.toolbarButton = DispatchWithEvents(btnMyButton, ButtonEvent)
|
||||
btnMyButton.Style = constants.msoButtonCaption
|
||||
btnMyButton.BeginGroup = True
|
||||
btnMyButton.Caption = "&Python"
|
||||
btnMyButton.TooltipText = "Python rules the World"
|
||||
btnMyButton.Width = "34"
|
||||
cbcMyBar.Visible = True
|
||||
except pythoncom.com_error as xxx_todo_changeme:
|
||||
(hr, msg, exc, arg) = xxx_todo_changeme.args
|
||||
print("The Excel call failed with code %d: %s" % (hr, msg))
|
||||
if exc is None:
|
||||
print("There is no extended error information")
|
||||
else:
|
||||
wcode, source, text, helpFile, helpId, scode = exc
|
||||
print("The source of the error is", source)
|
||||
print("The error message is", text)
|
||||
print("More info can be found in %s (id=%d)" % (helpFile, helpId))
|
||||
|
||||
def OnDisconnection(self, mode, custom):
|
||||
print("OnDisconnection")
|
||||
self.appHostApp.CommandBars("PythonBar").Delete
|
||||
self.appHostApp=None
|
||||
|
||||
def OnAddInsUpdate(self, custom):
|
||||
print("OnAddInsUpdate", custom)
|
||||
def OnStartupComplete(self, custom):
|
||||
print("OnStartupComplete", custom)
|
||||
def OnBeginShutdown(self, custom):
|
||||
print("OnBeginShutdown", custom)
|
||||
|
||||
def RegisterAddin(klass):
|
||||
import winreg
|
||||
key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Excel\\Addins")
|
||||
subkey = winreg.CreateKey(key, klass._reg_progid_)
|
||||
winreg.SetValueEx(subkey, "CommandLineSafe", 0, winreg.REG_DWORD, 0)
|
||||
winreg.SetValueEx(subkey, "LoadBehavior", 0, winreg.REG_DWORD, 3)
|
||||
winreg.SetValueEx(subkey, "Description", 0, winreg.REG_SZ, "Excel Addin")
|
||||
winreg.SetValueEx(subkey, "FriendlyName", 0, winreg.REG_SZ, "A Simple Excel Addin")
|
||||
|
||||
def UnregisterAddin(klass):
|
||||
import winreg
|
||||
try:
|
||||
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Excel\\Addins\\" + klass._reg_progid_)
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
import win32com.server.register
|
||||
win32com.server.register.UseCommandLine(ExcelAddin)
|
||||
if "--unregister" in sys.argv:
|
||||
UnregisterAddin(ExcelAddin)
|
||||
else:
|
||||
RegisterAddin(ExcelAddin)
|
409
venv/Lib/site-packages/win32com/demos/excelRTDServer.py
Normal file
|
@ -0,0 +1,409 @@
|
|||
"""Excel IRTDServer implementation.
|
||||
|
||||
This module is a functional example of how to implement the IRTDServer interface
|
||||
in python, using the pywin32 extensions. Further details, about this interface
|
||||
and it can be found at:
|
||||
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnexcl2k2/html/odc_xlrtdfaq.asp
|
||||
"""
|
||||
|
||||
# Copyright (c) 2003-2004 by Chris Nilsson <chris@slort.org>
|
||||
#
|
||||
# By obtaining, using, and/or copying this software and/or its
|
||||
# associated documentation, you agree that you have read, understood,
|
||||
# and will comply with the following terms and conditions:
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and
|
||||
# its associated documentation for any purpose and without fee is
|
||||
# hereby granted, provided that the above copyright notice appears in
|
||||
# all copies, and that both that copyright notice and this permission
|
||||
# notice appear in supporting documentation, and that the name of
|
||||
# Christopher Nilsson (the author) not be used in advertising or publicity
|
||||
# pertaining to distribution of the software without specific, written
|
||||
# prior permission.
|
||||
#
|
||||
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
|
||||
# ABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
|
||||
import pythoncom
|
||||
import win32com.client
|
||||
from win32com import universal
|
||||
from win32com.client import gencache
|
||||
from win32com.server.exception import COMException
|
||||
|
||||
import threading
|
||||
import datetime # For the example classes...
|
||||
|
||||
# Typelib info for version 10 - aka Excel XP.
|
||||
# This is the minimum version of excel that we can work with as this is when
|
||||
# Microsoft introduced these interfaces.
|
||||
EXCEL_TLB_GUID = '{00020813-0000-0000-C000-000000000046}'
|
||||
EXCEL_TLB_LCID = 0
|
||||
EXCEL_TLB_MAJOR = 1
|
||||
EXCEL_TLB_MINOR = 4
|
||||
|
||||
# Import the excel typelib to make sure we've got early-binding going on.
|
||||
# The "ByRef" parameters we use later won't work without this.
|
||||
gencache.EnsureModule(EXCEL_TLB_GUID, EXCEL_TLB_LCID, \
|
||||
EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR)
|
||||
|
||||
# Tell pywin to import these extra interfaces.
|
||||
# --
|
||||
# QUESTION: Why? The interfaces seem to descend from IDispatch, so
|
||||
# I'd have thought, for example, calling callback.UpdateNotify() (on the
|
||||
# IRTDUpdateEvent callback excel gives us) would work without molestation.
|
||||
# But the callback needs to be cast to a "real" IRTDUpdateEvent type. Hmm...
|
||||
# This is where my small knowledge of the pywin framework / COM gets hazy.
|
||||
# --
|
||||
# Again, we feed in the Excel typelib as the source of these interfaces.
|
||||
universal.RegisterInterfaces(EXCEL_TLB_GUID,
|
||||
EXCEL_TLB_LCID, EXCEL_TLB_MAJOR, EXCEL_TLB_MINOR,
|
||||
['IRtdServer','IRTDUpdateEvent'])
|
||||
|
||||
class ExcelRTDServer(object):
|
||||
"""Base RTDServer class.
|
||||
|
||||
Provides most of the features needed to implement the IRtdServer interface.
|
||||
Manages topic adding, removal, and packing up the values for excel.
|
||||
|
||||
Shouldn't be instanciated directly.
|
||||
|
||||
Instead, descendant classes should override the CreateTopic() method.
|
||||
Topic objects only need to provide a GetValue() function to play nice here.
|
||||
The values given need to be atomic (eg. string, int, float... etc).
|
||||
|
||||
Also note: nothing has been done within this class to ensure that we get
|
||||
time to check our topics for updates. I've left that up to the subclass
|
||||
since the ways, and needs, of refreshing your topics will vary greatly. For
|
||||
example, the sample implementation uses a timer thread to wake itself up.
|
||||
Whichever way you choose to do it, your class needs to be able to wake up
|
||||
occaisionally, since excel will never call your class without being asked to
|
||||
first.
|
||||
|
||||
Excel will communicate with our object in this order:
|
||||
1. Excel instanciates our object and calls ServerStart, providing us with
|
||||
an IRTDUpdateEvent callback object.
|
||||
2. Excel calls ConnectData when it wants to subscribe to a new "topic".
|
||||
3. When we have new data to provide, we call the UpdateNotify method of the
|
||||
callback object we were given.
|
||||
4. Excel calls our RefreshData method, and receives a 2d SafeArray (row-major)
|
||||
containing the Topic ids in the 1st dim, and the topic values in the
|
||||
2nd dim.
|
||||
5. When not needed anymore, Excel will call our DisconnectData to
|
||||
unsubscribe from a topic.
|
||||
6. When there are no more topics left, Excel will call our ServerTerminate
|
||||
method to kill us.
|
||||
|
||||
Throughout, at undetermined periods, Excel will call our Heartbeat
|
||||
method to see if we're still alive. It must return a non-zero value, or
|
||||
we'll be killed.
|
||||
|
||||
NOTE: By default, excel will at most call RefreshData once every 2 seconds.
|
||||
This is a setting that needs to be changed excel-side. To change this,
|
||||
you can set the throttle interval like this in the excel VBA object model:
|
||||
Application.RTD.ThrottleInterval = 1000 ' milliseconds
|
||||
"""
|
||||
_com_interfaces_ = ['IRtdServer']
|
||||
_public_methods_ = ['ConnectData','DisconnectData','Heartbeat',
|
||||
'RefreshData','ServerStart','ServerTerminate']
|
||||
_reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
|
||||
#_reg_clsid_ = "# subclass must provide this class attribute"
|
||||
#_reg_desc_ = "# subclass should provide this description"
|
||||
#_reg_progid_ = "# subclass must provide this class attribute"
|
||||
|
||||
ALIVE = 1
|
||||
NOT_ALIVE = 0
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
super(ExcelRTDServer, self).__init__()
|
||||
self.IsAlive = self.ALIVE
|
||||
self.__callback = None
|
||||
self.topics = {}
|
||||
|
||||
def SignalExcel(self):
|
||||
"""Use the callback we were given to tell excel new data is available."""
|
||||
if self.__callback is None:
|
||||
raise COMException(desc="Callback excel provided is Null")
|
||||
self.__callback.UpdateNotify()
|
||||
|
||||
def ConnectData(self, TopicID, Strings, GetNewValues):
|
||||
"""Creates a new topic out of the Strings excel gives us."""
|
||||
try:
|
||||
self.topics[TopicID] = self.CreateTopic(Strings)
|
||||
except Exception as why:
|
||||
raise COMException(desc=str(why))
|
||||
GetNewValues = True
|
||||
result = self.topics[TopicID]
|
||||
if result is None:
|
||||
result = "# %s: Waiting for update" % self.__class__.__name__
|
||||
else:
|
||||
result = result.GetValue()
|
||||
|
||||
# fire out internal event...
|
||||
self.OnConnectData(TopicID)
|
||||
|
||||
# GetNewValues as per interface is ByRef, so we need to pass it back too.
|
||||
return result, GetNewValues
|
||||
|
||||
def DisconnectData(self, TopicID):
|
||||
"""Deletes the given topic."""
|
||||
self.OnDisconnectData(TopicID)
|
||||
|
||||
if TopicID in self.topics:
|
||||
self.topics[TopicID] = None
|
||||
del self.topics[TopicID]
|
||||
|
||||
def Heartbeat(self):
|
||||
"""Called by excel to see if we're still here."""
|
||||
return self.IsAlive
|
||||
|
||||
def RefreshData(self, TopicCount):
|
||||
"""Packs up the topic values. Called by excel when it's ready for an update.
|
||||
|
||||
Needs to:
|
||||
* Return the current number of topics, via the "ByRef" TopicCount
|
||||
* Return a 2d SafeArray of the topic data.
|
||||
- 1st dim: topic numbers
|
||||
- 2nd dim: topic values
|
||||
|
||||
We could do some caching, instead of repacking everytime...
|
||||
But this works for demonstration purposes."""
|
||||
TopicCount = len(self.topics)
|
||||
self.OnRefreshData()
|
||||
|
||||
# Grow the lists, so we don't need a heap of calls to append()
|
||||
results = [[None] * TopicCount, [None] * TopicCount]
|
||||
|
||||
# Excel expects a 2-dimensional array. The first dim contains the
|
||||
# topic numbers, and the second contains the values for the topics.
|
||||
# In true VBA style (yuck), we need to pack the array in row-major format,
|
||||
# which looks like:
|
||||
# ( (topic_num1, topic_num2, ..., topic_numN), \
|
||||
# (topic_val1, topic_val2, ..., topic_valN) )
|
||||
for idx, topicdata in enumerate(self.topics.items()):
|
||||
topicNum, topic = topicdata
|
||||
results[0][idx] = topicNum
|
||||
results[1][idx] = topic.GetValue()
|
||||
|
||||
# TopicCount is meant to be passed to us ByRef, so return it as well, as per
|
||||
# the way pywin32 handles ByRef arguments.
|
||||
return tuple(results), TopicCount
|
||||
|
||||
def ServerStart(self, CallbackObject):
|
||||
"""Excel has just created us... We take its callback for later, and set up shop."""
|
||||
self.IsAlive = self.ALIVE
|
||||
|
||||
if CallbackObject is None:
|
||||
raise COMException(desc='Excel did not provide a callback')
|
||||
|
||||
# Need to "cast" the raw PyIDispatch object to the IRTDUpdateEvent interface
|
||||
IRTDUpdateEventKlass = win32com.client.CLSIDToClass.GetClass('{A43788C1-D91B-11D3-8F39-00C04F3651B8}')
|
||||
self.__callback = IRTDUpdateEventKlass(CallbackObject)
|
||||
|
||||
self.OnServerStart()
|
||||
|
||||
return self.IsAlive
|
||||
|
||||
def ServerTerminate(self):
|
||||
"""Called when excel no longer wants us."""
|
||||
self.IsAlive = self.NOT_ALIVE # On next heartbeat, excel will free us
|
||||
self.OnServerTerminate()
|
||||
|
||||
def CreateTopic(self, TopicStrings=None):
|
||||
"""Topic factory method. Subclass must override.
|
||||
|
||||
Topic objects need to provide:
|
||||
* GetValue() method which returns an atomic value.
|
||||
|
||||
Will raise NotImplemented if not overridden.
|
||||
"""
|
||||
raise NotImplemented('Subclass must implement')
|
||||
|
||||
# Overridable class events...
|
||||
def OnConnectData(self, TopicID):
|
||||
"""Called when a new topic has been created, at excel's request."""
|
||||
pass
|
||||
def OnDisconnectData(self, TopicID):
|
||||
"""Called when a topic is about to be deleted, at excel's request."""
|
||||
pass
|
||||
def OnRefreshData(self):
|
||||
"""Called when excel has requested all current topic data."""
|
||||
pass
|
||||
def OnServerStart(self):
|
||||
"""Called when excel has instanciated us."""
|
||||
pass
|
||||
def OnServerTerminate(self):
|
||||
"""Called when excel is about to destroy us."""
|
||||
pass
|
||||
|
||||
class RTDTopic(object):
|
||||
"""Base RTD Topic.
|
||||
Only method required by our RTDServer implementation is GetValue().
|
||||
The others are more for convenience."""
|
||||
def __init__(self, TopicStrings):
|
||||
super(RTDTopic, self).__init__()
|
||||
self.TopicStrings = TopicStrings
|
||||
self.__currentValue = None
|
||||
self.__dirty = False
|
||||
|
||||
def Update(self, sender):
|
||||
"""Called by the RTD Server.
|
||||
Gives us a chance to check if our topic data needs to be
|
||||
changed (eg. check a file, quiz a database, etc)."""
|
||||
raise NotImplemented('subclass must implement')
|
||||
|
||||
def Reset(self):
|
||||
"""Call when this topic isn't considered "dirty" anymore."""
|
||||
self.__dirty = False
|
||||
|
||||
def GetValue(self):
|
||||
return self.__currentValue
|
||||
|
||||
def SetValue(self, value):
|
||||
self.__dirty = True
|
||||
self.__currentValue = value
|
||||
|
||||
def HasChanged(self):
|
||||
return self.__dirty
|
||||
|
||||
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
|
||||
######################################
|
||||
# Example classes
|
||||
######################################
|
||||
|
||||
class TimeServer(ExcelRTDServer):
|
||||
"""Example Time RTD server.
|
||||
|
||||
Sends time updates back to excel.
|
||||
|
||||
example of use, in an excel sheet:
|
||||
=RTD("Python.RTD.TimeServer","","seconds","5")
|
||||
|
||||
This will cause a timestamp string to fill the cell, and update its value
|
||||
every 5 seconds (or as close as possible depending on how busy excel is).
|
||||
|
||||
The empty string parameter denotes the com server is running on the local
|
||||
machine. Otherwise, put in the hostname to look on. For more info
|
||||
on this, lookup the Excel help for its "RTD" worksheet function.
|
||||
|
||||
Obviously, you'd want to wrap this kind of thing in a friendlier VBA
|
||||
function.
|
||||
|
||||
Also, remember that the RTD function accepts a maximum of 28 arguments!
|
||||
If you want to pass more, you may need to concatenate arguments into one
|
||||
string, and have your topic parse them appropriately.
|
||||
"""
|
||||
# win32com.server setup attributes...
|
||||
# Never copy the _reg_clsid_ value in your own classes!
|
||||
_reg_clsid_ = '{EA7F2CF1-11A2-45E4-B2D5-68E240DB8CB1}'
|
||||
_reg_progid_ = 'Python.RTD.TimeServer'
|
||||
_reg_desc_ = "Python class implementing Excel IRTDServer -- feeds time"
|
||||
|
||||
# other class attributes...
|
||||
INTERVAL = 0.5 # secs. Threaded timer will wake us up at this interval.
|
||||
|
||||
def __init__(self):
|
||||
super(TimeServer, self).__init__()
|
||||
|
||||
# Simply timer thread to ensure we get to update our topics, and
|
||||
# tell excel about any changes. This is a pretty basic and dirty way to
|
||||
# do this. Ideally, there should be some sort of waitable (eg. either win32
|
||||
# event, socket data event...) and be kicked off by that event triggering.
|
||||
# As soon as we set up shop here, we _must_ return control back to excel.
|
||||
# (ie. we can't block and do our own thing...)
|
||||
self.ticker = threading.Timer(self.INTERVAL, self.Update)
|
||||
|
||||
def OnServerStart(self):
|
||||
self.ticker.start()
|
||||
|
||||
def OnServerTerminate(self):
|
||||
if not self.ticker.finished.isSet():
|
||||
self.ticker.cancel() # Cancel our wake-up thread. Excel has killed us.
|
||||
|
||||
def Update(self):
|
||||
# Get our wake-up thread ready...
|
||||
self.ticker = threading.Timer(self.INTERVAL, self.Update)
|
||||
try:
|
||||
# Check if any of our topics have new info to pass on
|
||||
if len(self.topics):
|
||||
refresh = False
|
||||
for topic in self.topics.values():
|
||||
topic.Update(self)
|
||||
if topic.HasChanged():
|
||||
refresh = True
|
||||
topic.Reset()
|
||||
|
||||
if refresh:
|
||||
self.SignalExcel()
|
||||
finally:
|
||||
self.ticker.start() # Make sure we get to run again
|
||||
|
||||
def CreateTopic(self, TopicStrings=None):
|
||||
"""Topic factory. Builds a TimeTopic object out of the given TopicStrings."""
|
||||
return TimeTopic(TopicStrings)
|
||||
|
||||
class TimeTopic(RTDTopic):
|
||||
"""Example topic for example RTD server.
|
||||
|
||||
Will accept some simple commands to alter how long to delay value updates.
|
||||
|
||||
Commands:
|
||||
* seconds, delay_in_seconds
|
||||
* minutes, delay_in_minutes
|
||||
* hours, delay_in_hours
|
||||
"""
|
||||
def __init__(self, TopicStrings):
|
||||
super(TimeTopic, self).__init__(TopicStrings)
|
||||
try:
|
||||
self.cmd, self.delay = self.TopicStrings
|
||||
except Exception as E:
|
||||
# We could simply return a "# ERROR" type string as the
|
||||
# topic value, but explosions like this should be able to get handled by
|
||||
# the VBA-side "On Error" stuff.
|
||||
raise ValueError("Invalid topic strings: %s" % str(TopicStrings))
|
||||
|
||||
#self.cmd = str(self.cmd)
|
||||
self.delay = float(self.delay)
|
||||
|
||||
# setup our initial value
|
||||
self.checkpoint = self.timestamp()
|
||||
self.SetValue(str(self.checkpoint))
|
||||
|
||||
def timestamp(self):
|
||||
return datetime.datetime.now()
|
||||
|
||||
def Update(self, sender):
|
||||
now = self.timestamp()
|
||||
delta = now - self.checkpoint
|
||||
refresh = False
|
||||
if self.cmd == "seconds":
|
||||
if delta.seconds >= self.delay:
|
||||
refresh = True
|
||||
elif self.cmd == "minutes":
|
||||
if delta.minutes >= self.delay:
|
||||
refresh = True
|
||||
elif self.cmd == "hours":
|
||||
if delta.hours >= self.delay:
|
||||
refresh = True
|
||||
else:
|
||||
self.SetValue("#Unknown command: " + self.cmd)
|
||||
|
||||
if refresh:
|
||||
self.SetValue(str(now))
|
||||
self.checkpoint = now
|
||||
|
||||
if __name__ == "__main__":
|
||||
import win32com.server.register
|
||||
|
||||
# Register/Unregister TimeServer example
|
||||
# eg. at the command line: excelrtd.py --register
|
||||
# Then type in an excel cell something like:
|
||||
# =RTD("Python.RTD.TimeServer","","seconds","5")
|
||||
win32com.server.register.UseCommandLine(TimeServer)
|
188
venv/Lib/site-packages/win32com/demos/iebutton.py
Normal file
|
@ -0,0 +1,188 @@
|
|||
# -*- coding: latin-1 -*-
|
||||
|
||||
# PyWin32 Internet Explorer Button
|
||||
#
|
||||
# written by Leonard Ritter (paniq@gmx.net)
|
||||
# and Robert Förtsch (info@robert-foertsch.com)
|
||||
|
||||
|
||||
"""
|
||||
This sample implements a simple IE Button COM server
|
||||
with access to the IWebBrowser2 interface.
|
||||
|
||||
To demonstrate:
|
||||
* Execute this script to register the server.
|
||||
* Open Pythonwin's Tools -> Trace Collector Debugging Tool, so you can
|
||||
see the output of 'print' statements in this demo.
|
||||
* Open a new IE instance. The toolbar should have a new "scissors" icon,
|
||||
with tooltip text "IE Button" - this is our new button - click it.
|
||||
* Switch back to the Pythonwin window - you should see:
|
||||
IOleCommandTarget::Exec called.
|
||||
This is the button being clicked. Extending this to do something more
|
||||
useful is left as an exercise.
|
||||
|
||||
Contribtions to this sample to make it a little "friendlier" welcome!
|
||||
"""
|
||||
|
||||
# imports section
|
||||
import sys, os
|
||||
from win32com import universal
|
||||
from win32com.client import gencache, DispatchWithEvents, Dispatch
|
||||
from win32com.client import constants, getevents
|
||||
import win32com.server.register
|
||||
import win32com
|
||||
import pythoncom
|
||||
import win32api
|
||||
|
||||
# This demo uses 'print' - use win32traceutil to see it if we have no
|
||||
# console.
|
||||
try:
|
||||
win32api.GetConsoleTitle()
|
||||
except win32api.error:
|
||||
import win32traceutil
|
||||
|
||||
from win32com.axcontrol import axcontrol
|
||||
|
||||
import array, struct
|
||||
|
||||
# ensure we know the ms internet controls typelib so we have access to IWebBrowser2 later on
|
||||
win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}',0,1,1)
|
||||
|
||||
|
||||
#
|
||||
IObjectWithSite_methods = ['SetSite','GetSite']
|
||||
IOleCommandTarget_methods = ['Exec','QueryStatus']
|
||||
|
||||
_iebutton_methods_ = IOleCommandTarget_methods + IObjectWithSite_methods
|
||||
_iebutton_com_interfaces_ = [
|
||||
axcontrol.IID_IOleCommandTarget,
|
||||
axcontrol.IID_IObjectWithSite, # IObjectWithSite
|
||||
]
|
||||
|
||||
class Stub:
|
||||
"""
|
||||
this class serves as a method stub,
|
||||
outputting debug info whenever the object
|
||||
is being called.
|
||||
"""
|
||||
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def __call__(self,*args):
|
||||
print('STUB: ',self.name,args)
|
||||
|
||||
class IEButton:
|
||||
"""
|
||||
The actual COM server class
|
||||
"""
|
||||
_com_interfaces_ = _iebutton_com_interfaces_
|
||||
_public_methods_ = _iebutton_methods_
|
||||
_reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
|
||||
_button_text_ = 'IE Button'
|
||||
_tool_tip_ = 'An example implementation for an IE Button.'
|
||||
_icon_ = ''
|
||||
_hot_icon_ = ''
|
||||
|
||||
def __init__( self ):
|
||||
# put stubs for non-implemented methods
|
||||
for method in self._public_methods_:
|
||||
if not hasattr(self,method):
|
||||
print('providing default stub for %s' % method)
|
||||
setattr(self,method,Stub(method))
|
||||
|
||||
def QueryStatus (self, pguidCmdGroup, prgCmds, cmdtextf):
|
||||
# 'cmdtextf' is the 'cmdtextf' element from the OLECMDTEXT structure,
|
||||
# or None if a NULL pointer was passed.
|
||||
result = []
|
||||
for id, flags in prgCmds:
|
||||
flags |= axcontrol.OLECMDF_SUPPORTED | axcontrol.OLECMDF_ENABLED
|
||||
result.append((id, flags))
|
||||
if cmdtextf is None:
|
||||
cmdtext = None # must return None if nothing requested.
|
||||
# IE never seems to want any text - this code is here for
|
||||
# demo purposes only
|
||||
elif cmdtextf == axcontrol.OLECMDTEXTF_NAME:
|
||||
cmdtext = "IEButton Name"
|
||||
else:
|
||||
cmdtext = "IEButton State"
|
||||
return result, cmdtext
|
||||
|
||||
def Exec(self, pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn):
|
||||
print(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn)
|
||||
print("IOleCommandTarget::Exec called.")
|
||||
#self.webbrowser.ShowBrowserBar(GUID_IETOOLBAR, not is_ietoolbar_visible())
|
||||
|
||||
def SetSite(self,unknown):
|
||||
if unknown:
|
||||
# first get a command target
|
||||
cmdtarget = unknown.QueryInterface(axcontrol.IID_IOleCommandTarget)
|
||||
# then travel over to a service provider
|
||||
serviceprovider = cmdtarget.QueryInterface(pythoncom.IID_IServiceProvider)
|
||||
# finally ask for the internet explorer application, returned as a dispatch object
|
||||
self.webbrowser = win32com.client.Dispatch(serviceprovider.QueryService('{0002DF05-0000-0000-C000-000000000046}',pythoncom.IID_IDispatch))
|
||||
else:
|
||||
# lose all references
|
||||
self.webbrowser = None
|
||||
|
||||
def GetClassID(self):
|
||||
return self._reg_clsid_
|
||||
|
||||
def register(classobj):
|
||||
import winreg
|
||||
subKeyCLSID = "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\%38s" % classobj._reg_clsid_
|
||||
try:
|
||||
hKey = winreg.CreateKey( winreg.HKEY_LOCAL_MACHINE, subKeyCLSID )
|
||||
subKey = winreg.SetValueEx( hKey, "ButtonText", 0, winreg.REG_SZ, classobj._button_text_ )
|
||||
winreg.SetValueEx( hKey, "ClsidExtension", 0, winreg.REG_SZ, classobj._reg_clsid_ ) # reg value for calling COM object
|
||||
winreg.SetValueEx( hKey, "CLSID", 0, winreg.REG_SZ, "{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}" ) # CLSID for button that sends command to COM object
|
||||
winreg.SetValueEx( hKey, "Default Visible", 0, winreg.REG_SZ, "Yes" )
|
||||
winreg.SetValueEx( hKey, "ToolTip", 0, winreg.REG_SZ, classobj._tool_tip_ )
|
||||
winreg.SetValueEx( hKey, "Icon", 0, winreg.REG_SZ, classobj._icon_)
|
||||
winreg.SetValueEx( hKey, "HotIcon", 0, winreg.REG_SZ, classobj._hot_icon_)
|
||||
except WindowsError:
|
||||
print("Couldn't set standard toolbar reg keys.")
|
||||
else:
|
||||
print("Set standard toolbar reg keys.")
|
||||
|
||||
def unregister(classobj):
|
||||
import winreg
|
||||
subKeyCLSID = "SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\%38s" % classobj._reg_clsid_
|
||||
try:
|
||||
hKey = winreg.CreateKey( winreg.HKEY_LOCAL_MACHINE, subKeyCLSID )
|
||||
subKey = winreg.DeleteValue( hKey, "ButtonText" )
|
||||
winreg.DeleteValue( hKey, "ClsidExtension" ) # for calling COM object
|
||||
winreg.DeleteValue( hKey, "CLSID" )
|
||||
winreg.DeleteValue( hKey, "Default Visible" )
|
||||
winreg.DeleteValue( hKey, "ToolTip" )
|
||||
winreg.DeleteValue( hKey, "Icon" )
|
||||
winreg.DeleteValue( hKey, "HotIcon" )
|
||||
winreg.DeleteKey( winreg.HKEY_LOCAL_MACHINE, subKeyCLSID )
|
||||
except WindowsError:
|
||||
print("Couldn't delete Standard toolbar regkey.")
|
||||
else:
|
||||
print("Deleted Standard toolbar regkey.")
|
||||
|
||||
#
|
||||
# test implementation
|
||||
#
|
||||
|
||||
class PyWin32InternetExplorerButton(IEButton):
|
||||
_reg_clsid_ = "{104B66A9-9E68-49D1-A3F5-94754BE9E0E6}"
|
||||
_reg_progid_ = "PyWin32.IEButton"
|
||||
_reg_desc_ = 'Test Button'
|
||||
_button_text_ = 'IE Button'
|
||||
_tool_tip_ = 'An example implementation for an IE Button.'
|
||||
_icon_ = ''
|
||||
_hot_icon_ = _icon_
|
||||
|
||||
def DllRegisterServer():
|
||||
register(PyWin32InternetExplorerButton)
|
||||
|
||||
def DllUnregisterServer():
|
||||
unregister(PyWin32InternetExplorerButton)
|
||||
|
||||
if __name__ == '__main__':
|
||||
win32com.server.register.UseCommandLine(PyWin32InternetExplorerButton,
|
||||
finalize_register = DllRegisterServer,
|
||||
finalize_unregister = DllUnregisterServer)
|
320
venv/Lib/site-packages/win32com/demos/ietoolbar.py
Normal file
|
@ -0,0 +1,320 @@
|
|||
# -*- coding: latin-1 -*-
|
||||
|
||||
# PyWin32 Internet Explorer Toolbar
|
||||
#
|
||||
# written by Leonard Ritter (paniq@gmx.net)
|
||||
# and Robert Förtsch (info@robert-foertsch.com)
|
||||
|
||||
|
||||
"""
|
||||
This sample implements a simple IE Toolbar COM server
|
||||
supporting Windows XP styles and access to
|
||||
the IWebBrowser2 interface.
|
||||
|
||||
It also demonstrates how to hijack the parent window
|
||||
to catch WM_COMMAND messages.
|
||||
"""
|
||||
|
||||
# imports section
|
||||
import sys, os
|
||||
from win32com import universal
|
||||
from win32com.client import gencache, DispatchWithEvents, Dispatch
|
||||
from win32com.client import constants, getevents
|
||||
import win32com
|
||||
import pythoncom
|
||||
import winreg
|
||||
|
||||
from win32com.shell import shell
|
||||
from win32com.shell.shellcon import *
|
||||
from win32com.axcontrol import axcontrol
|
||||
|
||||
try:
|
||||
# try to get styles (winxp)
|
||||
import winxpgui as win32gui
|
||||
except:
|
||||
# import default module (win2k and lower)
|
||||
import win32gui
|
||||
import win32ui
|
||||
import win32con
|
||||
import commctrl
|
||||
|
||||
import array, struct
|
||||
|
||||
# ensure we know the ms internet controls typelib so we have access to IWebBrowser2 later on
|
||||
win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}',0,1,1)
|
||||
|
||||
#
|
||||
IDeskBand_methods = ['GetBandInfo']
|
||||
IDockingWindow_methods = ['ShowDW','CloseDW','ResizeBorderDW']
|
||||
IOleWindow_methods = ['GetWindow','ContextSensitiveHelp']
|
||||
IInputObject_methods = ['UIActivateIO','HasFocusIO','TranslateAcceleratorIO']
|
||||
IObjectWithSite_methods = ['SetSite','GetSite']
|
||||
IPersistStream_methods = ['GetClassID','IsDirty','Load','Save','GetSizeMax']
|
||||
|
||||
_ietoolbar_methods_ = IDeskBand_methods + IDockingWindow_methods + \
|
||||
IOleWindow_methods + IInputObject_methods + \
|
||||
IObjectWithSite_methods + IPersistStream_methods
|
||||
_ietoolbar_com_interfaces_ = [
|
||||
shell.IID_IDeskBand, # IDeskBand
|
||||
axcontrol.IID_IObjectWithSite, # IObjectWithSite
|
||||
pythoncom.IID_IPersistStream,
|
||||
axcontrol.IID_IOleCommandTarget,
|
||||
]
|
||||
|
||||
class WIN32STRUCT:
|
||||
def __init__(self, **kw):
|
||||
full_fmt = ""
|
||||
for name, fmt, default in self._struct_items_:
|
||||
self.__dict__[name] = None
|
||||
if fmt == "z":
|
||||
full_fmt += "pi"
|
||||
else:
|
||||
full_fmt += fmt
|
||||
for name, val in kw.items():
|
||||
self.__dict__[name] = val
|
||||
|
||||
def __setattr__(self, attr, val):
|
||||
if not attr.startswith("_") and attr not in self.__dict__:
|
||||
raise AttributeError(attr)
|
||||
self.__dict__[attr] = val
|
||||
|
||||
def toparam(self):
|
||||
self._buffs = []
|
||||
full_fmt = ""
|
||||
vals = []
|
||||
for name, fmt, default in self._struct_items_:
|
||||
val = self.__dict__[name]
|
||||
if fmt == "z":
|
||||
fmt = "Pi"
|
||||
if val is None:
|
||||
vals.append(0)
|
||||
vals.append(0)
|
||||
else:
|
||||
str_buf = array.array("c", val+'\0')
|
||||
vals.append(str_buf.buffer_info()[0])
|
||||
vals.append(len(val))
|
||||
self._buffs.append(str_buf) # keep alive during the call.
|
||||
else:
|
||||
if val is None:
|
||||
val = default
|
||||
vals.append(val)
|
||||
full_fmt += fmt
|
||||
return struct.pack(*(full_fmt,) + tuple(vals))
|
||||
|
||||
class TBBUTTON(WIN32STRUCT):
|
||||
_struct_items_ = [
|
||||
("iBitmap", "i", 0),
|
||||
("idCommand", "i", 0),
|
||||
("fsState", "B", 0),
|
||||
("fsStyle", "B", 0),
|
||||
("bReserved", "H", 0),
|
||||
("dwData", "I", 0),
|
||||
("iString", "z", None),
|
||||
]
|
||||
|
||||
class Stub:
|
||||
"""
|
||||
this class serves as a method stub,
|
||||
outputting debug info whenever the object
|
||||
is being called.
|
||||
"""
|
||||
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def __call__(self,*args):
|
||||
print('STUB: ',self.name,args)
|
||||
|
||||
class IEToolbarCtrl:
|
||||
"""
|
||||
a tiny wrapper for our winapi-based
|
||||
toolbar control implementation.
|
||||
"""
|
||||
def __init__(self,hwndparent):
|
||||
styles = win32con.WS_CHILD \
|
||||
| win32con.WS_VISIBLE \
|
||||
| win32con.WS_CLIPSIBLINGS \
|
||||
| win32con.WS_CLIPCHILDREN \
|
||||
| commctrl.TBSTYLE_LIST \
|
||||
| commctrl.TBSTYLE_FLAT \
|
||||
| commctrl.TBSTYLE_TRANSPARENT \
|
||||
| commctrl.CCS_TOP \
|
||||
| commctrl.CCS_NODIVIDER \
|
||||
| commctrl.CCS_NORESIZE \
|
||||
| commctrl.CCS_NOPARENTALIGN
|
||||
self.hwnd = win32gui.CreateWindow('ToolbarWindow32', None, styles,
|
||||
0, 0, 100, 100,
|
||||
hwndparent, 0, win32gui.dllhandle,
|
||||
None)
|
||||
win32gui.SendMessage(self.hwnd, commctrl.TB_BUTTONSTRUCTSIZE, 20, 0)
|
||||
|
||||
def ShowWindow(self,mode):
|
||||
win32gui.ShowWindow(self.hwnd,mode)
|
||||
|
||||
def AddButtons(self,*buttons):
|
||||
tbbuttons = ''
|
||||
for button in buttons:
|
||||
tbbuttons += button.toparam()
|
||||
return win32gui.SendMessage(self.hwnd, commctrl.TB_ADDBUTTONS,
|
||||
len(buttons), tbbuttons)
|
||||
|
||||
def GetSafeHwnd(self):
|
||||
return self.hwnd
|
||||
|
||||
class IEToolbar:
|
||||
"""
|
||||
The actual COM server class
|
||||
"""
|
||||
_com_interfaces_ = _ietoolbar_com_interfaces_
|
||||
_public_methods_ = _ietoolbar_methods_
|
||||
_reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
|
||||
# if you copy and modify this example, be sure to change the clsid below
|
||||
_reg_clsid_ = "{F21202A2-959A-4149-B1C3-68B9013F3335}"
|
||||
_reg_progid_ = "PyWin32.IEToolbar"
|
||||
_reg_desc_ = 'PyWin32 IE Toolbar'
|
||||
|
||||
def __init__( self ):
|
||||
# put stubs for non-implemented methods
|
||||
for method in self._public_methods_:
|
||||
if not hasattr(self,method):
|
||||
print('providing default stub for %s' % method)
|
||||
setattr(self,method,Stub(method))
|
||||
|
||||
def GetWindow(self):
|
||||
return self.toolbar.GetSafeHwnd()
|
||||
|
||||
def Load(self, stream):
|
||||
# called when the toolbar is loaded
|
||||
pass
|
||||
|
||||
def Save(self, pStream, fClearDirty):
|
||||
# called when the toolbar shall save its information
|
||||
pass
|
||||
|
||||
def CloseDW(self, dwReserved):
|
||||
del self.toolbar
|
||||
|
||||
def ShowDW(self, bShow):
|
||||
if bShow:
|
||||
self.toolbar.ShowWindow(win32con.SW_SHOW)
|
||||
else:
|
||||
self.toolbar.ShowWindow(win32con.SW_HIDE)
|
||||
|
||||
def on_first_button(self):
|
||||
print("first!")
|
||||
self.webbrowser.Navigate2('http://starship.python.net/crew/mhammond/')
|
||||
|
||||
def on_second_button(self):
|
||||
print("second!")
|
||||
|
||||
def on_third_button(self):
|
||||
print("third!")
|
||||
|
||||
def toolbar_command_handler(self,args):
|
||||
hwnd,message,wparam,lparam,time,point = args
|
||||
if lparam == self.toolbar.GetSafeHwnd():
|
||||
self._command_map[wparam]()
|
||||
|
||||
def SetSite(self,unknown):
|
||||
if unknown:
|
||||
# retrieve the parent window interface for this site
|
||||
olewindow = unknown.QueryInterface(pythoncom.IID_IOleWindow)
|
||||
# ask the window for its handle
|
||||
hwndparent = olewindow.GetWindow()
|
||||
|
||||
# first get a command target
|
||||
cmdtarget = unknown.QueryInterface(axcontrol.IID_IOleCommandTarget)
|
||||
# then travel over to a service provider
|
||||
serviceprovider = cmdtarget.QueryInterface(pythoncom.IID_IServiceProvider)
|
||||
# finally ask for the internet explorer application, returned as a dispatch object
|
||||
self.webbrowser = win32com.client.Dispatch(serviceprovider.QueryService('{0002DF05-0000-0000-C000-000000000046}',pythoncom.IID_IDispatch))
|
||||
|
||||
# now create and set up the toolbar
|
||||
self.toolbar = IEToolbarCtrl(hwndparent)
|
||||
|
||||
buttons = [
|
||||
('Visit PyWin32 Homepage',self.on_first_button),
|
||||
('Another Button', self.on_second_button),
|
||||
('Yet Another Button', self.on_third_button),
|
||||
]
|
||||
|
||||
self._command_map = {}
|
||||
# wrap our parent window so we can hook message handlers
|
||||
window = win32ui.CreateWindowFromHandle(hwndparent)
|
||||
|
||||
# add the buttons
|
||||
for i in range(len(buttons)):
|
||||
button = TBBUTTON()
|
||||
name,func = buttons[i]
|
||||
id = 0x4444+i
|
||||
button.iBitmap = -2
|
||||
button.idCommand = id
|
||||
button.fsState = commctrl.TBSTATE_ENABLED
|
||||
button.fsStyle = commctrl.TBSTYLE_BUTTON
|
||||
button.iString = name
|
||||
self._command_map[0x4444+i] = func
|
||||
self.toolbar.AddButtons(button)
|
||||
window.HookMessage(self.toolbar_command_handler,win32con.WM_COMMAND)
|
||||
else:
|
||||
# lose all references
|
||||
self.webbrowser = None
|
||||
|
||||
def GetClassID(self):
|
||||
return self._reg_clsid_
|
||||
|
||||
def GetBandInfo(self, dwBandId, dwViewMode, dwMask):
|
||||
ptMinSize = (0,24)
|
||||
ptMaxSize = (2000,24)
|
||||
ptIntegral = (0,0)
|
||||
ptActual = (2000,24)
|
||||
wszTitle = 'PyWin32 IE Toolbar'
|
||||
dwModeFlags = DBIMF_VARIABLEHEIGHT
|
||||
crBkgnd = 0
|
||||
return (ptMinSize,ptMaxSize,ptIntegral,ptActual,wszTitle,dwModeFlags,crBkgnd)
|
||||
|
||||
# used for HKLM install
|
||||
def DllInstall( bInstall, cmdLine ):
|
||||
comclass = IEToolbar
|
||||
|
||||
# register plugin
|
||||
def DllRegisterServer():
|
||||
comclass = IEToolbar
|
||||
|
||||
# register toolbar with IE
|
||||
try:
|
||||
print("Trying to register Toolbar.\n")
|
||||
hkey = winreg.CreateKey( winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Internet Explorer\\Toolbar" )
|
||||
subKey = winreg.SetValueEx( hkey, comclass._reg_clsid_, 0, winreg.REG_BINARY, "\0" )
|
||||
except WindowsError:
|
||||
print("Couldn't set registry value.\nhkey: %d\tCLSID: %s\n" % ( hkey, comclass._reg_clsid_ ))
|
||||
else:
|
||||
print("Set registry value.\nhkey: %d\tCLSID: %s\n" % ( hkey, comclass._reg_clsid_ ))
|
||||
# TODO: implement reg settings for standard toolbar button
|
||||
|
||||
# unregister plugin
|
||||
def DllUnregisterServer():
|
||||
comclass = IEToolbar
|
||||
|
||||
# unregister toolbar from internet explorer
|
||||
try:
|
||||
print("Trying to unregister Toolbar.\n")
|
||||
hkey = winreg.CreateKey( winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Internet Explorer\\Toolbar" )
|
||||
winreg.DeleteValue( hkey, comclass._reg_clsid_ )
|
||||
except WindowsError:
|
||||
print("Couldn't delete registry value.\nhkey: %d\tCLSID: %s\n" % ( hkey, comclass._reg_clsid_ ))
|
||||
else:
|
||||
print("Deleting reg key succeeded.\n")
|
||||
|
||||
# entry point
|
||||
if __name__ == '__main__':
|
||||
import win32com.server.register
|
||||
win32com.server.register.UseCommandLine( IEToolbar )
|
||||
|
||||
# parse actual command line option
|
||||
if "--unregister" in sys.argv:
|
||||
DllUnregisterServer()
|
||||
else:
|
||||
DllRegisterServer()
|
||||
else:
|
||||
# import trace utility for remote debugging
|
||||
import win32traceutil
|
114
venv/Lib/site-packages/win32com/demos/outlookAddin.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
# A demo plugin for Microsoft Outlook (NOT Outlook Express)
|
||||
#
|
||||
# This addin simply adds a new button to the main Outlook toolbar,
|
||||
# and displays a message box when clicked. Thus, it demonstrates
|
||||
# how to plug in to Outlook itself, and hook outlook events.
|
||||
#
|
||||
# Additionally, each time a new message arrives in the Inbox, a message
|
||||
# is printed with the subject of the message.
|
||||
#
|
||||
# To register the addin, simply execute:
|
||||
# outlookAddin.py
|
||||
# This will install the COM server, and write the necessary
|
||||
# AddIn key to Outlook
|
||||
#
|
||||
# To unregister completely:
|
||||
# outlookAddin.py --unregister
|
||||
#
|
||||
# To debug, execute:
|
||||
# outlookAddin.py --debug
|
||||
#
|
||||
# Then open Pythonwin, and select "Tools->Trace Collector Debugging Tool"
|
||||
# Restart Outlook, and you should see some output generated.
|
||||
#
|
||||
# NOTE: If the AddIn fails with an error, Outlook will re-register
|
||||
# the addin to not automatically load next time Outlook starts. To
|
||||
# correct this, simply re-register the addin (see above)
|
||||
|
||||
from win32com import universal
|
||||
from win32com.server.exception import COMException
|
||||
from win32com.client import gencache, DispatchWithEvents
|
||||
import winerror
|
||||
import pythoncom
|
||||
from win32com.client import constants
|
||||
import sys
|
||||
|
||||
# Support for COM objects we use.
|
||||
gencache.EnsureModule('{00062FFF-0000-0000-C000-000000000046}', 0, 9, 0, bForDemand=True) # Outlook 9
|
||||
gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, bForDemand=True) # Office 9
|
||||
|
||||
# The TLB defining the interfaces we implement
|
||||
universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"])
|
||||
|
||||
class ButtonEvent:
|
||||
def OnClick(self, button, cancel):
|
||||
import win32ui # Possible, but not necessary, to use a Pythonwin GUI
|
||||
win32ui.MessageBox("Hello from Python")
|
||||
return cancel
|
||||
|
||||
class FolderEvent:
|
||||
def OnItemAdd(self, item):
|
||||
try:
|
||||
print("An item was added to the inbox with subject:", item.Subject)
|
||||
except AttributeError:
|
||||
print("An item was added to the inbox, but it has no subject! - ", repr(item))
|
||||
|
||||
|
||||
|
||||
class OutlookAddin:
|
||||
_com_interfaces_ = ['_IDTExtensibility2']
|
||||
_public_methods_ = []
|
||||
_reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
|
||||
_reg_clsid_ = "{0F47D9F3-598B-4d24-B7E3-92AC15ED27E2}"
|
||||
_reg_progid_ = "Python.Test.OutlookAddin"
|
||||
_reg_policy_spec_ = "win32com.server.policy.EventHandlerPolicy"
|
||||
def OnConnection(self, application, connectMode, addin, custom):
|
||||
print("OnConnection", application, connectMode, addin, custom)
|
||||
# ActiveExplorer may be none when started without a UI (eg, WinCE synchronisation)
|
||||
activeExplorer = application.ActiveExplorer()
|
||||
if activeExplorer is not None:
|
||||
bars = activeExplorer.CommandBars
|
||||
toolbar = bars.Item("Standard")
|
||||
item = toolbar.Controls.Add(Type=constants.msoControlButton, Temporary=True)
|
||||
# Hook events for the item
|
||||
item = self.toolbarButton = DispatchWithEvents(item, ButtonEvent)
|
||||
item.Caption="Python"
|
||||
item.TooltipText = "Click for Python"
|
||||
item.Enabled = True
|
||||
|
||||
# And now, for the sake of demonstration, setup a hook for all new messages
|
||||
inbox = application.Session.GetDefaultFolder(constants.olFolderInbox)
|
||||
self.inboxItems = DispatchWithEvents(inbox.Items, FolderEvent)
|
||||
|
||||
def OnDisconnection(self, mode, custom):
|
||||
print("OnDisconnection")
|
||||
def OnAddInsUpdate(self, custom):
|
||||
print("OnAddInsUpdate", custom)
|
||||
def OnStartupComplete(self, custom):
|
||||
print("OnStartupComplete", custom)
|
||||
def OnBeginShutdown(self, custom):
|
||||
print("OnBeginShutdown", custom)
|
||||
|
||||
def RegisterAddin(klass):
|
||||
import winreg
|
||||
key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins")
|
||||
subkey = winreg.CreateKey(key, klass._reg_progid_)
|
||||
winreg.SetValueEx(subkey, "CommandLineSafe", 0, winreg.REG_DWORD, 0)
|
||||
winreg.SetValueEx(subkey, "LoadBehavior", 0, winreg.REG_DWORD, 3)
|
||||
winreg.SetValueEx(subkey, "Description", 0, winreg.REG_SZ, klass._reg_progid_)
|
||||
winreg.SetValueEx(subkey, "FriendlyName", 0, winreg.REG_SZ, klass._reg_progid_)
|
||||
|
||||
def UnregisterAddin(klass):
|
||||
import winreg
|
||||
try:
|
||||
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins\\" + klass._reg_progid_)
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
import win32com.server.register
|
||||
win32com.server.register.UseCommandLine(OutlookAddin)
|
||||
if "--unregister" in sys.argv:
|
||||
UnregisterAddin(OutlookAddin)
|
||||
else:
|
||||
RegisterAddin(OutlookAddin)
|
75
venv/Lib/site-packages/win32com/demos/trybag.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
import pythoncom
|
||||
from win32com.server import util
|
||||
from win32com.server import exception
|
||||
|
||||
VT_EMPTY = pythoncom.VT_EMPTY
|
||||
|
||||
class Bag:
|
||||
_public_methods_ = [ 'Read', 'Write' ]
|
||||
_com_interfaces_ = [ pythoncom.IID_IPropertyBag ]
|
||||
|
||||
def __init__(self):
|
||||
self.data = { }
|
||||
|
||||
def Read(self, propName, varType, errorLog):
|
||||
print("read: name=", propName, "type=", varType)
|
||||
if propName not in self.data:
|
||||
if errorLog:
|
||||
hr = 0x80070057
|
||||
exc = pythoncom.com_error(0, "Bag.Read", "no such item", None, 0, hr)
|
||||
errorLog.AddError(propName, exc)
|
||||
raise exception.Exception(scode=hr)
|
||||
return self.data[propName]
|
||||
|
||||
def Write(self, propName, value):
|
||||
print("write: name=", propName, "value=", value)
|
||||
self.data[propName] = value
|
||||
|
||||
|
||||
class Target:
|
||||
_public_methods_ = [ 'GetClassID', 'InitNew', 'Load', 'Save' ]
|
||||
_com_interfaces_ = [ pythoncom.IID_IPersist,
|
||||
pythoncom.IID_IPersistPropertyBag ]
|
||||
|
||||
def GetClassID(self):
|
||||
raise exception.Exception(scode=0x80004005) # E_FAIL
|
||||
|
||||
def InitNew(self):
|
||||
pass
|
||||
|
||||
def Load(self, bag, log):
|
||||
print(bag.Read('prop1', VT_EMPTY, log))
|
||||
print(bag.Read('prop2', VT_EMPTY, log))
|
||||
try:
|
||||
print(bag.Read('prop3', VT_EMPTY, log))
|
||||
except exception.Exception:
|
||||
pass
|
||||
|
||||
def Save(self, bag, clearDirty, saveAllProps):
|
||||
bag.Write('prop1', 'prop1.hello')
|
||||
bag.Write('prop2', 'prop2.there')
|
||||
|
||||
class Log:
|
||||
_public_methods_ = [ 'AddError' ]
|
||||
_com_interfaces_ = [ pythoncom.IID_IErrorLog ]
|
||||
|
||||
def AddError(self, propName, excepInfo):
|
||||
print("error: propName=", propName, "error=", excepInfo)
|
||||
|
||||
def test():
|
||||
bag = Bag()
|
||||
target = Target()
|
||||
log = Log()
|
||||
|
||||
target.Save(bag, 1, 1)
|
||||
target.Load(bag, log)
|
||||
|
||||
comBag = util.wrap(bag, pythoncom.IID_IPropertyBag)
|
||||
comTarget = util.wrap(target, pythoncom.IID_IPersistPropertyBag)
|
||||
comLog = util.wrap(log, pythoncom.IID_IErrorLog)
|
||||
|
||||
comTarget.Save(comBag, 1, 1)
|
||||
comTarget.Load(comBag, comLog)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
760
venv/Lib/site-packages/win32com/include/PythonCOM.h
Normal file
|
@ -0,0 +1,760 @@
|
|||
/* PythonCOM.h
|
||||
|
||||
Main header for Python COM support.
|
||||
|
||||
This file is involved mainly with client side COM support for
|
||||
Python.
|
||||
|
||||
Most COM work put together by Greg Stein and Mark Hammond, with a
|
||||
few others starting to come out of the closet.
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
||||
Thread State Rules
|
||||
------------------
|
||||
These rules apply to PythonCOM in general, and not just to
|
||||
the client side.
|
||||
|
||||
The rules are quite simple, but it is critical they be followed.
|
||||
In general, errors here will be picked up quite quickly, as Python
|
||||
will raise a Fatal Error. However, the Release() issue in particular
|
||||
may keep a number of problems well hidden.
|
||||
|
||||
Interfaces:
|
||||
-----------
|
||||
Before making ANY call out to COM, you MUST release the Python lock.
|
||||
This is true to ANY call whatsoever, including the COM call in question,
|
||||
but also any calls to "->Release();"
|
||||
|
||||
This is normally achieved with the calls
|
||||
PY_INTERFACE_PRECALL and PY_INTERFACE_POSTCALL, which release
|
||||
and acquire the Python lock.
|
||||
|
||||
Gateways:
|
||||
---------
|
||||
Before doing anything related to Python, gateways MUST acquire the
|
||||
Python lock, and must release it before returning.
|
||||
|
||||
This is normally achieved with PY_GATEWAY_METHOD at the top of a
|
||||
gateway method. This macro resolves to a class, which automatically does
|
||||
the right thing.
|
||||
|
||||
Release:
|
||||
--------
|
||||
As mentioned above for Interfaces, EVERY call to Release() must be done
|
||||
with the Python lock released. This is expanded here.
|
||||
|
||||
This is very important, but an error may not be noticed. The problem will
|
||||
only be seen when the Release() is on a Python object and the Release() is the
|
||||
final one for the object. In this case, the Python object will attempt to
|
||||
acquire the Python lock before destroying itself, and Python will raise a
|
||||
fatal error.
|
||||
|
||||
In many many cases, you will not notice this error, but someday, someone will
|
||||
implement the other side in Python, and suddenly FatalErrors will start
|
||||
appearing. Make sure you get this right.
|
||||
|
||||
Eg, this code is correct:
|
||||
PY_INTERFACE_PRECALL;
|
||||
pSomeObj->SomeFunction(pSomeOtherObject);
|
||||
pSomeOtherObject->Release();
|
||||
PY_INTERFACE_POSTCALL;
|
||||
|
||||
However, this code is WRONG, but will RARELY FAIL.
|
||||
PY_INTERFACE_PRECALL;
|
||||
pSomeObj->SomeFunction(pSomeOtherObject);
|
||||
PY_INTERFACE_POSTCALL;
|
||||
pSomeOtherObject->Release();
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef __PYTHONCOM_H__
|
||||
#define __PYTHONCOM_H__
|
||||
|
||||
// #define _DEBUG_LIFETIMES // Trace COM object lifetimes.
|
||||
|
||||
#ifdef FREEZE_PYTHONCOM
|
||||
/* The pythoncom module is being included in a frozen .EXE/.DLL */
|
||||
#define PYCOM_EXPORT
|
||||
#else
|
||||
#ifdef BUILD_PYTHONCOM
|
||||
/* We are building pythoncomxx.dll */
|
||||
#define PYCOM_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
/* This module uses pythoncomxx.dll */
|
||||
#define PYCOM_EXPORT __declspec(dllimport)
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "pythoncom.lib")
|
||||
#else
|
||||
#pragma comment(lib, "pythoncom_d.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINCE
|
||||
// List of interfaces not supported by CE.
|
||||
#define NO_PYCOM_IDISPATCHEX
|
||||
#define NO_PYCOM_IPROVIDECLASSINFO
|
||||
#define NO_PYCOM_IENUMGUID
|
||||
#define NO_PYCOM_IENUMCATEGORYINFO
|
||||
#define NO_PYCOM_ICATINFORMATION
|
||||
#define NO_PYCOM_ICATREGISTER
|
||||
#define NO_PYCOM_ISERVICEPROVIDER
|
||||
#define NO_PYCOM_IPROPERTYSTORAGE
|
||||
#define NO_PYCOM_IPROPERTYSETSTORAGE
|
||||
#define NO_PYCOM_ENUMSTATPROPSTG
|
||||
|
||||
#include "ocidl.h"
|
||||
#include "oleauto.h"
|
||||
|
||||
#endif // MS_WINCE
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// Special Mingw32 considerations.
|
||||
#define NO_PYCOM_ENUMSTATPROPSTG
|
||||
#define __try try
|
||||
#define __except catch
|
||||
#include <olectl.h>
|
||||
|
||||
#endif // __MINGW32__
|
||||
|
||||
#include <PyWinTypes.h> // Standard Win32 Types
|
||||
|
||||
#ifndef NO_PYCOM_IDISPATCHEX
|
||||
#include <dispex.h> // New header for IDispatchEx interface.
|
||||
#endif // NO_PYCOM_IDISPATCHEX
|
||||
|
||||
#if defined(MAINWIN)
|
||||
// Mainwin seems to have 1/2 the VT_RECORD infrastructure in place
|
||||
#if !defined(VT_RECORD)
|
||||
#define VT_RECORD 36
|
||||
#define V_RECORDINFO(X) ((X)->brecVal.pRecInfo)
|
||||
#define V_RECORD(X) ((X)->brecVal.pvRecord)
|
||||
#else
|
||||
#pragma message( \
|
||||
"MAINWIN appears to have grown correct VT_RECORD " \
|
||||
"support. Please update PythonCOM.h accordingly")
|
||||
#endif // VT_RECORD
|
||||
#endif // MAINWIN
|
||||
|
||||
class PyIUnknown;
|
||||
// To make life interesting/complicated, I use C++ classes for
|
||||
// all Python objects. The main advantage is that I can derive
|
||||
// a PyIDispatch object from a PyIUnknown, etc. This provides a
|
||||
// clean C++ interface, and "automatically" provides all base
|
||||
// Python methods to "derived" Python types.
|
||||
//
|
||||
// Main disadvantage is that any extension DLLs will need to include
|
||||
// these headers, and link with this .lib
|
||||
//
|
||||
// Base class for (most of) the type objects.
|
||||
|
||||
class PYCOM_EXPORT PyComTypeObject : public PyTypeObject {
|
||||
public:
|
||||
PyComTypeObject(const char *name, PyComTypeObject *pBaseType, int typeSize, struct PyMethodDef *methodList,
|
||||
PyIUnknown *(*thector)(IUnknown *));
|
||||
~PyComTypeObject();
|
||||
|
||||
// is the given object an interface type object? (e.g. PyIUnknown)
|
||||
static BOOL is_interface_type(PyObject *ob);
|
||||
|
||||
public:
|
||||
PyIUnknown *(*ctor)(IUnknown *);
|
||||
};
|
||||
|
||||
// A type used for interfaces that can automatically provide enumerators
|
||||
// (ie, they themselves aren't enumerable, but do have a suitable default
|
||||
// method that returns a PyIEnum object
|
||||
class PYCOM_EXPORT PyComEnumProviderTypeObject : public PyComTypeObject {
|
||||
public:
|
||||
PyComEnumProviderTypeObject(const char *name, PyComTypeObject *pBaseType, int typeSize,
|
||||
struct PyMethodDef *methodList, PyIUnknown *(*thector)(IUnknown *),
|
||||
const char *enum_method_name);
|
||||
static PyObject *iter(PyObject *self);
|
||||
const char *enum_method_name;
|
||||
};
|
||||
|
||||
// A type used for PyIEnum interfaces
|
||||
class PYCOM_EXPORT PyComEnumTypeObject : public PyComTypeObject {
|
||||
public:
|
||||
static PyObject *iter(PyObject *self);
|
||||
static PyObject *iternext(PyObject *self);
|
||||
PyComEnumTypeObject(const char *name, PyComTypeObject *pBaseType, int typeSize, struct PyMethodDef *methodList,
|
||||
PyIUnknown *(*thector)(IUnknown *));
|
||||
};
|
||||
|
||||
// Very very base class - not COM specific - Should exist in the
|
||||
// Python core somewhere, IMO.
|
||||
class PYCOM_EXPORT PyIBase : public PyObject {
|
||||
public:
|
||||
// virtuals for Python support
|
||||
virtual PyObject *getattr(char *name);
|
||||
virtual int setattr(char *name, PyObject *v);
|
||||
virtual PyObject *repr();
|
||||
virtual int compare(PyObject *other)
|
||||
{
|
||||
if (this == other)
|
||||
return 0;
|
||||
if (this < other)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
// These iter are a little special, in that returning NULL means
|
||||
// use the implementation in the type
|
||||
virtual PyObject *iter() { return NULL; }
|
||||
virtual PyObject *iternext() { return NULL; }
|
||||
|
||||
protected:
|
||||
PyIBase();
|
||||
virtual ~PyIBase();
|
||||
|
||||
public:
|
||||
static BOOL is_object(PyObject *, PyComTypeObject *which);
|
||||
BOOL is_object(PyComTypeObject *which);
|
||||
static void dealloc(PyObject *ob);
|
||||
static PyObject *repr(PyObject *ob);
|
||||
static PyObject *getattro(PyObject *self, PyObject *name);
|
||||
static int setattro(PyObject *op, PyObject *obname, PyObject *v);
|
||||
static int cmp(PyObject *ob1, PyObject *ob2);
|
||||
static PyObject *richcmp(PyObject *ob1, PyObject *ob2, int op);
|
||||
};
|
||||
|
||||
/* Special Type objects */
|
||||
extern PYCOM_EXPORT PyTypeObject PyOleEmptyType; // equivalent to VT_EMPTY
|
||||
extern PYCOM_EXPORT PyTypeObject PyOleMissingType; // special Python handling.
|
||||
extern PYCOM_EXPORT PyTypeObject PyOleArgNotFoundType; // special VT_ERROR value
|
||||
extern PYCOM_EXPORT PyTypeObject PyOleNothingType; // special VT_ERROR value
|
||||
|
||||
// ALL of these set an appropriate Python error on bad return.
|
||||
|
||||
// Given a Python object that is a registered COM type, return a given
|
||||
// interface pointer on its underlying object, with a new reference added.
|
||||
PYCOM_EXPORT BOOL PyCom_InterfaceFromPyObject(PyObject *ob, REFIID iid, LPVOID *ppv, BOOL bNoneOK = TRUE);
|
||||
|
||||
// As above, but allows instance with "_oleobj_" attribute.
|
||||
PYCOM_EXPORT BOOL PyCom_InterfaceFromPyInstanceOrObject(PyObject *ob, REFIID iid, LPVOID *ppv, BOOL bNoneOK = TRUE);
|
||||
|
||||
// Release an arbitary COM pointer.
|
||||
// NOTE: the PRECALL/POSTCALL stuff is probably not strictly necessary
|
||||
// since the PyGILSTATE stuff has been in place (and even then, it only
|
||||
// mattered when it was the last Release() on a Python implemented object)
|
||||
#define PYCOM_RELEASE(pUnk) \
|
||||
{ \
|
||||
if (pUnk) { \
|
||||
PY_INTERFACE_PRECALL; \
|
||||
(pUnk)->Release(); \
|
||||
PY_INTERFACE_POSTCALL; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Given an IUnknown and an Interface ID, create and return an object
|
||||
// of the appropriate type. eg IID_Unknown->PyIUnknown,
|
||||
// IID_IDispatch->PyIDispatch, etc.
|
||||
// Uses a map that external extension DLLs can populate with their IID/type.
|
||||
// Under the principal of least surprise, this will return Py_None is punk is NULL.
|
||||
// Otherwise, a valid PyI*, but with NULL m_obj (and therefore totally useless)
|
||||
// object would be created.
|
||||
// BOOL bAddRef indicates if a COM reference count should be added to the IUnknown.
|
||||
// This depends purely on the context in which it is called. If the IUnknown is obtained
|
||||
// from a function that creates a new ref (eg, CoCreateInstance()) then you should use
|
||||
// FALSE. If you receive the pointer as (eg) a param to a gateway function, then
|
||||
// you normally need to pass TRUE, as this is truly a new reference.
|
||||
// *** ALWAYS take the time to get this right. ***
|
||||
PYCOM_EXPORT PyObject *PyCom_PyObjectFromIUnknown(IUnknown *punk, REFIID riid, BOOL bAddRef = FALSE);
|
||||
|
||||
// VARIANT <-> PyObject conversion utilities.
|
||||
PYCOM_EXPORT BOOL PyCom_VariantFromPyObject(PyObject *obj, VARIANT *var);
|
||||
PYCOM_EXPORT PyObject *PyCom_PyObjectFromVariant(const VARIANT *var);
|
||||
|
||||
// PROPVARIANT
|
||||
PYCOM_EXPORT PyObject *PyObject_FromPROPVARIANT(PROPVARIANT *pVar);
|
||||
PYCOM_EXPORT PyObject *PyObject_FromPROPVARIANTs(PROPVARIANT *pVars, ULONG cVars);
|
||||
PYCOM_EXPORT BOOL PyObject_AsPROPVARIANT(PyObject *ob, PROPVARIANT *pVar);
|
||||
|
||||
// Other conversion helpers...
|
||||
PYCOM_EXPORT PyObject *PyCom_PyObjectFromSTATSTG(STATSTG *pStat);
|
||||
PYCOM_EXPORT BOOL PyCom_PyObjectAsSTATSTG(PyObject *ob, STATSTG *pStat, DWORD flags = 0);
|
||||
PYCOM_EXPORT BOOL PyCom_SAFEARRAYFromPyObject(PyObject *obj, SAFEARRAY **ppSA, VARENUM vt = VT_VARIANT);
|
||||
PYCOM_EXPORT PyObject *PyCom_PyObjectFromSAFEARRAY(SAFEARRAY *psa, VARENUM vt = VT_VARIANT);
|
||||
#ifndef NO_PYCOM_STGOPTIONS
|
||||
PYCOM_EXPORT BOOL PyCom_PyObjectAsSTGOPTIONS(PyObject *obstgoptions, STGOPTIONS **ppstgoptions);
|
||||
#endif
|
||||
PYCOM_EXPORT PyObject *PyCom_PyObjectFromSTATPROPSETSTG(STATPROPSETSTG *pStat);
|
||||
PYCOM_EXPORT BOOL PyCom_PyObjectAsSTATPROPSETSTG(PyObject *, STATPROPSETSTG *);
|
||||
|
||||
// Currency support.
|
||||
PYCOM_EXPORT PyObject *PyObject_FromCurrency(CURRENCY &cy);
|
||||
PYCOM_EXPORT BOOL PyObject_AsCurrency(PyObject *ob, CURRENCY *pcy);
|
||||
|
||||
// OLEMENUGROUPWIDTHS are used by axcontrol, shell, etc
|
||||
PYCOM_EXPORT BOOL PyObject_AsOLEMENUGROUPWIDTHS(PyObject *oblpMenuWidths, OLEMENUGROUPWIDTHS *pWidths);
|
||||
PYCOM_EXPORT PyObject *PyObject_FromOLEMENUGROUPWIDTHS(const OLEMENUGROUPWIDTHS *pWidths);
|
||||
|
||||
/* Functions for Initializing COM, and also letting the core know about it!
|
||||
*/
|
||||
PYCOM_EXPORT HRESULT PyCom_CoInitializeEx(LPVOID reserved, DWORD dwInit);
|
||||
PYCOM_EXPORT HRESULT PyCom_CoInitialize(LPVOID reserved);
|
||||
PYCOM_EXPORT void PyCom_CoUninitialize();
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Error related functions
|
||||
|
||||
// Client related functions - generally called by interfaces before
|
||||
// they return NULL back to Python to indicate the error.
|
||||
// All these functions return NULL so interfaces can generally
|
||||
// just "return PyCom_BuildPyException(hr, punk, IID_IWhatever)"
|
||||
|
||||
// Uses the HRESULT, and IErrorInfo interfaces if available to
|
||||
// create and set a pythoncom.com_error.
|
||||
PYCOM_EXPORT PyObject *PyCom_BuildPyException(HRESULT hr, IUnknown *pUnk = NULL, REFIID iid = IID_NULL);
|
||||
|
||||
// Uses the HRESULT and an EXCEPINFO structure to create and
|
||||
// set a pythoncom.com_error.
|
||||
PYCOM_EXPORT PyObject *PyCom_BuildPyExceptionFromEXCEPINFO(HRESULT hr, EXCEPINFO *pexcepInfo, UINT nArgErr = (UINT)-1);
|
||||
|
||||
// Sets a pythoncom.internal_error - no one should ever see these!
|
||||
PYCOM_EXPORT PyObject *PyCom_BuildInternalPyException(char *msg);
|
||||
|
||||
// Log an error to a Python logger object if one can be found, or
|
||||
// to stderr if no log available.
|
||||
// If logProvider is not NULL, we will call a "_GetLogger_()" method on it.
|
||||
// If logProvider is NULL, we attempt to fetch "win32com.logger".
|
||||
// If they do not exist, return None, or raise an error fetching them
|
||||
// (or even writing to them once fetched), the message still goes to stderr.
|
||||
// NOTE: By default, win32com does *not* provide a logger, so default is that
|
||||
// all errors are written to stdout.
|
||||
// This will *not* write a record if a COM Server error is current.
|
||||
PYCOM_EXPORT void PyCom_LoggerNonServerException(PyObject *logProvider, const char *fmt, ...);
|
||||
|
||||
// Write an error record, including exception. This will write an error
|
||||
// record even if a COM server error is current.
|
||||
PYCOM_EXPORT void PyCom_LoggerException(PyObject *logProvider, const char *fmt, ...);
|
||||
|
||||
// Write a warning record - in general this does *not* mean a call failed, but
|
||||
// still is something in the programmers control that they should change.
|
||||
// XXX - if an exception is pending when this is called, the traceback will
|
||||
// also be written. This is undesirable and will be changed should this
|
||||
// start being a problem.
|
||||
PYCOM_EXPORT void PyCom_LoggerWarning(PyObject *logProvider, const char *fmt, ...);
|
||||
|
||||
// Server related error functions
|
||||
// These are supplied so that any Python errors we detect can be
|
||||
// converted into COM error information. The HRESULT returned should
|
||||
// be returned by the COM function, and these functions also set the
|
||||
// IErrorInfo interfaces, so the caller can extract more detailed
|
||||
// information about the Python exception.
|
||||
|
||||
// Set a COM exception, logging the exception if not an explicitly raised 'server' exception
|
||||
PYCOM_EXPORT HRESULT PyCom_SetAndLogCOMErrorFromPyException(const char *methodName, REFIID riid /* = IID_NULL */);
|
||||
PYCOM_EXPORT HRESULT PyCom_SetAndLogCOMErrorFromPyExceptionEx(PyObject *provider, const char *methodName,
|
||||
REFIID riid /* = IID_NULL */);
|
||||
|
||||
// Used in gateways to SetErrorInfo() with a simple HRESULT, then return it.
|
||||
// The description is generally only useful for debugging purposes,
|
||||
// and if you are debugging via a server that supports IErrorInfo (like Python :-)
|
||||
// NOTE: this function is usuable from outside the Python context
|
||||
PYCOM_EXPORT HRESULT PyCom_SetCOMErrorFromSimple(HRESULT hr, REFIID riid = IID_NULL, const char *description = NULL);
|
||||
|
||||
// Used in gateways to SetErrorInfo() the current Python exception, and
|
||||
// (assuming not a server error explicitly raised) also logs an error
|
||||
// to stdout/win32com.logger.
|
||||
// NOTE: this function assumes GIL held
|
||||
PYCOM_EXPORT HRESULT PyCom_SetCOMErrorFromPyException(REFIID riid = IID_NULL);
|
||||
|
||||
// A couple of EXCEPINFO helpers - could be private to IDispatch
|
||||
// if it wasnt for the AXScript support (and ITypeInfo if we get around to that :-)
|
||||
// These functions do not set any error states to either Python or
|
||||
// COM - they simply convert to/from PyObjects and EXCEPINFOs
|
||||
|
||||
// Use the current Python exception to fill an EXCEPINFO structure.
|
||||
PYCOM_EXPORT void PyCom_ExcepInfoFromPyException(EXCEPINFO *pExcepInfo);
|
||||
|
||||
// Fill in an EXCEPINFO structure from a Python instance or tuple object.
|
||||
// (ie, similar to the above, except the Python exception object is specified,
|
||||
// rather than using the "current"
|
||||
PYCOM_EXPORT BOOL PyCom_ExcepInfoFromPyObject(PyObject *obExcepInfo, EXCEPINFO *pexcepInfo, HRESULT *phresult = NULL);
|
||||
|
||||
// Create a Python object holding the exception information. The exception
|
||||
// information is *not* freed by this function. Python exceptions are
|
||||
// raised and NULL is returned if an error occurs.
|
||||
PYCOM_EXPORT PyObject *PyCom_PyObjectFromExcepInfo(const EXCEPINFO *pexcepInfo);
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// External C++ helpers - these helpers are for other DLLs which
|
||||
// may need similar functionality, but dont want to duplicate all
|
||||
|
||||
// This helper is for an application that has an IDispatch, and COM arguments
|
||||
// and wants to call a Python function. It is assumed the caller can map the IDispatch
|
||||
// to a Python object, so the Python handler is passed.
|
||||
// Args:
|
||||
// handler : A Python callable object.
|
||||
// dispparms : the COM arguments.
|
||||
// pVarResult : The variant for the return value of the Python call.
|
||||
// pexcepinfo : Exception info the helper may fill out.
|
||||
// puArgErr : Argument error the helper may fill out on exception
|
||||
// addnArgs : Any additional arguments to the Python function. May be NULL.
|
||||
// If addnArgs is NULL, then it is assumed the Python call should be native -
|
||||
// ie, the COM args are packed as normal Python args to the call.
|
||||
// If addnArgs is NOT NULL, it is assumed the Python function itself is
|
||||
// a helper. This Python function will be called with 2 arguments - both
|
||||
// tuples - first one is the COM args, second is the addn args.
|
||||
PYCOM_EXPORT BOOL PyCom_MakeOlePythonCall(PyObject *handler, DISPPARAMS FAR *params, VARIANT FAR *pVarResult,
|
||||
EXCEPINFO FAR *pexcepinfo, UINT FAR *puArgErr, PyObject *addnlArgs);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Various special purpose singletons
|
||||
class PYCOM_EXPORT PyOleEmpty : public PyObject {
|
||||
public:
|
||||
PyOleEmpty();
|
||||
};
|
||||
|
||||
class PYCOM_EXPORT PyOleMissing : public PyObject {
|
||||
public:
|
||||
PyOleMissing();
|
||||
};
|
||||
|
||||
class PYCOM_EXPORT PyOleArgNotFound : public PyObject {
|
||||
public:
|
||||
PyOleArgNotFound();
|
||||
};
|
||||
|
||||
class PYCOM_EXPORT PyOleNothing : public PyObject {
|
||||
public:
|
||||
PyOleNothing();
|
||||
};
|
||||
|
||||
// We need to dynamically create C++ Python objects
|
||||
// These helpers allow each type object to create it.
|
||||
#define MAKE_PYCOM_CTOR(classname) \
|
||||
static PyIUnknown *classname::PyObConstruct(IUnknown *pInitObj) { return new classname(pInitObj); }
|
||||
#define MAKE_PYCOM_CTOR_ERRORINFO(classname, iid) \
|
||||
static PyIUnknown *classname::PyObConstruct(IUnknown *pInitObj) { return new classname(pInitObj); } \
|
||||
static PyObject *SetPythonCOMError(PyObject *self, HRESULT hr) \
|
||||
{ \
|
||||
return PyCom_BuildPyException(hr, GetI(self), iid); \
|
||||
}
|
||||
#define GET_PYCOM_CTOR(classname) classname::PyObConstruct
|
||||
|
||||
// Macros that interfaces should use. PY_INTERFACE_METHOD at the top of the method
|
||||
// The other 2 wrap directly around the underlying method call.
|
||||
#define PY_INTERFACE_METHOD
|
||||
// Identical to Py_BEGIN_ALLOW_THREADS except no { !!!
|
||||
#define PY_INTERFACE_PRECALL PyThreadState *_save = PyEval_SaveThread();
|
||||
#define PY_INTERFACE_POSTCALL PyEval_RestoreThread(_save);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyIUnknown
|
||||
class PYCOM_EXPORT PyIUnknown : public PyIBase {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyIUnknown);
|
||||
virtual PyObject *repr();
|
||||
virtual int compare(PyObject *other);
|
||||
|
||||
static IUnknown *GetI(PyObject *self);
|
||||
IUnknown *m_obj;
|
||||
static char *szErrMsgObjectReleased;
|
||||
static void SafeRelease(PyIUnknown *ob);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
static PyObject *QueryInterface(PyObject *self, PyObject *args);
|
||||
static PyObject *SafeRelease(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIUnknown(IUnknown *punk);
|
||||
~PyIUnknown();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyIDispatch
|
||||
|
||||
class PYCOM_EXPORT PyIDispatch : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyIDispatch);
|
||||
static IDispatch *GetI(PyObject *self);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
static PyObject *Invoke(PyObject *self, PyObject *args);
|
||||
static PyObject *InvokeTypes(PyObject *self, PyObject *args);
|
||||
static PyObject *GetIDsOfNames(PyObject *self, PyObject *args);
|
||||
static PyObject *GetTypeInfo(PyObject *self, PyObject *args);
|
||||
static PyObject *GetTypeInfoCount(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIDispatch(IUnknown *pdisp);
|
||||
~PyIDispatch();
|
||||
};
|
||||
|
||||
#ifndef NO_PYCOM_IDISPATCHEX
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyIDispatchEx
|
||||
|
||||
class PYCOM_EXPORT PyIDispatchEx : public PyIDispatch {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR_ERRORINFO(PyIDispatchEx, IID_IDispatchEx);
|
||||
static IDispatchEx *GetI(PyObject *self);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
static PyObject *GetDispID(PyObject *self, PyObject *args);
|
||||
static PyObject *InvokeEx(PyObject *self, PyObject *args);
|
||||
static PyObject *DeleteMemberByName(PyObject *self, PyObject *args);
|
||||
static PyObject *DeleteMemberByDispID(PyObject *self, PyObject *args);
|
||||
static PyObject *GetMemberProperties(PyObject *self, PyObject *args);
|
||||
static PyObject *GetMemberName(PyObject *self, PyObject *args);
|
||||
static PyObject *GetNextDispID(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIDispatchEx(IUnknown *pdisp);
|
||||
~PyIDispatchEx();
|
||||
};
|
||||
#endif // NO_PYCOM_IDISPATCHEX
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyIClassFactory
|
||||
|
||||
class PYCOM_EXPORT PyIClassFactory : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyIClassFactory);
|
||||
static IClassFactory *GetI(PyObject *self);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
static PyObject *CreateInstance(PyObject *self, PyObject *args);
|
||||
static PyObject *LockServer(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIClassFactory(IUnknown *pdisp);
|
||||
~PyIClassFactory();
|
||||
};
|
||||
|
||||
#ifndef NO_PYCOM_IPROVIDECLASSINFO
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyIProvideTypeInfo
|
||||
|
||||
class PYCOM_EXPORT PyIProvideClassInfo : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyIProvideClassInfo);
|
||||
static IProvideClassInfo *GetI(PyObject *self);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
static PyObject *GetClassInfo(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIProvideClassInfo(IUnknown *pdisp);
|
||||
~PyIProvideClassInfo();
|
||||
};
|
||||
|
||||
class PYCOM_EXPORT PyIProvideClassInfo2 : public PyIProvideClassInfo {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyIProvideClassInfo2);
|
||||
static IProvideClassInfo2 *GetI(PyObject *self);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
static PyObject *GetGUID(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIProvideClassInfo2(IUnknown *pdisp);
|
||||
~PyIProvideClassInfo2();
|
||||
};
|
||||
#endif // NO_PYCOM_IPROVIDECLASSINFO
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyITypeInfo
|
||||
class PYCOM_EXPORT PyITypeInfo : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyITypeInfo);
|
||||
static PyComTypeObject type;
|
||||
static ITypeInfo *GetI(PyObject *self);
|
||||
|
||||
PyObject *GetContainingTypeLib();
|
||||
PyObject *GetDocumentation(MEMBERID);
|
||||
PyObject *GetRefTypeInfo(HREFTYPE href);
|
||||
PyObject *GetRefTypeOfImplType(int index);
|
||||
PyObject *GetFuncDesc(int pos);
|
||||
PyObject *GetIDsOfNames(OLECHAR FAR *FAR *, int);
|
||||
PyObject *GetNames(MEMBERID);
|
||||
PyObject *GetTypeAttr();
|
||||
PyObject *GetVarDesc(int pos);
|
||||
PyObject *GetImplTypeFlags(int index);
|
||||
PyObject *GetTypeComp();
|
||||
|
||||
protected:
|
||||
PyITypeInfo(IUnknown *);
|
||||
~PyITypeInfo();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyITypeComp
|
||||
class PYCOM_EXPORT PyITypeComp : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyITypeComp);
|
||||
static PyComTypeObject type;
|
||||
static ITypeComp *GetI(PyObject *self);
|
||||
|
||||
PyObject *Bind(OLECHAR *szName, unsigned short wflags);
|
||||
PyObject *BindType(OLECHAR *szName);
|
||||
|
||||
protected:
|
||||
PyITypeComp(IUnknown *);
|
||||
~PyITypeComp();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class CPyTypeLib
|
||||
|
||||
class PYCOM_EXPORT PyITypeLib : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(PyITypeLib);
|
||||
static PyComTypeObject type;
|
||||
static ITypeLib *GetI(PyObject *self);
|
||||
|
||||
PyObject *GetLibAttr();
|
||||
PyObject *GetDocumentation(int pos);
|
||||
PyObject *GetTypeInfo(int pos);
|
||||
PyObject *GetTypeInfoCount();
|
||||
PyObject *GetTypeInfoOfGuid(REFGUID guid);
|
||||
PyObject *GetTypeInfoType(int pos);
|
||||
PyObject *GetTypeComp();
|
||||
|
||||
protected:
|
||||
PyITypeLib(IUnknown *);
|
||||
~PyITypeLib();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PyIConnectionPoint
|
||||
|
||||
class PYCOM_EXPORT PyIConnectionPoint : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR_ERRORINFO(PyIConnectionPoint, IID_IConnectionPoint);
|
||||
static PyComTypeObject type;
|
||||
static IConnectionPoint *GetI(PyObject *self);
|
||||
|
||||
static PyObject *GetConnectionInterface(PyObject *self, PyObject *args);
|
||||
static PyObject *GetConnectionPointContainer(PyObject *self, PyObject *args);
|
||||
static PyObject *Advise(PyObject *self, PyObject *args);
|
||||
static PyObject *Unadvise(PyObject *self, PyObject *args);
|
||||
static PyObject *EnumConnections(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIConnectionPoint(IUnknown *);
|
||||
~PyIConnectionPoint();
|
||||
};
|
||||
|
||||
class PYCOM_EXPORT PyIConnectionPointContainer : public PyIUnknown {
|
||||
public:
|
||||
MAKE_PYCOM_CTOR_ERRORINFO(PyIConnectionPointContainer, IID_IConnectionPointContainer);
|
||||
static PyComTypeObject type;
|
||||
static IConnectionPointContainer *GetI(PyObject *self);
|
||||
|
||||
static PyObject *EnumConnectionPoints(PyObject *self, PyObject *args);
|
||||
static PyObject *FindConnectionPoint(PyObject *self, PyObject *args);
|
||||
|
||||
protected:
|
||||
PyIConnectionPointContainer(IUnknown *);
|
||||
~PyIConnectionPointContainer();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// class PythonOleArgHelper
|
||||
//
|
||||
// A PythonOleArgHelper is used primarily to help out Python helpers
|
||||
// which need to convert from a Python object when the specific OLE
|
||||
// type is known - eg, when a TypeInfo is available.
|
||||
//
|
||||
// The type of conversion determines who owns what buffers etc. I wish BYREF didnt exist :-)
|
||||
typedef enum {
|
||||
// We dont know what sort of conversion it is yet.
|
||||
POAH_CONVERT_UNKNOWN,
|
||||
// A PyObject is given, we convert to a VARIANT, make the COM call, then BYREFs back to a PyObject
|
||||
// ie, this is typically a "normal" COM call, where Python initiates the call
|
||||
POAH_CONVERT_FROM_PYOBJECT,
|
||||
// A VARIANT is given, we convert to a PyObject, make the Python call, then BYREFs back to a VARIANT.
|
||||
// ie, this is typically handling a COM event, where COM itself initiates the call.
|
||||
POAH_CONVERT_FROM_VARIANT,
|
||||
} POAH_CONVERT_DIRECTION;
|
||||
|
||||
class PYCOM_EXPORT PythonOleArgHelper {
|
||||
public:
|
||||
PythonOleArgHelper();
|
||||
~PythonOleArgHelper();
|
||||
BOOL ParseTypeInformation(PyObject *reqdObjectTuple);
|
||||
|
||||
// Using this call with reqdObject != NULL will check the existing
|
||||
// VT_ of the variant. If not VT_EMPTY, then the result will be coerced to
|
||||
// that type. This contrasts with PyCom_PyObjectToVariant which just
|
||||
// uses the Python type to determine the variant type.
|
||||
BOOL MakeObjToVariant(PyObject *obj, VARIANT *var, PyObject *reqdObjectTuple = NULL);
|
||||
PyObject *MakeVariantToObj(VARIANT *var);
|
||||
|
||||
VARTYPE m_reqdType;
|
||||
BOOL m_bParsedTypeInfo;
|
||||
BOOL m_bIsOut;
|
||||
POAH_CONVERT_DIRECTION m_convertDirection;
|
||||
PyObject *m_pyVariant; // if non-null, a win32com.client.VARIANT
|
||||
union {
|
||||
void *m_pValueHolder;
|
||||
short m_sBuf;
|
||||
long m_lBuf;
|
||||
LONGLONG m_llBuf;
|
||||
VARIANT_BOOL m_boolBuf;
|
||||
double m_dBuf;
|
||||
float m_fBuf;
|
||||
IDispatch *m_dispBuf;
|
||||
IUnknown *m_unkBuf;
|
||||
SAFEARRAY *m_arrayBuf;
|
||||
VARIANT *m_varBuf;
|
||||
DATE m_dateBuf;
|
||||
CY m_cyBuf;
|
||||
};
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// global functions and variables
|
||||
PYCOM_EXPORT BOOL MakePythonArgumentTuples(PyObject **pArgs, PythonOleArgHelper **ppHelpers, PyObject **pNamedArgs,
|
||||
PythonOleArgHelper **ppNamedHelpers, DISPPARAMS FAR *params);
|
||||
|
||||
// Convert a Python object to a BSTR - allow embedded NULLs, None, etc.
|
||||
PYCOM_EXPORT BOOL PyCom_BstrFromPyObject(PyObject *stringObject, BSTR *pResult, BOOL bNoneOK = FALSE);
|
||||
|
||||
// MakeBstrToObj - convert a BSTR into a Python string.
|
||||
//
|
||||
// ONLY USE THIS FOR TRUE BSTR's - Use the fn below for OLECHAR *'s.
|
||||
// NOTE - does not use standard macros, so NULLs get through!
|
||||
PYCOM_EXPORT PyObject *MakeBstrToObj(const BSTR bstr);
|
||||
|
||||
// Size info is available (eg, a fn returns a string and also fills in a size variable)
|
||||
PYCOM_EXPORT PyObject *MakeOLECHARToObj(const OLECHAR *str, int numChars);
|
||||
|
||||
// No size info avail.
|
||||
PYCOM_EXPORT PyObject *MakeOLECHARToObj(const OLECHAR *str);
|
||||
|
||||
PYCOM_EXPORT void PyCom_LogF(const char *fmt, ...);
|
||||
|
||||
// Generic conversion from python sequence to VT_VECTOR array
|
||||
// Resulting array must be freed with CoTaskMemFree
|
||||
template <typename arraytype>
|
||||
BOOL SeqToVector(PyObject *ob, arraytype **pA, ULONG *pcount, BOOL (*converter)(PyObject *, arraytype *))
|
||||
{
|
||||
TmpPyObject seq = PyWinSequence_Tuple(ob, pcount);
|
||||
if (seq == NULL)
|
||||
return FALSE;
|
||||
*pA = (arraytype *)CoTaskMemAlloc(*pcount * sizeof(arraytype));
|
||||
if (*pA == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return FALSE;
|
||||
}
|
||||
for (ULONG i = 0; i < *pcount; i++) {
|
||||
PyObject *item = PyTuple_GET_ITEM((PyObject *)seq, i);
|
||||
if (!(*converter)(item, &(*pA)[i]))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif // __PYTHONCOM_H__
|
84
venv/Lib/site-packages/win32com/include/PythonCOMRegister.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Support for PythonCOM and its extensions to register the interfaces,
|
||||
// gateways and IIDs it supports.
|
||||
//
|
||||
// The module can simply declare an array of type PyCom_InterfaceSupportInfo, then
|
||||
// use the macros to populate it.
|
||||
//
|
||||
// See Register.cpp and AXScript.cpp for examples on its use.
|
||||
|
||||
#ifndef __PYTHONCOMREGISTER_H__
|
||||
#define __PYTHONCOMREGISTER_H__
|
||||
|
||||
#include "PythonCOMServer.h" // Need defns in this file...
|
||||
|
||||
typedef struct {
|
||||
const GUID *pGUID; // The supported IID - required
|
||||
const char *interfaceName; // Name of the interface - required
|
||||
const char *iidName; // Name of the IID that goes into the dict. - required
|
||||
PyTypeObject *pTypeOb; // the type object for client PyI* side - NULL for server only support.
|
||||
pfnPyGatewayConstructor ctor; // Gateway (PyG*) interface constructor - NULL for client only support
|
||||
|
||||
} PyCom_InterfaceSupportInfo;
|
||||
|
||||
#define PYCOM_INTERFACE_IID_ONLY(ifc) \
|
||||
{ \
|
||||
&IID_I##ifc, "I" #ifc, "IID_I" #ifc, NULL, NULL \
|
||||
}
|
||||
#define PYCOM_INTERFACE_CLSID_ONLY(ifc) \
|
||||
{ \
|
||||
&CLSID_##ifc, "CLSID_" #ifc, "CLSID_" #ifc, NULL, NULL \
|
||||
}
|
||||
#define PYCOM_INTERFACE_CATID_ONLY(ifc) \
|
||||
{ \
|
||||
&CATID_##ifc, "CATID_" #ifc, "CATID_" #ifc, NULL, NULL \
|
||||
}
|
||||
#define PYCOM_INTERFACE_CLIENT_ONLY(ifc) \
|
||||
{ \
|
||||
&IID_I##ifc, "I" #ifc, "IID_I" #ifc, &PyI##ifc::type, NULL \
|
||||
}
|
||||
#define PYCOM_INTERFACE_SERVER_ONLY(ifc) \
|
||||
{ \
|
||||
&IID_I##ifc, "I" #ifc, "IID_I" #ifc, NULL, GET_PYGATEWAY_CTOR(PyG##ifc) \
|
||||
}
|
||||
#define PYCOM_INTERFACE_FULL(ifc) \
|
||||
{ \
|
||||
&IID_I##ifc, "I" #ifc, "IID_I" #ifc, &PyI##ifc::type, GET_PYGATEWAY_CTOR(PyG##ifc) \
|
||||
}
|
||||
|
||||
// Versions that use __uuidof() to get the IID, which seems to avoid the need
|
||||
// to link with a lib holding the IIDs. Note that almost all extensions
|
||||
// build with __uuidof() being the default; the build failed at 'shell' - so
|
||||
// we could consider making this the default and making the 'explicit' version
|
||||
// above the special case.
|
||||
#define PYCOM_INTERFACE_IID_ONLY_UUIDOF(ifc) \
|
||||
{ \
|
||||
&__uuidof(I##ifc), "I" #ifc, "IID_I" #ifc, NULL, NULL \
|
||||
}
|
||||
#define PYCOM_INTERFACE_CLIENT_ONLY_UUIDOF(ifc) \
|
||||
{ \
|
||||
&__uuidof(I##ifc), "I" #ifc, "IID_I" #ifc, &PyI##ifc::type, NULL \
|
||||
}
|
||||
#define PYCOM_INTERFACE_SERVER_ONLY_UUIDOF(ifc) \
|
||||
{ \
|
||||
&__uuidof(I##ifc), "I" #ifc, "IID_I" #ifc, NULL, GET_PYGATEWAY_CTOR(PyG##ifc) \
|
||||
}
|
||||
#define PYCOM_INTERFACE_FULL_UUIDOF(ifc) \
|
||||
{ \
|
||||
&__uuidof(I##ifc), "I" #ifc, "IID_I" #ifc, &PyI##ifc::type, GET_PYGATEWAY_CTOR(PyG##ifc) \
|
||||
}
|
||||
|
||||
// Prototypes for the register functions
|
||||
|
||||
// Register a PythonCOM extension module
|
||||
PYCOM_EXPORT int PyCom_RegisterExtensionSupport(PyObject *dict, const PyCom_InterfaceSupportInfo *pInterfaces,
|
||||
int numEntries);
|
||||
|
||||
// THESE SHOULD NO LONGER BE USED. Instead, use the functions above passing an
|
||||
// array of PyCom_InterfaceSupportInfo objects.
|
||||
|
||||
PYCOM_EXPORT int PyCom_RegisterClientType(PyTypeObject *typeOb, const GUID *guid);
|
||||
|
||||
HRESULT PYCOM_EXPORT PyCom_RegisterGatewayObject(REFIID iid, pfnPyGatewayConstructor ctor, const char *interfaceName);
|
||||
PYCOM_EXPORT int PyCom_IsGatewayRegistered(REFIID iid);
|
||||
|
||||
#endif /* __PYTHONCOMREGISTER_H__ */
|
176
venv/Lib/site-packages/win32com/include/PythonCOMServer.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
#ifndef __PYTHONCOMSERVER_H__
|
||||
#define __PYTHONCOMSERVER_H__
|
||||
|
||||
// PythonCOMServer.h :Server side COM support
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#define DLLAcquireGlobalLock PyWin_AcquireGlobalLock
|
||||
#define DLLReleaseGlobalLock PyWin_ReleaseGlobalLock
|
||||
|
||||
void PYCOM_EXPORT PyCom_DLLAddRef(void);
|
||||
void PYCOM_EXPORT PyCom_DLLReleaseRef(void);
|
||||
|
||||
// Use this macro at the start of all gateway methods.
|
||||
#define PY_GATEWAY_METHOD CEnterLeavePython _celp
|
||||
|
||||
class PyGatewayBase;
|
||||
// Gateway constructors.
|
||||
// Each gateway must be able to be created from a "gateway constructor". This
|
||||
// is simply a function that takes a Python instance as as argument, and returns
|
||||
// a gateway object of the correct type. The MAKE_PYGATEWAY_CTOR is a helper that
|
||||
// will embed such a constructor in the class - however, this is not necessary -
|
||||
// _any_ function of the correct signature can be used.
|
||||
|
||||
typedef HRESULT (*pfnPyGatewayConstructor)(PyObject *PythonInstance, PyGatewayBase *, void **ppResult, REFIID iid);
|
||||
HRESULT PyCom_MakeRegisteredGatewayObject(REFIID iid, PyObject *instance, PyGatewayBase *base, void **ppv);
|
||||
|
||||
// A version of the above which support classes being derived from
|
||||
// other than IUnknown
|
||||
#define PYGATEWAY_MAKE_SUPPORT2(classname, IInterface, theIID, gatewaybaseclass) \
|
||||
public: \
|
||||
static HRESULT classname::PyGatewayConstruct(PyObject *pPyInstance, PyGatewayBase *unkBase, void **ppResult, \
|
||||
REFIID iid) \
|
||||
{ \
|
||||
if (ppResult == NULL) \
|
||||
return E_INVALIDARG; \
|
||||
classname *newob = new classname(pPyInstance); \
|
||||
newob->m_pBaseObject = unkBase; \
|
||||
if (unkBase) \
|
||||
unkBase->AddRef(); \
|
||||
*ppResult = newob->ThisAsIID(iid); \
|
||||
return *ppResult ? S_OK : E_OUTOFMEMORY; \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
virtual IID GetIID(void) { return theIID; } \
|
||||
virtual void *ThisAsIID(IID iid) \
|
||||
{ \
|
||||
if (this == NULL) \
|
||||
return NULL; \
|
||||
if (iid == theIID) \
|
||||
return (IInterface *)this; \
|
||||
else \
|
||||
return gatewaybaseclass::ThisAsIID(iid); \
|
||||
} \
|
||||
STDMETHOD_(ULONG, AddRef)(void) { return gatewaybaseclass::AddRef(); } \
|
||||
STDMETHOD_(ULONG, Release)(void) { return gatewaybaseclass::Release(); } \
|
||||
STDMETHOD(QueryInterface)(REFIID iid, void **obj) { return gatewaybaseclass::QueryInterface(iid, obj); };
|
||||
|
||||
// This is the "old" version to use, or use it if you derive
|
||||
// directly from PyGatewayBase
|
||||
#define PYGATEWAY_MAKE_SUPPORT(classname, IInterface, theIID) \
|
||||
PYGATEWAY_MAKE_SUPPORT2(classname, IInterface, theIID, PyGatewayBase)
|
||||
|
||||
#define GET_PYGATEWAY_CTOR(classname) classname::PyGatewayConstruct
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable an OK warning...
|
||||
#pragma warning(disable : 4275)
|
||||
// warning C4275: non dll-interface struct 'IDispatch' used as base for dll-interface class 'PyGatewayBase'
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Helper interface for fetching a Python object from a gateway
|
||||
|
||||
extern const GUID IID_IInternalUnwrapPythonObject;
|
||||
|
||||
interface IInternalUnwrapPythonObject : public IUnknown
|
||||
{
|
||||
public:
|
||||
STDMETHOD(Unwrap)(PyObject * *ppPyObject) = 0;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// PyGatewayBase
|
||||
//
|
||||
// Base class for all gateways.
|
||||
//
|
||||
class PYCOM_EXPORT PyGatewayBase :
|
||||
#ifndef NO_PYCOM_IDISPATCHEX
|
||||
public IDispatchEx, // IDispatch comes along for the ride!
|
||||
#else
|
||||
public IDispatch, // No IDispatchEx - must explicitely use IDispatch
|
||||
#endif
|
||||
public ISupportErrorInfo,
|
||||
public IInternalUnwrapPythonObject {
|
||||
protected:
|
||||
PyGatewayBase(PyObject *instance);
|
||||
virtual ~PyGatewayBase();
|
||||
|
||||
// Invoke the Python method (via the policy object)
|
||||
STDMETHOD(InvokeViaPolicy)(const char *szMethodName, PyObject **ppResult = NULL, const char *szFormat = NULL, ...);
|
||||
|
||||
public:
|
||||
// IUnknown
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
STDMETHOD(QueryInterface)(REFIID iid, void **obj);
|
||||
|
||||
// IDispatch
|
||||
STDMETHOD(GetTypeInfoCount)(UINT FAR *pctInfo);
|
||||
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo FAR *FAR *pptInfo);
|
||||
STDMETHOD(GetIDsOfNames)(REFIID refiid, OLECHAR FAR *FAR *rgszNames, UINT cNames, LCID lcid, DISPID FAR *rgdispid);
|
||||
STDMETHOD(Invoke)
|
||||
(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *params, VARIANT FAR *pVarResult,
|
||||
EXCEPINFO FAR *pexcepinfo, UINT FAR *puArgErr);
|
||||
|
||||
// IDispatchEx
|
||||
#ifndef NO_PYCOM_IDISPATCHEX
|
||||
STDMETHOD(GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid);
|
||||
STDMETHOD(InvokeEx)
|
||||
(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller);
|
||||
STDMETHOD(DeleteMemberByName)(BSTR bstr, DWORD grfdex);
|
||||
STDMETHOD(DeleteMemberByDispID)(DISPID id);
|
||||
STDMETHOD(GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex);
|
||||
STDMETHOD(GetMemberName)(DISPID id, BSTR *pbstrName);
|
||||
STDMETHOD(GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid);
|
||||
STDMETHOD(GetNameSpaceParent)(IUnknown **ppunk);
|
||||
#endif // NO_PYCOM_IDISPATCHEX
|
||||
// ISupportErrorInfo
|
||||
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
|
||||
|
||||
// IInternalUnwrapPythonObject
|
||||
STDMETHOD(Unwrap)(PyObject **ppPyObject);
|
||||
|
||||
// Basically just PYGATEWAY_MAKE_SUPPORT(PyGatewayBase, IDispatch, IID_IDispatch);
|
||||
// but with special handling as its the base class.
|
||||
static HRESULT PyGatewayBase::PyGatewayConstruct(PyObject *pPyInstance, PyGatewayBase *gatewayBase, void **ppResult,
|
||||
REFIID iid)
|
||||
{
|
||||
if (ppResult == NULL)
|
||||
return E_INVALIDARG;
|
||||
PyGatewayBase *obNew = new PyGatewayBase(pPyInstance);
|
||||
obNew->m_pBaseObject = gatewayBase;
|
||||
if (gatewayBase)
|
||||
gatewayBase->AddRef();
|
||||
*ppResult = (IDispatch *)obNew;
|
||||
return *ppResult ? S_OK : E_OUTOFMEMORY;
|
||||
}
|
||||
// Currently this is used only for ISupportErrorInfo,
|
||||
// so hopefully this will never be called in this base class.
|
||||
// (however, this is not a rule, so we wont assert or anything!)
|
||||
virtual IID GetIID(void) { return IID_IUnknown; }
|
||||
virtual void *ThisAsIID(IID iid);
|
||||
// End of PYGATEWAY_MAKE_SUPPORT
|
||||
PyObject *m_pPyObject;
|
||||
PyGatewayBase *m_pBaseObject;
|
||||
|
||||
private:
|
||||
LONG m_cRef;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(default : 4275)
|
||||
#endif // _MSC_VER
|
||||
|
||||
// B/W compat hack for gateways.
|
||||
#define PyCom_HandlePythonFailureToCOM() \
|
||||
PyCom_SetAndLogCOMErrorFromPyExceptionEx(this->m_pPyObject, "<unknown>", GetIID())
|
||||
|
||||
// F/W compat hack for gateways! Must be careful about updating
|
||||
// PyGatewayBase vtable, so a slightly older pythoncomXX.dll will work
|
||||
// with slightly later extensions. So use a #define.
|
||||
#define MAKE_PYCOM_GATEWAY_FAILURE_CODE(method_name) \
|
||||
PyCom_SetAndLogCOMErrorFromPyExceptionEx(this->m_pPyObject, method_name, GetIID())
|
||||
|
||||
#endif /* __PYTHONCOMSERVER_H__ */
|
BIN
venv/Lib/site-packages/win32com/libs/axscript.lib
Normal file
BIN
venv/Lib/site-packages/win32com/libs/pythoncom.lib
Normal file
1
venv/Lib/site-packages/win32com/makegw/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# indicates a python package.
|
451
venv/Lib/site-packages/win32com/makegw/makegw.py
Normal file
|
@ -0,0 +1,451 @@
|
|||
"""Utility functions for writing out gateway C++ files
|
||||
|
||||
This module will generate a C++/Python binding for a specific COM
|
||||
interface.
|
||||
|
||||
At this stage, no command line interface exists. You must start Python,
|
||||
import this module, change to the directory where the generated code should
|
||||
be written, and run the public function.
|
||||
|
||||
This module is capable of generating both 'Interfaces' (ie, Python
|
||||
client side support for the interface) and 'Gateways' (ie, Python
|
||||
server side support for the interface). Many COM interfaces are useful
|
||||
both as Client and Server. Other interfaces, however, really only make
|
||||
sense to implement one side or the other. For example, it would be pointless
|
||||
for Python to implement Server side for 'IRunningObjectTable', unless we were
|
||||
implementing core COM for an operating system in Python (hey - now there's an idea!)
|
||||
|
||||
Most COM interface code is totally boiler-plate - it consists of
|
||||
converting arguments, dispatching the call to Python, and processing
|
||||
any result values.
|
||||
|
||||
This module automates the generation of such code. It has the ability to
|
||||
parse a .H file generated by the MIDL tool (ie, almost all COM .h files)
|
||||
and build almost totally complete C++ code.
|
||||
|
||||
The module understands some of the well known data types, and how to
|
||||
convert them. There are only a couple of places where hand-editing is
|
||||
necessary, as detailed below:
|
||||
|
||||
unsupported types -- If a type is not known, the generator will
|
||||
pretty much ignore it, but write a comment to the generated code. You
|
||||
may want to add custom support for this type. In some cases, C++ compile errors
|
||||
will result. These are intentional - generating code to remove these errors would
|
||||
imply a false sense of security that the generator has done the right thing.
|
||||
|
||||
other return policies -- By default, Python never sees the return SCODE from
|
||||
a COM function. The interface usually returns None if OK, else a COM exception
|
||||
if "FAILED(scode)" is TRUE. You may need to change this if:
|
||||
* EXCEPINFO is passed to the COM function. This is not detected and handled
|
||||
* For some reason Python should always see the result SCODE, even if it
|
||||
did fail or succeed. For example, some functions return a BOOLEAN result
|
||||
in the SCODE, meaning Python should always see it.
|
||||
* FAILED(scode) for the interface still has valid data to return (by default,
|
||||
the code generated does not process the return values, and raise an exception
|
||||
to Python/COM
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
from . import makegwparse
|
||||
|
||||
def make_framework_support(header_file_name, interface_name, bMakeInterface = 1, bMakeGateway = 1):
|
||||
"""Generate C++ code for a Python Interface and Gateway
|
||||
|
||||
header_file_name -- The full path to the .H file which defines the interface.
|
||||
interface_name -- The name of the interface to search for, and to generate.
|
||||
bMakeInterface = 1 -- Should interface (ie, client) support be generated.
|
||||
bMakeGatewayInterface = 1 -- Should gateway (ie, server) support be generated.
|
||||
|
||||
This method will write a .cpp and .h file into the current directory,
|
||||
(using the name of the interface to build the file name.
|
||||
|
||||
"""
|
||||
fin=open(header_file_name)
|
||||
try:
|
||||
interface = makegwparse.parse_interface_info(interface_name, fin)
|
||||
finally:
|
||||
fin.close()
|
||||
|
||||
if bMakeInterface and bMakeGateway:
|
||||
desc = "Interface and Gateway"
|
||||
elif bMakeInterface and not bMakeGateway:
|
||||
desc = "Interface"
|
||||
else:
|
||||
desc = "Gateway"
|
||||
if interface.name[:5]=="IEnum": # IEnum - use my really simple template-based one
|
||||
import win32com.makegw.makegwenum
|
||||
ifc_cpp_writer = win32com.makegw.makegwenum._write_enumifc_cpp
|
||||
gw_cpp_writer = win32com.makegw.makegwenum._write_enumgw_cpp
|
||||
else: # Use my harder working ones.
|
||||
ifc_cpp_writer = _write_ifc_cpp
|
||||
gw_cpp_writer = _write_gw_cpp
|
||||
|
||||
fout=open("Py%s.cpp" % interface.name, "w")
|
||||
try:
|
||||
fout.write(\
|
||||
'''\
|
||||
// This file implements the %s %s for Python.
|
||||
// Generated by makegw.py
|
||||
|
||||
#include "shell_pch.h"
|
||||
''' % (interface.name, desc))
|
||||
# if bMakeGateway:
|
||||
# fout.write('#include "PythonCOMServer.h"\n')
|
||||
# if interface.base not in ["IUnknown", "IDispatch"]:
|
||||
# fout.write('#include "Py%s.h"\n' % interface.base)
|
||||
fout.write('#include "Py%s.h"\n\n// @doc - This file contains autoduck documentation\n' % interface.name)
|
||||
if bMakeInterface: ifc_cpp_writer(fout, interface)
|
||||
if bMakeGateway: gw_cpp_writer(fout, interface)
|
||||
finally:
|
||||
fout.close()
|
||||
fout=open("Py%s.h" % interface.name, "w")
|
||||
try:
|
||||
fout.write(\
|
||||
'''\
|
||||
// This file declares the %s %s for Python.
|
||||
// Generated by makegw.py
|
||||
''' % (interface.name, desc))
|
||||
|
||||
if bMakeInterface: _write_ifc_h(fout, interface)
|
||||
if bMakeGateway: _write_gw_h(fout, interface)
|
||||
finally:
|
||||
fout.close()
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# INTERNAL FUNCTIONS
|
||||
#
|
||||
#
|
||||
|
||||
def _write_ifc_h(f, interface):
|
||||
f.write(\
|
||||
'''\
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Interface Declaration
|
||||
|
||||
class Py%s : public Py%s
|
||||
{
|
||||
public:
|
||||
MAKE_PYCOM_CTOR(Py%s);
|
||||
static %s *GetI(PyObject *self);
|
||||
static PyComTypeObject type;
|
||||
|
||||
// The Python methods
|
||||
''' % (interface.name, interface.base, interface.name, interface.name))
|
||||
for method in interface.methods:
|
||||
f.write('\tstatic PyObject *%s(PyObject *self, PyObject *args);\n' % method.name)
|
||||
f.write(\
|
||||
'''\
|
||||
|
||||
protected:
|
||||
Py%s(IUnknown *pdisp);
|
||||
~Py%s();
|
||||
};
|
||||
''' % (interface.name, interface.name))
|
||||
|
||||
def _write_ifc_cpp(f, interface):
|
||||
name = interface.name
|
||||
f.write(\
|
||||
'''\
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Interface Implementation
|
||||
|
||||
Py%(name)s::Py%(name)s(IUnknown *pdisp):
|
||||
Py%(base)s(pdisp)
|
||||
{
|
||||
ob_type = &type;
|
||||
}
|
||||
|
||||
Py%(name)s::~Py%(name)s()
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ %(name)s *Py%(name)s::GetI(PyObject *self)
|
||||
{
|
||||
return (%(name)s *)Py%(base)s::GetI(self);
|
||||
}
|
||||
|
||||
''' % (interface.__dict__))
|
||||
|
||||
ptr = re.sub('[a-z]', '', interface.name)
|
||||
strdict = {'interfacename':interface.name, 'ptr': ptr}
|
||||
for method in interface.methods:
|
||||
strdict['method'] = method.name
|
||||
f.write(\
|
||||
'''\
|
||||
// @pymethod |Py%(interfacename)s|%(method)s|Description of %(method)s.
|
||||
PyObject *Py%(interfacename)s::%(method)s(PyObject *self, PyObject *args)
|
||||
{
|
||||
%(interfacename)s *p%(ptr)s = GetI(self);
|
||||
if ( p%(ptr)s == NULL )
|
||||
return NULL;
|
||||
''' % strdict)
|
||||
argsParseTuple = argsCOM = formatChars = codePost = \
|
||||
codePobjects = codeCobjects = cleanup = cleanup_gil = ""
|
||||
needConversion = 0
|
||||
# if method.name=="Stat": import win32dbg;win32dbg.brk()
|
||||
for arg in method.args:
|
||||
try:
|
||||
argCvt = makegwparse.make_arg_converter(arg)
|
||||
if arg.HasAttribute("in"):
|
||||
val = argCvt.GetFormatChar()
|
||||
if val:
|
||||
f.write ('\t' + argCvt.GetAutoduckString() + "\n")
|
||||
formatChars = formatChars + val
|
||||
argsParseTuple = argsParseTuple + ", " + argCvt.GetParseTupleArg()
|
||||
codePobjects = codePobjects + argCvt.DeclareParseArgTupleInputConverter()
|
||||
codePost = codePost + argCvt.GetParsePostCode()
|
||||
needConversion = needConversion or argCvt.NeedUSES_CONVERSION()
|
||||
cleanup = cleanup + argCvt.GetInterfaceArgCleanup()
|
||||
cleanup_gil = cleanup_gil + argCvt.GetInterfaceArgCleanupGIL()
|
||||
comArgName, comArgDeclString = argCvt.GetInterfaceCppObjectInfo()
|
||||
if comArgDeclString: # If we should declare a variable
|
||||
codeCobjects = codeCobjects + "\t%s;\n" % (comArgDeclString)
|
||||
argsCOM = argsCOM + ", " + comArgName
|
||||
except makegwparse.error_not_supported as why:
|
||||
f.write('// *** The input argument %s of type "%s" was not processed ***\n// Please check the conversion function is appropriate and exists!\n' % (arg.name, arg.raw_type))
|
||||
|
||||
f.write('\t%s %s;\n\tPyObject *ob%s;\n' % (arg.type, arg.name, arg.name))
|
||||
f.write('\t// @pyparm <o Py%s>|%s||Description for %s\n' % (arg.type, arg.name, arg.name))
|
||||
codePost = codePost + '\tif (bPythonIsHappy && !PyObject_As%s( ob%s, &%s )) bPythonIsHappy = FALSE;\n' % (arg.type, arg.name, arg.name)
|
||||
|
||||
formatChars = formatChars + "O"
|
||||
argsParseTuple = argsParseTuple + ", &ob%s" % (arg.name)
|
||||
|
||||
argsCOM = argsCOM + ", " + arg.name
|
||||
cleanup = cleanup + "\tPyObject_Free%s(%s);\n" % (arg.type, arg.name)
|
||||
|
||||
if needConversion: f.write("\tUSES_CONVERSION;\n")
|
||||
f.write(codePobjects);
|
||||
f.write(codeCobjects);
|
||||
f.write('\tif ( !PyArg_ParseTuple(args, "%s:%s"%s) )\n\t\treturn NULL;\n' % (formatChars, method.name, argsParseTuple))
|
||||
if codePost:
|
||||
f.write('\tBOOL bPythonIsHappy = TRUE;\n')
|
||||
f.write(codePost);
|
||||
f.write('\tif (!bPythonIsHappy) return NULL;\n')
|
||||
strdict['argsCOM'] = argsCOM[1:]
|
||||
strdict['cleanup'] = cleanup
|
||||
strdict['cleanup_gil'] = cleanup_gil
|
||||
f.write(\
|
||||
''' HRESULT hr;
|
||||
PY_INTERFACE_PRECALL;
|
||||
hr = p%(ptr)s->%(method)s(%(argsCOM)s );
|
||||
%(cleanup)s
|
||||
PY_INTERFACE_POSTCALL;
|
||||
%(cleanup_gil)s
|
||||
if ( FAILED(hr) )
|
||||
return PyCom_BuildPyException(hr, p%(ptr)s, IID_%(interfacename)s );
|
||||
''' % strdict)
|
||||
codePre = codePost = formatChars = codeVarsPass = codeDecl = ""
|
||||
for arg in method.args:
|
||||
if not arg.HasAttribute("out"):
|
||||
continue
|
||||
try:
|
||||
argCvt = makegwparse.make_arg_converter(arg)
|
||||
formatChar = argCvt.GetFormatChar()
|
||||
if formatChar:
|
||||
formatChars = formatChars + formatChar
|
||||
codePre = codePre + argCvt.GetBuildForInterfacePreCode()
|
||||
codePost = codePost + argCvt.GetBuildForInterfacePostCode()
|
||||
codeVarsPass = codeVarsPass + ", " + argCvt.GetBuildValueArg()
|
||||
codeDecl = codeDecl + argCvt.DeclareParseArgTupleInputConverter()
|
||||
except makegwparse.error_not_supported as why:
|
||||
f.write('// *** The output argument %s of type "%s" was not processed ***\n// %s\n' % (arg.name, arg.raw_type, why))
|
||||
continue
|
||||
if formatChars:
|
||||
f.write('%s\n%s\tPyObject *pyretval = Py_BuildValue("%s"%s);\n%s\treturn pyretval;' % (codeDecl, codePre, formatChars, codeVarsPass, codePost))
|
||||
else:
|
||||
f.write('\tPy_INCREF(Py_None);\n\treturn Py_None;\n')
|
||||
f.write('\n}\n\n')
|
||||
|
||||
f.write ('// @object Py%s|Description of the interface\n' % (name))
|
||||
f.write('static struct PyMethodDef Py%s_methods[] =\n{\n' % name)
|
||||
for method in interface.methods:
|
||||
f.write('\t{ "%s", Py%s::%s, 1 }, // @pymeth %s|Description of %s\n' % (method.name, interface.name, method.name, method.name, method.name))
|
||||
|
||||
interfacebase = interface.base
|
||||
f.write('''\
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
PyComTypeObject Py%(name)s::type("Py%(name)s",
|
||||
&Py%(interfacebase)s::type,
|
||||
sizeof(Py%(name)s),
|
||||
Py%(name)s_methods,
|
||||
GET_PYCOM_CTOR(Py%(name)s));
|
||||
''' % locals())
|
||||
|
||||
def _write_gw_h(f, interface):
|
||||
if interface.name[0] == "I":
|
||||
gname = 'PyG' + interface.name[1:]
|
||||
else:
|
||||
gname = 'PyG' + interface.name
|
||||
name = interface.name
|
||||
if interface.base == "IUnknown" or interface.base == "IDispatch":
|
||||
base_name = "PyGatewayBase"
|
||||
else:
|
||||
if interface.base[0] == "I":
|
||||
base_name = 'PyG' + interface.base[1:]
|
||||
else:
|
||||
base_name = 'PyG' + interface.base
|
||||
f.write(\
|
||||
'''\
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Gateway Declaration
|
||||
|
||||
class %s : public %s, public %s
|
||||
{
|
||||
protected:
|
||||
%s(PyObject *instance) : %s(instance) { ; }
|
||||
PYGATEWAY_MAKE_SUPPORT2(%s, %s, IID_%s, %s)
|
||||
|
||||
''' % (gname, base_name, name, gname, base_name, gname, name, name, base_name))
|
||||
if interface.base != "IUnknown":
|
||||
f.write("\t// %s\n\t// *** Manually add %s method decls here\n\n" % (interface.base, interface.base))
|
||||
else:
|
||||
f.write('\n\n')
|
||||
|
||||
f.write("\t// %s\n" % name)
|
||||
|
||||
for method in interface.methods:
|
||||
f.write('\tSTDMETHOD(%s)(\n' % method.name)
|
||||
if method.args:
|
||||
for arg in method.args[:-1]:
|
||||
f.write("\t\t%s,\n" % (arg.GetRawDeclaration()))
|
||||
arg = method.args[-1]
|
||||
f.write("\t\t%s);\n\n" % (arg.GetRawDeclaration()))
|
||||
else:
|
||||
f.write('\t\tvoid);\n\n')
|
||||
|
||||
f.write('};\n')
|
||||
f.close()
|
||||
|
||||
def _write_gw_cpp(f, interface):
|
||||
if interface.name[0] == "I":
|
||||
gname = 'PyG' + interface.name[1:]
|
||||
else:
|
||||
gname = 'PyG' + interface.name
|
||||
name = interface.name
|
||||
if interface.base == "IUnknown" or interface.base == "IDispatch":
|
||||
base_name = "PyGatewayBase"
|
||||
else:
|
||||
if interface.base[0] == "I":
|
||||
base_name = 'PyG' + interface.base[1:]
|
||||
else:
|
||||
base_name = 'PyG' + interface.base
|
||||
f.write('''\
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Gateway Implementation
|
||||
''' % {'name':name, 'gname':gname, 'base_name':base_name})
|
||||
|
||||
for method in interface.methods:
|
||||
f.write(\
|
||||
'''\
|
||||
STDMETHODIMP %s::%s(
|
||||
''' % (gname, method.name))
|
||||
|
||||
if method.args:
|
||||
for arg in method.args[:-1]:
|
||||
inoutstr = ']['.join(arg.inout)
|
||||
f.write("\t\t/* [%s] */ %s,\n" % (inoutstr, arg.GetRawDeclaration()))
|
||||
|
||||
arg = method.args[-1]
|
||||
inoutstr = ']['.join(arg.inout)
|
||||
f.write("\t\t/* [%s] */ %s)\n" % (inoutstr, arg.GetRawDeclaration()))
|
||||
else:
|
||||
f.write('\t\tvoid)\n')
|
||||
|
||||
f.write("{\n\tPY_GATEWAY_METHOD;\n")
|
||||
cout = 0
|
||||
codePre = codePost = codeVars = ""
|
||||
argStr = ""
|
||||
needConversion = 0
|
||||
formatChars = ""
|
||||
if method.args:
|
||||
for arg in method.args:
|
||||
if arg.HasAttribute("out"):
|
||||
cout = cout + 1
|
||||
if arg.indirectionLevel ==2 :
|
||||
f.write("\tif (%s==NULL) return E_POINTER;\n" % arg.name)
|
||||
if arg.HasAttribute("in"):
|
||||
try:
|
||||
argCvt = makegwparse.make_arg_converter(arg)
|
||||
argCvt.SetGatewayMode()
|
||||
formatchar = argCvt.GetFormatChar();
|
||||
needConversion = needConversion or argCvt.NeedUSES_CONVERSION()
|
||||
|
||||
if formatchar:
|
||||
formatChars = formatChars + formatchar
|
||||
codeVars = codeVars + argCvt.DeclareParseArgTupleInputConverter()
|
||||
argStr = argStr + ", " + argCvt.GetBuildValueArg()
|
||||
codePre = codePre + argCvt.GetBuildForGatewayPreCode()
|
||||
codePost = codePost + argCvt.GetBuildForGatewayPostCode()
|
||||
except makegwparse.error_not_supported as why:
|
||||
f.write('// *** The input argument %s of type "%s" was not processed ***\n// - Please ensure this conversion function exists, and is appropriate\n// - %s\n' % (arg.name, arg.raw_type, why))
|
||||
f.write('\tPyObject *ob%s = PyObject_From%s(%s);\n' % (arg.name, arg.type, arg.name))
|
||||
f.write('\tif (ob%s==NULL) return MAKE_PYCOM_GATEWAY_FAILURE_CODE("%s");\n' % (arg.name, method.name))
|
||||
codePost = codePost + "\tPy_DECREF(ob%s);\n" % arg.name
|
||||
formatChars = formatChars + "O"
|
||||
argStr = argStr + ", ob%s" % (arg.name)
|
||||
|
||||
if needConversion: f.write('\tUSES_CONVERSION;\n')
|
||||
f.write(codeVars)
|
||||
f.write(codePre)
|
||||
if cout:
|
||||
f.write("\tPyObject *result;\n")
|
||||
resStr = "&result"
|
||||
else:
|
||||
resStr = "NULL"
|
||||
|
||||
if formatChars:
|
||||
fullArgStr = '%s, "%s"%s' % (resStr, formatChars, argStr)
|
||||
else:
|
||||
fullArgStr = resStr
|
||||
|
||||
f.write('\tHRESULT hr=InvokeViaPolicy("%s", %s);\n' % (method.name, fullArgStr))
|
||||
f.write(codePost)
|
||||
if cout:
|
||||
f.write("\tif (FAILED(hr)) return hr;\n")
|
||||
f.write("\t// Process the Python results, and convert back to the real params\n")
|
||||
# process the output arguments.
|
||||
formatChars = codePobjects = codePost = argsParseTuple = ""
|
||||
needConversion = 0
|
||||
for arg in method.args:
|
||||
if not arg.HasAttribute("out"):
|
||||
continue
|
||||
try:
|
||||
argCvt = makegwparse.make_arg_converter(arg)
|
||||
argCvt.SetGatewayMode()
|
||||
val = argCvt.GetFormatChar()
|
||||
if val:
|
||||
formatChars = formatChars + val
|
||||
argsParseTuple = argsParseTuple + ", " + argCvt.GetParseTupleArg()
|
||||
codePobjects = codePobjects + argCvt.DeclareParseArgTupleInputConverter()
|
||||
codePost = codePost + argCvt.GetParsePostCode()
|
||||
needConversion = needConversion or argCvt.NeedUSES_CONVERSION()
|
||||
except makegwparse.error_not_supported as why:
|
||||
f.write('// *** The output argument %s of type "%s" was not processed ***\n// %s\n' % (arg.name, arg.raw_type, why))
|
||||
|
||||
if formatChars: # If I have any to actually process.
|
||||
if len(formatChars)==1:
|
||||
parseFn = "PyArg_Parse"
|
||||
else:
|
||||
parseFn = "PyArg_ParseTuple"
|
||||
if codePobjects: f.write(codePobjects)
|
||||
f.write('\tif (!%s(result, "%s" %s))\n\t\treturn MAKE_PYCOM_GATEWAY_FAILURE_CODE("%s");\n' % (parseFn, formatChars, argsParseTuple, method.name))
|
||||
if codePost:
|
||||
f.write('\tBOOL bPythonIsHappy = TRUE;\n')
|
||||
f.write(codePost)
|
||||
f.write('\tif (!bPythonIsHappy) hr = MAKE_PYCOM_GATEWAY_FAILURE_CODE("%s");\n' % method.name)
|
||||
f.write('\tPy_DECREF(result);\n');
|
||||
f.write('\treturn hr;\n}\n\n')
|
||||
|
||||
def test():
|
||||
# make_framework_support("d:\\msdev\\include\\objidl.h", "ILockBytes")
|
||||
make_framework_support("d:\\msdev\\include\\objidl.h", "IStorage")
|
||||
# make_framework_support("d:\\msdev\\include\\objidl.h", "IEnumSTATSTG")
|
317
venv/Lib/site-packages/win32com/makegw/makegwenum.py
Normal file
|
@ -0,0 +1,317 @@
|
|||
"""Utility file for generating PyIEnum support.
|
||||
|
||||
This is almost a 'template' file. It simplay contains almost full
|
||||
C++ source code for PyIEnum* support, and the Python code simply
|
||||
substitutes the appropriate interface name.
|
||||
|
||||
This module is notmally not used directly - the @makegw@ module
|
||||
automatically calls this.
|
||||
"""
|
||||
#
|
||||
# INTERNAL FUNCTIONS
|
||||
#
|
||||
#
|
||||
import string
|
||||
|
||||
def is_interface_enum(enumtype):
|
||||
return not (enumtype[0] in string.uppercase and enumtype[2] in string.uppercase)
|
||||
|
||||
|
||||
def _write_enumifc_cpp(f, interface):
|
||||
enumtype = interface.name[5:]
|
||||
if is_interface_enum(enumtype):
|
||||
# Assume an interface.
|
||||
enum_interface = "I" + enumtype[:-1]
|
||||
converter = "PyObject *ob = PyCom_PyObjectFromIUnknown(rgVar[i], IID_%(enum_interface)s, FALSE);" % locals()
|
||||
arraydeclare = "%(enum_interface)s **rgVar = new %(enum_interface)s *[celt];" % locals()
|
||||
else:
|
||||
# Enum of a simple structure
|
||||
converter = "PyObject *ob = PyCom_PyObjectFrom%(enumtype)s(&rgVar[i]);" % locals()
|
||||
arraydeclare = "%(enumtype)s *rgVar = new %(enumtype)s[celt];" % locals()
|
||||
|
||||
f.write(\
|
||||
'''
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Interface Implementation
|
||||
|
||||
PyIEnum%(enumtype)s::PyIEnum%(enumtype)s(IUnknown *pdisp):
|
||||
PyIUnknown(pdisp)
|
||||
{
|
||||
ob_type = &type;
|
||||
}
|
||||
|
||||
PyIEnum%(enumtype)s::~PyIEnum%(enumtype)s()
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ IEnum%(enumtype)s *PyIEnum%(enumtype)s::GetI(PyObject *self)
|
||||
{
|
||||
return (IEnum%(enumtype)s *)PyIUnknown::GetI(self);
|
||||
}
|
||||
|
||||
// @pymethod object|PyIEnum%(enumtype)s|Next|Retrieves a specified number of items in the enumeration sequence.
|
||||
PyObject *PyIEnum%(enumtype)s::Next(PyObject *self, PyObject *args)
|
||||
{
|
||||
long celt = 1;
|
||||
// @pyparm int|num|1|Number of items to retrieve.
|
||||
if ( !PyArg_ParseTuple(args, "|l:Next", &celt) )
|
||||
return NULL;
|
||||
|
||||
IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
|
||||
if ( pIE%(enumtype)s == NULL )
|
||||
return NULL;
|
||||
|
||||
%(arraydeclare)s
|
||||
if ( rgVar == NULL ) {
|
||||
PyErr_SetString(PyExc_MemoryError, "allocating result %(enumtype)ss");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int i;
|
||||
/* for ( i = celt; i--; )
|
||||
// *** possibly init each structure element???
|
||||
*/
|
||||
|
||||
ULONG celtFetched = 0;
|
||||
PY_INTERFACE_PRECALL;
|
||||
HRESULT hr = pIE%(enumtype)s->Next(celt, rgVar, &celtFetched);
|
||||
PY_INTERFACE_POSTCALL;
|
||||
if ( HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS && FAILED(hr) )
|
||||
{
|
||||
delete [] rgVar;
|
||||
return PyCom_BuildPyException(hr,pIE%(enumtype)s, IID_IE%(enumtype)s);
|
||||
}
|
||||
|
||||
PyObject *result = PyTuple_New(celtFetched);
|
||||
if ( result != NULL )
|
||||
{
|
||||
for ( i = celtFetched; i--; )
|
||||
{
|
||||
%(converter)s
|
||||
if ( ob == NULL )
|
||||
{
|
||||
Py_DECREF(result);
|
||||
result = NULL;
|
||||
break;
|
||||
}
|
||||
PyTuple_SET_ITEM(result, i, ob);
|
||||
}
|
||||
}
|
||||
|
||||
/* for ( i = celtFetched; i--; )
|
||||
// *** possibly cleanup each structure element???
|
||||
*/
|
||||
delete [] rgVar;
|
||||
return result;
|
||||
}
|
||||
|
||||
// @pymethod |PyIEnum%(enumtype)s|Skip|Skips over the next specified elementes.
|
||||
PyObject *PyIEnum%(enumtype)s::Skip(PyObject *self, PyObject *args)
|
||||
{
|
||||
long celt;
|
||||
if ( !PyArg_ParseTuple(args, "l:Skip", &celt) )
|
||||
return NULL;
|
||||
|
||||
IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
|
||||
if ( pIE%(enumtype)s == NULL )
|
||||
return NULL;
|
||||
|
||||
PY_INTERFACE_PRECALL;
|
||||
HRESULT hr = pIE%(enumtype)s->Skip(celt);
|
||||
PY_INTERFACE_POSTCALL;
|
||||
if ( FAILED(hr) )
|
||||
return PyCom_BuildPyException(hr, pIE%(enumtype)s, IID_IE%(enumtype)s);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
// @pymethod |PyIEnum%(enumtype)s|Reset|Resets the enumeration sequence to the beginning.
|
||||
PyObject *PyIEnum%(enumtype)s::Reset(PyObject *self, PyObject *args)
|
||||
{
|
||||
if ( !PyArg_ParseTuple(args, ":Reset") )
|
||||
return NULL;
|
||||
|
||||
IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
|
||||
if ( pIE%(enumtype)s == NULL )
|
||||
return NULL;
|
||||
|
||||
PY_INTERFACE_PRECALL;
|
||||
HRESULT hr = pIE%(enumtype)s->Reset();
|
||||
PY_INTERFACE_POSTCALL;
|
||||
if ( FAILED(hr) )
|
||||
return PyCom_BuildPyException(hr, pIE%(enumtype)s, IID_IE%(enumtype)s);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
// @pymethod <o PyIEnum%(enumtype)s>|PyIEnum%(enumtype)s|Clone|Creates another enumerator that contains the same enumeration state as the current one
|
||||
PyObject *PyIEnum%(enumtype)s::Clone(PyObject *self, PyObject *args)
|
||||
{
|
||||
if ( !PyArg_ParseTuple(args, ":Clone") )
|
||||
return NULL;
|
||||
|
||||
IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
|
||||
if ( pIE%(enumtype)s == NULL )
|
||||
return NULL;
|
||||
|
||||
IEnum%(enumtype)s *pClone;
|
||||
PY_INTERFACE_PRECALL;
|
||||
HRESULT hr = pIE%(enumtype)s->Clone(&pClone);
|
||||
PY_INTERFACE_POSTCALL;
|
||||
if ( FAILED(hr) )
|
||||
return PyCom_BuildPyException(hr, pIE%(enumtype)s, IID_IE%(enumtype)s);
|
||||
|
||||
return PyCom_PyObjectFromIUnknown(pClone, IID_IEnum%(enumtype)s, FALSE);
|
||||
}
|
||||
|
||||
// @object PyIEnum%(enumtype)s|A Python interface to IEnum%(enumtype)s
|
||||
static struct PyMethodDef PyIEnum%(enumtype)s_methods[] =
|
||||
{
|
||||
{ "Next", PyIEnum%(enumtype)s::Next, 1 }, // @pymeth Next|Retrieves a specified number of items in the enumeration sequence.
|
||||
{ "Skip", PyIEnum%(enumtype)s::Skip, 1 }, // @pymeth Skip|Skips over the next specified elementes.
|
||||
{ "Reset", PyIEnum%(enumtype)s::Reset, 1 }, // @pymeth Reset|Resets the enumeration sequence to the beginning.
|
||||
{ "Clone", PyIEnum%(enumtype)s::Clone, 1 }, // @pymeth Clone|Creates another enumerator that contains the same enumeration state as the current one.
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
PyComEnumTypeObject PyIEnum%(enumtype)s::type("PyIEnum%(enumtype)s",
|
||||
&PyIUnknown::type,
|
||||
sizeof(PyIEnum%(enumtype)s),
|
||||
PyIEnum%(enumtype)s_methods,
|
||||
GET_PYCOM_CTOR(PyIEnum%(enumtype)s));
|
||||
''' % locals() )
|
||||
|
||||
|
||||
|
||||
def _write_enumgw_cpp(f, interface):
|
||||
enumtype = interface.name[5:]
|
||||
if is_interface_enum(enumtype):
|
||||
# Assume an interface.
|
||||
enum_interface = "I" + enumtype[:-1]
|
||||
converter = "if ( !PyCom_InterfaceFromPyObject(ob, IID_%(enum_interface)s, (void **)&rgVar[i], FALSE) )" % locals()
|
||||
argdeclare="%(enum_interface)s __RPC_FAR * __RPC_FAR *rgVar" % locals()
|
||||
else:
|
||||
argdeclare="%(enumtype)s __RPC_FAR *rgVar" % locals()
|
||||
converter="if ( !PyCom_PyObjectAs%(enumtype)s(ob, &rgVar[i]) )" % locals()
|
||||
f.write(
|
||||
'''
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// Gateway Implementation
|
||||
|
||||
// Std delegation
|
||||
STDMETHODIMP_(ULONG) PyGEnum%(enumtype)s::AddRef(void) {return PyGatewayBase::AddRef();}
|
||||
STDMETHODIMP_(ULONG) PyGEnum%(enumtype)s::Release(void) {return PyGatewayBase::Release();}
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::QueryInterface(REFIID iid, void ** obj) {return PyGatewayBase::QueryInterface(iid, obj);}
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::GetTypeInfoCount(UINT FAR* pctInfo) {return PyGatewayBase::GetTypeInfoCount(pctInfo);}
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptInfo) {return PyGatewayBase::GetTypeInfo(itinfo, lcid, pptInfo);}
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::GetIDsOfNames(REFIID refiid, OLECHAR FAR* FAR* rgszNames, UINT cNames, LCID lcid, DISPID FAR* rgdispid) {return PyGatewayBase::GetIDsOfNames( refiid, rgszNames, cNames, lcid, rgdispid);}
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* params, VARIANT FAR* pVarResult, EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr) {return PyGatewayBase::Invoke( dispid, riid, lcid, wFlags, params, pVarResult, pexcepinfo, puArgErr);}
|
||||
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::Next(
|
||||
/* [in] */ ULONG celt,
|
||||
/* [length_is][size_is][out] */ %(argdeclare)s,
|
||||
/* [out] */ ULONG __RPC_FAR *pCeltFetched)
|
||||
{
|
||||
PY_GATEWAY_METHOD;
|
||||
PyObject *result;
|
||||
HRESULT hr = InvokeViaPolicy("Next", &result, "i", celt);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
if ( !PySequence_Check(result) )
|
||||
goto error;
|
||||
int len;
|
||||
len = PyObject_Length(result);
|
||||
if ( len == -1 )
|
||||
goto error;
|
||||
if ( len > (int)celt)
|
||||
len = celt;
|
||||
|
||||
if ( pCeltFetched )
|
||||
*pCeltFetched = len;
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < len; ++i )
|
||||
{
|
||||
PyObject *ob = PySequence_GetItem(result, i);
|
||||
if ( ob == NULL )
|
||||
goto error;
|
||||
|
||||
%(converter)s
|
||||
{
|
||||
Py_DECREF(result);
|
||||
return PyCom_SetCOMErrorFromPyException(IID_IEnum%(enumtype)s);
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(result);
|
||||
|
||||
return len < (int)celt ? S_FALSE : S_OK;
|
||||
|
||||
error:
|
||||
PyErr_Clear(); // just in case
|
||||
Py_DECREF(result);
|
||||
return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum%(enumtype)s, "Next() did not return a sequence of objects");
|
||||
}
|
||||
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::Skip(
|
||||
/* [in] */ ULONG celt)
|
||||
{
|
||||
PY_GATEWAY_METHOD;
|
||||
return InvokeViaPolicy("Skip", NULL, "i", celt);
|
||||
}
|
||||
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::Reset(void)
|
||||
{
|
||||
PY_GATEWAY_METHOD;
|
||||
return InvokeViaPolicy("Reset");
|
||||
}
|
||||
|
||||
STDMETHODIMP PyGEnum%(enumtype)s::Clone(
|
||||
/* [out] */ IEnum%(enumtype)s __RPC_FAR *__RPC_FAR *ppEnum)
|
||||
{
|
||||
PY_GATEWAY_METHOD;
|
||||
PyObject * result;
|
||||
HRESULT hr = InvokeViaPolicy("Clone", &result);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
/*
|
||||
** Make sure we have the right kind of object: we should have some kind
|
||||
** of IUnknown subclass wrapped into a PyIUnknown instance.
|
||||
*/
|
||||
if ( !PyIBase::is_object(result, &PyIUnknown::type) )
|
||||
{
|
||||
/* the wrong kind of object was returned to us */
|
||||
Py_DECREF(result);
|
||||
return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum%(enumtype)s);
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the IUnknown out of the thing. note that the Python ob maintains
|
||||
** a reference, so we don't have to explicitly AddRef() here.
|
||||
*/
|
||||
IUnknown *punk = ((PyIUnknown *)result)->m_obj;
|
||||
if ( !punk )
|
||||
{
|
||||
/* damn. the object was released. */
|
||||
Py_DECREF(result);
|
||||
return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum%(enumtype)s);
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the interface we want. note it is returned with a refcount.
|
||||
** This QI is actually going to instantiate a PyGEnum%(enumtype)s.
|
||||
*/
|
||||
hr = punk->QueryInterface(IID_IEnum%(enumtype)s, (LPVOID *)ppEnum);
|
||||
|
||||
/* done with the result; this DECREF is also for <punk> */
|
||||
Py_DECREF(result);
|
||||
|
||||
return PyCom_SetCOMErrorFromSimple(hr, IID_IEnum%(enumtype)s, "Python could not convert the result from Next() into the required COM interface");
|
||||
}
|
||||
''' % locals())
|
783
venv/Lib/site-packages/win32com/makegw/makegwparse.py
Normal file
|
@ -0,0 +1,783 @@
|
|||
"""Utilities for makegw - Parse a header file to build an interface
|
||||
|
||||
This module contains the core code for parsing a header file describing a
|
||||
COM interface, and building it into an "Interface" structure.
|
||||
|
||||
Each Interface has methods, and each method has arguments.
|
||||
|
||||
Each argument knows how to use Py_BuildValue or Py_ParseTuple to
|
||||
exchange itself with Python.
|
||||
|
||||
See the @win32com.makegw@ module for information in building a COM
|
||||
interface
|
||||
"""
|
||||
import re
|
||||
import traceback
|
||||
|
||||
class error_not_found(Exception):
|
||||
def __init__(self, msg="The requested item could not be found"):
|
||||
super(error_not_found, self).__init__(msg)
|
||||
|
||||
class error_not_supported(Exception):
|
||||
def __init__(self, msg="The required functionality is not supported"):
|
||||
super(error_not_supported, self).__init__(msg)
|
||||
|
||||
VERBOSE=0
|
||||
DEBUG=0
|
||||
|
||||
## NOTE : For interfaces as params to work correctly, you must
|
||||
## make sure any PythonCOM extensions which expose the interface are loaded
|
||||
## before generating.
|
||||
|
||||
|
||||
class ArgFormatter:
|
||||
"""An instance for a specific type of argument. Knows how to convert itself"""
|
||||
def __init__(self, arg, builtinIndirection, declaredIndirection = 0):
|
||||
#print 'init:', arg.name, builtinIndirection, declaredIndirection, arg.indirectionLevel
|
||||
self.arg = arg
|
||||
self.builtinIndirection = builtinIndirection
|
||||
self.declaredIndirection = declaredIndirection
|
||||
self.gatewayMode = 0
|
||||
def _IndirectPrefix(self, indirectionFrom, indirectionTo):
|
||||
"""Given the indirection level I was declared at (0=Normal, 1=*, 2=**)
|
||||
return a string prefix so I can pass to a function with the
|
||||
required indirection (where the default is the indirection of the method's param.
|
||||
|
||||
eg, assuming my arg has indirection level of 2, if this function was passed 1
|
||||
it would return "&", so that a variable declared with indirection of 1
|
||||
can be prefixed with this to turn it into the indirection level required of 2
|
||||
"""
|
||||
dif = indirectionFrom - indirectionTo
|
||||
if dif==0:
|
||||
return ""
|
||||
elif dif==-1:
|
||||
return "&"
|
||||
elif dif==1:
|
||||
return "*"
|
||||
else:
|
||||
return "?? (%d)" % (dif,)
|
||||
raise error_not_supported("Can't indirect this far - please fix me :-)")
|
||||
def GetIndirectedArgName(self, indirectFrom, indirectionTo):
|
||||
#print 'get:',self.arg.name, indirectFrom,self._GetDeclaredIndirection() + self.builtinIndirection, indirectionTo, self.arg.indirectionLevel
|
||||
|
||||
if indirectFrom is None:
|
||||
### ACK! this does not account for [in][out] variables.
|
||||
### when this method is called, we need to know which
|
||||
indirectFrom = self._GetDeclaredIndirection() + self.builtinIndirection
|
||||
|
||||
return self._IndirectPrefix(indirectFrom, indirectionTo) + self.arg.name
|
||||
def GetBuildValueArg(self):
|
||||
"Get the argument to be passes to Py_BuildValue"
|
||||
return self.arg.name
|
||||
def GetParseTupleArg(self):
|
||||
"Get the argument to be passed to PyArg_ParseTuple"
|
||||
if self.gatewayMode:
|
||||
# use whatever they were declared with
|
||||
return self.GetIndirectedArgName(None, 1)
|
||||
# local declarations have just their builtin indirection
|
||||
return self.GetIndirectedArgName(self.builtinIndirection, 1)
|
||||
def GetInterfaceCppObjectInfo(self):
|
||||
"""Provide information about the C++ object used.
|
||||
|
||||
Simple variables (such as integers) can declare their type (eg an integer)
|
||||
and use it as the target of both PyArg_ParseTuple and the COM function itself.
|
||||
|
||||
More complex types require a PyObject * declared as the target of PyArg_ParseTuple,
|
||||
then some conversion routine to the C++ object which is actually passed to COM.
|
||||
|
||||
This method provides the name, and optionally the type of that C++ variable.
|
||||
If the type if provided, the caller will likely generate a variable declaration.
|
||||
The name must always be returned.
|
||||
|
||||
Result is a tuple of (variableName, [DeclareType|None|""])
|
||||
"""
|
||||
|
||||
# the first return element is the variable to be passed as
|
||||
# an argument to an interface method. the variable was
|
||||
# declared with only its builtin indirection level. when
|
||||
# we pass it, we'll need to pass in whatever amount of
|
||||
# indirection was applied (plus the builtin amount)
|
||||
# the second return element is the variable declaration; it
|
||||
# should simply be builtin indirection
|
||||
return self.GetIndirectedArgName(self.builtinIndirection, self.arg.indirectionLevel + self.builtinIndirection), \
|
||||
"%s %s" % (self.GetUnconstType(), self.arg.name)
|
||||
|
||||
def GetInterfaceArgCleanup(self):
|
||||
"Return cleanup code for C++ args passed to the interface method."
|
||||
if DEBUG:
|
||||
return "/* GetInterfaceArgCleanup output goes here: %s */\n" % self.arg.name
|
||||
else:
|
||||
return ""
|
||||
|
||||
def GetInterfaceArgCleanupGIL(self):
|
||||
"""Return cleanup code for C++ args passed to the interface
|
||||
method that must be executed with the GIL held"""
|
||||
if DEBUG:
|
||||
return "/* GetInterfaceArgCleanup (GIL held) output goes here: %s */\n" % self.arg.name
|
||||
else:
|
||||
return ""
|
||||
|
||||
def GetUnconstType(self):
|
||||
return self.arg.unc_type
|
||||
|
||||
def SetGatewayMode(self):
|
||||
self.gatewayMode = 1
|
||||
def _GetDeclaredIndirection(self):
|
||||
return self.arg.indirectionLevel
|
||||
print('declared:', self.arg.name, self.gatewayMode)
|
||||
if self.gatewayMode:
|
||||
return self.arg.indirectionLevel
|
||||
else:
|
||||
return self.declaredIndirection
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
"Declare the variable used as the PyArg_ParseTuple param for a gateway"
|
||||
# Only declare it??
|
||||
#if self.arg.indirectionLevel==0:
|
||||
# return "\t%s %s;\n" % (self.arg.type, self.arg.name)
|
||||
#else:
|
||||
if DEBUG:
|
||||
return "/* Declare ParseArgTupleInputConverter goes here: %s */\n" % self.arg.name
|
||||
else:
|
||||
return ""
|
||||
def GetParsePostCode(self):
|
||||
"Get a string of C++ code to be executed after (ie, to finalise) the PyArg_ParseTuple conversion"
|
||||
if DEBUG:
|
||||
return "/* GetParsePostCode code goes here: %s */\n" % self.arg.name
|
||||
else:
|
||||
return ""
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
"Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Interfaces"
|
||||
if DEBUG:
|
||||
return "/* GetBuildForInterfacePreCode goes here: %s */\n" % self.arg.name
|
||||
else:
|
||||
return ""
|
||||
def GetBuildForGatewayPreCode(self):
|
||||
"Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Gateways"
|
||||
s = self.GetBuildForInterfacePreCode() # Usually the same
|
||||
if DEBUG:
|
||||
if s[:4] == "/* G":
|
||||
s = "/* GetBuildForGatewayPreCode goes here: %s */\n" % self.arg.name
|
||||
return s
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
"Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Interfaces"
|
||||
if DEBUG:
|
||||
return "/* GetBuildForInterfacePostCode goes here: %s */\n" % self.arg.name
|
||||
return ""
|
||||
def GetBuildForGatewayPostCode(self):
|
||||
"Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Gateways"
|
||||
s = self.GetBuildForInterfacePostCode() # Usually the same
|
||||
if DEBUG:
|
||||
if s[:4] == "/* G":
|
||||
s = "/* GetBuildForGatewayPostCode goes here: %s */\n" % self.arg.name
|
||||
return s
|
||||
def GetAutoduckString(self):
|
||||
return '// @pyparm %s|%s||Description for %s' % (self._GetPythonTypeDesc(), self.arg.name, self.arg.name)
|
||||
def _GetPythonTypeDesc(self):
|
||||
"Returns a string with the description of the type. Used for doco purposes"
|
||||
return None
|
||||
def NeedUSES_CONVERSION(self):
|
||||
"Determines if this arg forces a USES_CONVERSION macro"
|
||||
return 0
|
||||
|
||||
# Special formatter for floats since they're smaller than Python floats.
|
||||
class ArgFormatterFloat(ArgFormatter):
|
||||
def GetFormatChar(self):
|
||||
return "f"
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
# Declare a double variable
|
||||
return "\tdouble dbl%s;\n" % self.arg.name
|
||||
def GetParseTupleArg(self):
|
||||
return "&dbl" + self.arg.name
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "float"
|
||||
def GetBuildValueArg(self):
|
||||
return "&dbl" + self.arg.name
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
return "\tdbl" + self.arg.name + " = " + self.arg.name + ";\n"
|
||||
def GetBuildForGatewayPreCode(self):
|
||||
return "\tdbl%s = " % self.arg.name + self._IndirectPrefix( \
|
||||
self._GetDeclaredIndirection(),
|
||||
0) + self.arg.name + ";\n"
|
||||
def GetParsePostCode(self):
|
||||
s = "\t"
|
||||
if self.gatewayMode:
|
||||
s = s + self._IndirectPrefix(
|
||||
self._GetDeclaredIndirection(),
|
||||
0)
|
||||
s = s + self.arg.name
|
||||
s = s + " = (float)dbl%s;\n" % self.arg.name
|
||||
return s
|
||||
|
||||
# Special formatter for Shorts because they're
|
||||
# a different size than Python ints!
|
||||
class ArgFormatterShort(ArgFormatter):
|
||||
def GetFormatChar(self):
|
||||
return "i"
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
# Declare a double variable
|
||||
return "\tINT i%s;\n" % self.arg.name
|
||||
def GetParseTupleArg(self):
|
||||
return "&i" + self.arg.name
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "int"
|
||||
def GetBuildValueArg(self):
|
||||
return "&i" + self.arg.name
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
return "\ti" + self.arg.name + " = " + self.arg.name + ";\n"
|
||||
def GetBuildForGatewayPreCode(self):
|
||||
return "\ti%s = " % self.arg.name + self._IndirectPrefix( \
|
||||
self._GetDeclaredIndirection(),
|
||||
0) + self.arg.name + ";\n"
|
||||
def GetParsePostCode(self):
|
||||
s = "\t"
|
||||
if self.gatewayMode:
|
||||
s = s + self._IndirectPrefix(
|
||||
self._GetDeclaredIndirection(),
|
||||
0)
|
||||
s = s + self.arg.name
|
||||
s = s + " = i%s;\n" % self.arg.name
|
||||
return s
|
||||
|
||||
# for types which are 64bits on AMD64 - eg, HWND
|
||||
class ArgFormatterLONG_PTR(ArgFormatter):
|
||||
def GetFormatChar(self):
|
||||
return "O"
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
# Declare a PyObject variable
|
||||
return "\tPyObject *ob%s;\n" % self.arg.name
|
||||
def GetParseTupleArg(self):
|
||||
return "&ob"+self.arg.name
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "int/long"
|
||||
def GetBuildValueArg(self):
|
||||
return "ob" + self.arg.name
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
# Declare a PyObject variable
|
||||
return "\tPyObject *ob%s;\n" % self.arg.name
|
||||
|
||||
def GetParsePostCode(self):
|
||||
return "\tif (bPythonIsHappy && !PyWinLong_AsULONG_PTR(ob%s, (ULONG_PTR *)%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = PyWinObject_FromULONG_PTR(%s);\n" % \
|
||||
(self.arg.name, notdirected)
|
||||
def GetBuildForGatewayPostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
|
||||
class ArgFormatterPythonCOM(ArgFormatter):
|
||||
"""An arg formatter for types exposed in the PythonCOM module"""
|
||||
def GetFormatChar(self):
|
||||
return "O"
|
||||
#def GetInterfaceCppObjectInfo(self):
|
||||
# return ArgFormatter.GetInterfaceCppObjectInfo(self)[0], \
|
||||
# "%s %s%s" % (self.arg.unc_type, "*" * self._GetDeclaredIndirection(), self.arg.name)
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
# Declare a PyObject variable
|
||||
return "\tPyObject *ob%s;\n" % self.arg.name
|
||||
def GetParseTupleArg(self):
|
||||
return "&ob"+self.arg.name
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o Py%s>" % self.arg.type
|
||||
def GetBuildValueArg(self):
|
||||
return "ob" + self.arg.name
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
def DeclareParseArgTupleInputConverter(self):
|
||||
# Declare a PyObject variable
|
||||
return "\tPyObject *ob%s;\n" % self.arg.name
|
||||
|
||||
class ArgFormatterBSTR(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o unicode>"
|
||||
def GetParsePostCode(self):
|
||||
return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = MakeBstrToObj(%s);\n" % \
|
||||
(self.arg.name, notdirected)
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
return "\tSysFreeString(%s);\n" % (self.arg.name,) + \
|
||||
ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
|
||||
def GetBuildForGatewayPostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
|
||||
class ArgFormatterOLECHAR(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o unicode>"
|
||||
def GetUnconstType(self):
|
||||
if self.arg.type[:3]=="LPC":
|
||||
return self.arg.type[:2] + self.arg.type[3:]
|
||||
else:
|
||||
return self.arg.unc_type
|
||||
def GetParsePostCode(self):
|
||||
return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
|
||||
def GetInterfaceArgCleanup(self):
|
||||
return "\tSysFreeString(%s);\n" % self.GetIndirectedArgName(None, 1)
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
# the variable was declared with just its builtin indirection
|
||||
notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
|
||||
return "\tob%s = MakeOLECHARToObj(%s);\n" % \
|
||||
(self.arg.name, notdirected)
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
# memory returned into an OLECHAR should be freed
|
||||
return "\tCoTaskMemFree(%s);\n" % (self.arg.name,) + \
|
||||
ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
|
||||
def GetBuildForGatewayPostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
|
||||
class ArgFormatterTCHAR(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "string/<o unicode>"
|
||||
def GetUnconstType(self):
|
||||
if self.arg.type[:3]=="LPC":
|
||||
return self.arg.type[:2] + self.arg.type[3:]
|
||||
else:
|
||||
return self.arg.unc_type
|
||||
def GetParsePostCode(self):
|
||||
return "\tif (bPythonIsHappy && !PyWinObject_AsTCHAR(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
|
||||
def GetInterfaceArgCleanup(self):
|
||||
return "\tPyWinObject_FreeTCHAR(%s);\n" % self.GetIndirectedArgName(None, 1)
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
# the variable was declared with just its builtin indirection
|
||||
notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
|
||||
return "\tob%s = PyWinObject_FromTCHAR(%s);\n" % \
|
||||
(self.arg.name, notdirected)
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
return "// ??? - TCHAR post code\n"
|
||||
def GetBuildForGatewayPostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
|
||||
class ArgFormatterIID(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o PyIID>"
|
||||
def GetParsePostCode(self):
|
||||
return "\tif (!PyWinObject_AsIID(ob%s, &%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.name)
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
# notdirected = self.GetIndirectedArgName(self.arg.indirectionLevel, 0)
|
||||
notdirected = self.GetIndirectedArgName(None, 0)
|
||||
return "\tob%s = PyWinObject_FromIID(%s);\n" % (self.arg.name, notdirected)
|
||||
def GetInterfaceCppObjectInfo(self):
|
||||
return self.arg.name, "IID %s" % (self.arg.name)
|
||||
|
||||
class ArgFormatterTime(ArgFormatterPythonCOM):
|
||||
def __init__(self, arg, builtinIndirection, declaredIndirection = 0):
|
||||
# we don't want to declare LPSYSTEMTIME / LPFILETIME objects
|
||||
if arg.indirectionLevel == 0 and arg.unc_type[:2] == "LP":
|
||||
arg.unc_type = arg.unc_type[2:]
|
||||
# reduce the builtin and increment the declaration
|
||||
arg.indirectionLevel = arg.indirectionLevel + 1
|
||||
builtinIndirection = 0
|
||||
ArgFormatterPythonCOM.__init__(self, arg, builtinIndirection, declaredIndirection)
|
||||
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o PyTime>"
|
||||
def GetParsePostCode(self):
|
||||
# variable was declared with only the builtinIndirection
|
||||
### NOTE: this is an [in] ... so use only builtin
|
||||
return '\tif (!PyTime_Check(ob%s)) {\n\t\tPyErr_SetString(PyExc_TypeError, "The argument must be a PyTime object");\n\t\tbPythonIsHappy = FALSE;\n\t}\n\tif (!((PyTime *)ob%s)->GetTime(%s)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.arg.name, self.GetIndirectedArgName(self.builtinIndirection, 1))
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
### use just the builtinIndirection again...
|
||||
notdirected = self.GetIndirectedArgName(self.builtinIndirection,0)
|
||||
return "\tob%s = new PyTime(%s);\n" % (self.arg.name, notdirected)
|
||||
def GetBuildForInterfacePostCode(self):
|
||||
### hack to determine if we need to free stuff
|
||||
ret = ''
|
||||
if self.builtinIndirection + self.arg.indirectionLevel > 1:
|
||||
# memory returned into an OLECHAR should be freed
|
||||
ret = "\tCoTaskMemFree(%s);\n" % self.arg.name
|
||||
return ret + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
|
||||
|
||||
class ArgFormatterSTATSTG(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o STATSTG>"
|
||||
def GetParsePostCode(self):
|
||||
return '\tif (!PyCom_PyObjectAsSTATSTG(ob%s, %s, 0/*flags*/)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = PyCom_PyObjectFromSTATSTG(%s);\n\t// STATSTG doco says our responsibility to free\n\tif ((%s).pwcsName) CoTaskMemFree((%s).pwcsName);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1),notdirected,notdirected)
|
||||
|
||||
class ArgFormatterGeneric(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o %s>" % self.arg.type
|
||||
def GetParsePostCode(self):
|
||||
return '\tif (!PyObject_As%s(ob%s, &%s) bPythonIsHappy = FALSE;\n' % (self.arg.type, self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
def GetInterfaceArgCleanup(self):
|
||||
return '\tPyObject_Free%s(%s);\n' % (self.arg.type, self.arg.name)
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = PyObject_From%s(%s);\n" % (self.arg.name, self.arg.type, self.GetIndirectedArgName(None, 1))
|
||||
|
||||
class ArgFormatterIDLIST(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o PyIDL>"
|
||||
def GetParsePostCode(self):
|
||||
return '\tif (bPythonIsHappy && !PyObject_AsPIDL(ob%s, &%s)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
def GetInterfaceArgCleanup(self):
|
||||
return '\tPyObject_FreePIDL(%s);\n' % (self.arg.name,)
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = PyObject_FromPIDL(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
|
||||
class ArgFormatterHANDLE(ArgFormatterPythonCOM):
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o PyHANDLE>"
|
||||
def GetParsePostCode(self):
|
||||
return '\tif (!PyWinObject_AsHANDLE(ob%s, &%s, FALSE) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = PyWinObject_FromHANDLE(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 0))
|
||||
|
||||
class ArgFormatterLARGE_INTEGER(ArgFormatterPythonCOM):
|
||||
def GetKeyName(self):
|
||||
return "LARGE_INTEGER"
|
||||
def _GetPythonTypeDesc(self):
|
||||
return "<o %s>" % self.GetKeyName()
|
||||
def GetParsePostCode(self):
|
||||
return '\tif (!PyWinObject_As%s(ob%s, %s)) bPythonIsHappy = FALSE;\n' % (self.GetKeyName(), self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 0)
|
||||
return "\tob%s = PyWinObject_From%s(%s);\n" % (self.arg.name, self.GetKeyName(), notdirected)
|
||||
|
||||
class ArgFormatterULARGE_INTEGER(ArgFormatterLARGE_INTEGER):
|
||||
def GetKeyName(self):
|
||||
return "ULARGE_INTEGER"
|
||||
|
||||
class ArgFormatterInterface(ArgFormatterPythonCOM):
|
||||
def GetInterfaceCppObjectInfo(self):
|
||||
return self.GetIndirectedArgName(1, self.arg.indirectionLevel), \
|
||||
"%s * %s" % (self.GetUnconstType(), self.arg.name)
|
||||
|
||||
def GetParsePostCode(self):
|
||||
# This gets called for out params in gateway mode
|
||||
if self.gatewayMode:
|
||||
sArg = self.GetIndirectedArgName(None, 2)
|
||||
else:
|
||||
# vs. in params for interface mode.
|
||||
sArg = self.GetIndirectedArgName(1, 2)
|
||||
return "\tif (bPythonIsHappy && !PyCom_InterfaceFromPyInstanceOrObject(ob%s, IID_%s, (void **)%s, TRUE /* bNoneOK */))\n\t\t bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.type, sArg)
|
||||
|
||||
def GetBuildForInterfacePreCode(self):
|
||||
return "\tob%s = PyCom_PyObjectFromIUnknown(%s, IID_%s, FALSE);\n" % (self.arg.name, self.arg.name, self.arg.type)
|
||||
|
||||
def GetBuildForGatewayPreCode(self):
|
||||
sPrefix = self._IndirectPrefix(self._GetDeclaredIndirection(), 1)
|
||||
return "\tob%s = PyCom_PyObjectFromIUnknown(%s%s, IID_%s, TRUE);\n" % (self.arg.name, sPrefix, self.arg.name, self.arg.type)
|
||||
|
||||
def GetInterfaceArgCleanup(self):
|
||||
return "\tif (%s) %s->Release();\n" % (self.arg.name, self.arg.name)
|
||||
|
||||
class ArgFormatterVARIANT(ArgFormatterPythonCOM):
|
||||
def GetParsePostCode(self):
|
||||
return "\tif ( !PyCom_VariantFromPyObject(ob%s, %s) )\n\t\tbPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 1))
|
||||
|
||||
def GetBuildForGatewayPreCode(self):
|
||||
notdirected = self.GetIndirectedArgName(None, 1)
|
||||
return "\tob%s = PyCom_PyObjectFromVariant(%s);\n" % (self.arg.name, notdirected)
|
||||
def GetBuildForGatewayPostCode(self):
|
||||
return "\tPy_XDECREF(ob%s);\n" % self.arg.name
|
||||
|
||||
# Key : , Python Type Description, ParseTuple format char
|
||||
ConvertSimpleTypes = {"BOOL":("BOOL", "int", "i"),
|
||||
"UINT":("UINT", "int", "i"),
|
||||
"BYTE": ("BYTE", "int", "i"),
|
||||
"INT": ("INT", "int", "i"),
|
||||
"DWORD": ("DWORD", "int", "l"),
|
||||
"HRESULT":("HRESULT", "int", "l"),
|
||||
"ULONG": ("ULONG", "int", "l"),
|
||||
"LONG": ("LONG", "int", "l"),
|
||||
"int": ("int", "int", "i"),
|
||||
"long": ("long", "int", "l"),
|
||||
"DISPID": ("DISPID", "long", "l"),
|
||||
"APPBREAKFLAGS": ("int", "int", "i"),
|
||||
"BREAKRESUMEACTION": ("int", "int", "i"),
|
||||
"ERRORRESUMEACTION": ("int", "int", "i"),
|
||||
"BREAKREASON": ("int", "int", "i"),
|
||||
"BREAKPOINT_STATE": ("int", "int", "i"),
|
||||
"BREAKRESUME_ACTION": ("int", "int", "i"),
|
||||
"SOURCE_TEXT_ATTR": ("int", "int", "i"),
|
||||
"TEXT_DOC_ATTR": ("int", "int", "i"),
|
||||
"QUERYOPTION": ("int", "int", "i"),
|
||||
"PARSEACTION": ("int", "int", "i"),
|
||||
}
|
||||
|
||||
class ArgFormatterSimple(ArgFormatter):
|
||||
"""An arg formatter for simple integer etc types"""
|
||||
def GetFormatChar(self):
|
||||
return ConvertSimpleTypes[self.arg.type][2]
|
||||
def _GetPythonTypeDesc(self):
|
||||
return ConvertSimpleTypes[self.arg.type][1]
|
||||
|
||||
AllConverters = {"const OLECHAR": (ArgFormatterOLECHAR, 0, 1),
|
||||
"WCHAR": (ArgFormatterOLECHAR, 0, 1),
|
||||
"OLECHAR": (ArgFormatterOLECHAR, 0, 1),
|
||||
"LPCOLESTR": (ArgFormatterOLECHAR, 1, 1),
|
||||
"LPOLESTR": (ArgFormatterOLECHAR, 1, 1),
|
||||
"LPCWSTR": (ArgFormatterOLECHAR, 1, 1),
|
||||
"LPWSTR": (ArgFormatterOLECHAR, 1, 1),
|
||||
"LPCSTR": (ArgFormatterOLECHAR, 1, 1),
|
||||
"LPTSTR": (ArgFormatterTCHAR, 1, 1),
|
||||
"LPCTSTR": (ArgFormatterTCHAR, 1, 1),
|
||||
"HANDLE": (ArgFormatterHANDLE, 0),
|
||||
"BSTR": (ArgFormatterBSTR, 1, 0),
|
||||
"const IID": (ArgFormatterIID, 0),
|
||||
"CLSID": (ArgFormatterIID, 0),
|
||||
"IID": (ArgFormatterIID, 0),
|
||||
"GUID": (ArgFormatterIID, 0),
|
||||
"const GUID": (ArgFormatterIID, 0),
|
||||
"const IID": (ArgFormatterIID, 0),
|
||||
"REFCLSID": (ArgFormatterIID, 0),
|
||||
"REFIID": (ArgFormatterIID, 0),
|
||||
"REFGUID": (ArgFormatterIID, 0),
|
||||
"const FILETIME": (ArgFormatterTime, 0),
|
||||
"const SYSTEMTIME":(ArgFormatterTime, 0),
|
||||
"const LPSYSTEMTIME":(ArgFormatterTime, 1, 1),
|
||||
"LPSYSTEMTIME": (ArgFormatterTime, 1, 1),
|
||||
"FILETIME": (ArgFormatterTime, 0),
|
||||
"SYSTEMTIME": (ArgFormatterTime, 0),
|
||||
"STATSTG": (ArgFormatterSTATSTG, 0),
|
||||
"LARGE_INTEGER": (ArgFormatterLARGE_INTEGER, 0),
|
||||
"ULARGE_INTEGER": (ArgFormatterULARGE_INTEGER, 0),
|
||||
"VARIANT": (ArgFormatterVARIANT, 0),
|
||||
"float": (ArgFormatterFloat, 0),
|
||||
"single": (ArgFormatterFloat, 0),
|
||||
"short": (ArgFormatterShort, 0),
|
||||
"WORD": (ArgFormatterShort, 0),
|
||||
"VARIANT_BOOL": (ArgFormatterShort, 0),
|
||||
"HWND": (ArgFormatterLONG_PTR, 1),
|
||||
"HMENU": (ArgFormatterLONG_PTR, 1),
|
||||
"HOLEMENU": (ArgFormatterLONG_PTR, 1),
|
||||
"HICON": (ArgFormatterLONG_PTR, 1),
|
||||
"HDC": (ArgFormatterLONG_PTR, 1),
|
||||
"LPARAM": (ArgFormatterLONG_PTR, 1),
|
||||
"WPARAM": (ArgFormatterLONG_PTR, 1),
|
||||
"LRESULT": (ArgFormatterLONG_PTR, 1),
|
||||
"UINT": (ArgFormatterShort, 0),
|
||||
"SVSIF": (ArgFormatterShort, 0),
|
||||
"Control": (ArgFormatterInterface, 0, 1),
|
||||
"DataObject": (ArgFormatterInterface, 0, 1),
|
||||
"_PropertyBag": (ArgFormatterInterface, 0, 1),
|
||||
"AsyncProp": (ArgFormatterInterface, 0, 1),
|
||||
"DataSource": (ArgFormatterInterface, 0, 1),
|
||||
"DataFormat": (ArgFormatterInterface, 0, 1),
|
||||
"void **": (ArgFormatterInterface, 2, 2),
|
||||
"ITEMIDLIST": (ArgFormatterIDLIST, 0, 0),
|
||||
"LPITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
|
||||
"LPCITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
|
||||
"const ITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
|
||||
}
|
||||
|
||||
# Auto-add all the simple types
|
||||
for key in ConvertSimpleTypes.keys():
|
||||
AllConverters[key] = ArgFormatterSimple, 0
|
||||
|
||||
def make_arg_converter(arg):
|
||||
try:
|
||||
clz = AllConverters[arg.type][0]
|
||||
bin = AllConverters[arg.type][1]
|
||||
decl = 0
|
||||
if len(AllConverters[arg.type])>2:
|
||||
decl = AllConverters[arg.type][2]
|
||||
return clz(arg,bin, decl)
|
||||
except KeyError:
|
||||
if arg.type[0]=="I":
|
||||
return ArgFormatterInterface(arg, 0, 1)
|
||||
|
||||
raise error_not_supported("The type '%s' (%s) is unknown." % (arg.type, arg.name))
|
||||
|
||||
|
||||
#############################################################
|
||||
#
|
||||
# The instances that represent the args, methods and interface
|
||||
class Argument:
|
||||
"""A representation of an argument to a COM method
|
||||
|
||||
This class contains information about a specific argument to a method.
|
||||
In addition, methods exist so that an argument knows how to convert itself
|
||||
to/from Python arguments.
|
||||
"""
|
||||
# in,out type name [ ]
|
||||
# -------------- -------- ------------ ------
|
||||
regex = re.compile(r'/\* \[([^\]]*.*?)] \*/[ \t](.*[* ]+)(\w+)(\[ *])?[\),]')
|
||||
def __init__(self, good_interface_names):
|
||||
self.good_interface_names = good_interface_names
|
||||
self.inout = self.name = self.type = None
|
||||
self.const = 0
|
||||
self.arrayDecl = 0
|
||||
def BuildFromFile(self, file):
|
||||
"""Parse and build my data from a file
|
||||
|
||||
Reads the next line in the file, and matches it as an argument
|
||||
description. If not a valid argument line, an error_not_found exception
|
||||
is raised.
|
||||
"""
|
||||
line = file.readline()
|
||||
mo = self.regex.search(line)
|
||||
if not mo:
|
||||
raise error_not_found
|
||||
self.name = mo.group(3)
|
||||
self.inout = mo.group(1).split('][')
|
||||
typ = mo.group(2).strip()
|
||||
self.raw_type = typ
|
||||
self.indirectionLevel = 0
|
||||
if mo.group(4): # Has "[ ]" decl
|
||||
self.arrayDecl = 1
|
||||
try:
|
||||
pos = typ.rindex("__RPC_FAR")
|
||||
self.indirectionLevel = self.indirectionLevel + 1
|
||||
typ = typ[:pos].strip()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
typ = typ.replace("__RPC_FAR", "")
|
||||
while 1:
|
||||
try:
|
||||
pos = typ.rindex("*")
|
||||
self.indirectionLevel = self.indirectionLevel + 1
|
||||
typ = typ[:pos].strip()
|
||||
except ValueError:
|
||||
break
|
||||
self.type = typ
|
||||
if self.type[:6]=="const ":
|
||||
self.unc_type = self.type[6:]
|
||||
else:
|
||||
self.unc_type = self.type
|
||||
|
||||
if VERBOSE:
|
||||
print(" Arg %s of type %s%s (%s)" % (self.name, self.type, "*" * self.indirectionLevel, self.inout))
|
||||
|
||||
def HasAttribute(self, typ):
|
||||
"""Determines if the argument has the specific attribute.
|
||||
|
||||
Argument attributes are specified in the header file, such as
|
||||
"[in][out][retval]" etc. You can pass a specific string (eg "out")
|
||||
to find if this attribute was specified for the argument
|
||||
"""
|
||||
return typ in self.inout
|
||||
|
||||
def GetRawDeclaration(self):
|
||||
ret = "%s %s" % (self.raw_type, self.name)
|
||||
if self.arrayDecl:
|
||||
ret = ret + "[]"
|
||||
return ret
|
||||
|
||||
class Method:
|
||||
"""A representation of a C++ method on a COM interface
|
||||
|
||||
This class contains information about a specific method, as well as
|
||||
a list of all @Argument@s
|
||||
"""
|
||||
# options ret type callconv name
|
||||
# ----------------- -------- -------- --------
|
||||
regex = re.compile(r'virtual (/\*.*?\*/ )?(.*?) (.*?) (.*?)\(\w?')
|
||||
def __init__(self, good_interface_names):
|
||||
self.good_interface_names = good_interface_names
|
||||
self.name = self.result = self.callconv = None
|
||||
self.args = []
|
||||
def BuildFromFile(self, file):
|
||||
"""Parse and build my data from a file
|
||||
|
||||
Reads the next line in the file, and matches it as a method
|
||||
description. If not a valid method line, an error_not_found exception
|
||||
is raised.
|
||||
"""
|
||||
line = file.readline()
|
||||
mo = self.regex.search(line)
|
||||
if not mo:
|
||||
raise error_not_found
|
||||
self.name = mo.group(4)
|
||||
self.result = mo.group(2)
|
||||
if self.result != "HRESULT":
|
||||
if self.result=="DWORD": # DWORD is for old old stuff?
|
||||
print("Warning: Old style interface detected - compilation errors likely!")
|
||||
else:
|
||||
print("Method %s - Only HRESULT return types are supported." % self.name)
|
||||
# raise error_not_supported, if VERBOSE:
|
||||
print(" Method %s %s(" % (self.result, self.name))
|
||||
while 1:
|
||||
arg = Argument(self.good_interface_names)
|
||||
try:
|
||||
arg.BuildFromFile(file)
|
||||
self.args.append(arg)
|
||||
except error_not_found:
|
||||
break
|
||||
|
||||
class Interface:
|
||||
"""A representation of a C++ COM Interface
|
||||
|
||||
This class contains information about a specific interface, as well as
|
||||
a list of all @Method@s
|
||||
"""
|
||||
# name base
|
||||
# -------- --------
|
||||
regex = re.compile("(interface|) ([^ ]*) : public (.*)$")
|
||||
def __init__(self, mo):
|
||||
self.methods = []
|
||||
self.name = mo.group(2)
|
||||
self.base = mo.group(3)
|
||||
if VERBOSE:
|
||||
print("Interface %s : public %s" % (self.name, self.base))
|
||||
|
||||
def BuildMethods(self, file):
|
||||
"""Build all sub-methods for this interface"""
|
||||
# skip the next 2 lines.
|
||||
file.readline();file.readline();
|
||||
while 1:
|
||||
try:
|
||||
method = Method([self.name])
|
||||
method.BuildFromFile(file)
|
||||
self.methods.append(method)
|
||||
except error_not_found:
|
||||
break
|
||||
|
||||
def find_interface(interfaceName, file):
|
||||
"""Find and return an interface in a file
|
||||
|
||||
Given an interface name and file, search for the specified interface.
|
||||
|
||||
Upon return, the interface itself has been built,
|
||||
but not the methods.
|
||||
"""
|
||||
interface = None
|
||||
line = file.readline()
|
||||
while line:
|
||||
mo = Interface.regex.search(line)
|
||||
if mo:
|
||||
name = mo.group(2)
|
||||
print(name)
|
||||
AllConverters[name] = (ArgFormatterInterface, 0, 1)
|
||||
if name==interfaceName:
|
||||
interface = Interface(mo)
|
||||
interface.BuildMethods(file)
|
||||
line = file.readline()
|
||||
if interface:
|
||||
return interface
|
||||
raise error_not_found
|
||||
|
||||
|
||||
def parse_interface_info(interfaceName, file):
|
||||
"""Find, parse and return an interface in a file
|
||||
|
||||
Given an interface name and file, search for the specified interface.
|
||||
|
||||
Upon return, the interface itself is fully built,
|
||||
"""
|
||||
try:
|
||||
return find_interface(interfaceName, file)
|
||||
except re.error:
|
||||
traceback.print_exc()
|
||||
print("The interface could not be built, as the regular expression failed!")
|
||||
def test():
|
||||
f=open("d:\\msdev\\include\\objidl.h")
|
||||
try:
|
||||
parse_interface_info("IPersistStream", f)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def test_regex(r,text):
|
||||
res=r.search(text,0)
|
||||
if res==-1:
|
||||
print("** Not found")
|
||||
else:
|
||||
print("%d\n%s\n%s\n%s\n%s" % (res, r.group(1), r.group(2), r.group(3), r.group(4)))
|
68
venv/Lib/site-packages/win32com/olectl.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
"""Constants used by COM Controls
|
||||
|
||||
Hand created version of OLECTL.H constants.
|
||||
"""
|
||||
|
||||
import winerror
|
||||
|
||||
FACILITY_CONTROL = 0xa
|
||||
|
||||
def MAKE_SCODE(sev, fac, code):
|
||||
return int((int(-sev)<<31) | ((fac)<<16) | ((code)))
|
||||
|
||||
def STD_CTL_SCODE(n):
|
||||
return MAKE_SCODE(winerror.SEVERITY_ERROR, FACILITY_CONTROL, n)
|
||||
|
||||
CTL_E_ILLEGALFUNCTIONCALL = STD_CTL_SCODE(5)
|
||||
CTL_E_OVERFLOW = STD_CTL_SCODE(6)
|
||||
CTL_E_OUTOFMEMORY = STD_CTL_SCODE(7)
|
||||
CTL_E_DIVISIONBYZERO = STD_CTL_SCODE(11)
|
||||
CTL_E_OUTOFSTRINGSPACE = STD_CTL_SCODE(14)
|
||||
CTL_E_OUTOFSTACKSPACE = STD_CTL_SCODE(28)
|
||||
CTL_E_BADFILENAMEORNUMBER = STD_CTL_SCODE(52)
|
||||
CTL_E_FILENOTFOUND = STD_CTL_SCODE(53)
|
||||
CTL_E_BADFILEMODE = STD_CTL_SCODE(54)
|
||||
CTL_E_FILEALREADYOPEN = STD_CTL_SCODE(55)
|
||||
CTL_E_DEVICEIOERROR = STD_CTL_SCODE(57)
|
||||
CTL_E_FILEALREADYEXISTS = STD_CTL_SCODE(58)
|
||||
CTL_E_BADRECORDLENGTH = STD_CTL_SCODE(59)
|
||||
CTL_E_DISKFULL = STD_CTL_SCODE(61)
|
||||
CTL_E_BADRECORDNUMBER = STD_CTL_SCODE(63)
|
||||
CTL_E_BADFILENAME = STD_CTL_SCODE(64)
|
||||
CTL_E_TOOMANYFILES = STD_CTL_SCODE(67)
|
||||
CTL_E_DEVICEUNAVAILABLE = STD_CTL_SCODE(68)
|
||||
CTL_E_PERMISSIONDENIED = STD_CTL_SCODE(70)
|
||||
CTL_E_DISKNOTREADY = STD_CTL_SCODE(71)
|
||||
CTL_E_PATHFILEACCESSERROR = STD_CTL_SCODE(75)
|
||||
CTL_E_PATHNOTFOUND = STD_CTL_SCODE(76)
|
||||
CTL_E_INVALIDPATTERNSTRING = STD_CTL_SCODE(93)
|
||||
CTL_E_INVALIDUSEOFNULL = STD_CTL_SCODE(94)
|
||||
CTL_E_INVALIDFILEFORMAT = STD_CTL_SCODE(321)
|
||||
CTL_E_INVALIDPROPERTYVALUE = STD_CTL_SCODE(380)
|
||||
CTL_E_INVALIDPROPERTYARRAYINDEX = STD_CTL_SCODE(381)
|
||||
CTL_E_SETNOTSUPPORTEDATRUNTIME = STD_CTL_SCODE(382)
|
||||
CTL_E_SETNOTSUPPORTED = STD_CTL_SCODE(383)
|
||||
CTL_E_NEEDPROPERTYARRAYINDEX = STD_CTL_SCODE(385)
|
||||
CTL_E_SETNOTPERMITTED = STD_CTL_SCODE(387)
|
||||
CTL_E_GETNOTSUPPORTEDATRUNTIME = STD_CTL_SCODE(393)
|
||||
CTL_E_GETNOTSUPPORTED = STD_CTL_SCODE(394)
|
||||
CTL_E_PROPERTYNOTFOUND = STD_CTL_SCODE(422)
|
||||
CTL_E_INVALIDCLIPBOARDFORMAT = STD_CTL_SCODE(460)
|
||||
CTL_E_INVALIDPICTURE = STD_CTL_SCODE(481)
|
||||
CTL_E_PRINTERERROR = STD_CTL_SCODE(482)
|
||||
CTL_E_CANTSAVEFILETOTEMP = STD_CTL_SCODE(735)
|
||||
CTL_E_SEARCHTEXTNOTFOUND = STD_CTL_SCODE(744)
|
||||
CTL_E_REPLACEMENTSTOOLONG = STD_CTL_SCODE(746)
|
||||
|
||||
CONNECT_E_FIRST = MAKE_SCODE(winerror.SEVERITY_ERROR, winerror.FACILITY_ITF, 0x0200)
|
||||
CONNECT_E_LAST = MAKE_SCODE(winerror.SEVERITY_ERROR, winerror.FACILITY_ITF, 0x020F)
|
||||
CONNECT_S_FIRST = MAKE_SCODE(winerror.SEVERITY_SUCCESS, winerror.FACILITY_ITF, 0x0200)
|
||||
CONNECT_S_LAST = MAKE_SCODE(winerror.SEVERITY_SUCCESS, winerror.FACILITY_ITF, 0x020F)
|
||||
|
||||
CONNECT_E_NOCONNECTION = CONNECT_E_FIRST+0
|
||||
CONNECT_E_ADVISELIMIT = CONNECT_E_FIRST+1
|
||||
CONNECT_E_CANNOTCONNECT = CONNECT_E_FIRST+2
|
||||
CONNECT_E_OVERRIDDEN = CONNECT_E_FIRST+3
|
||||
|
||||
CLASS_E_NOTLICENSED = winerror.CLASSFACTORY_E_FIRST+2
|
||||
|
87
venv/Lib/site-packages/win32com/readme.htm
Normal file
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>win32com Readme</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p><img width="551" height="99" id="_x0000_i1025"
|
||||
src="html%5Cimage%5Cpycom_blowing.gif"
|
||||
alt="Python and COM - Blowing the others away"> </p>
|
||||
|
||||
<h1>Python COM Extensions Readme </h1>
|
||||
|
||||
<p>This is the readme for win32com. Please check out the <a
|
||||
href="html/docindex.html">win32com documentation index</a></p>
|
||||
|
||||
<p>The <a href="test/.">win32com/test directory</a> contains some interesting
|
||||
scripts (and a new <a href="test/readme.txt">readme.txt</a>). Although these
|
||||
are used for testing, they do show a variety of COM techniques.</p>
|
||||
|
||||
<h3>VARIANT objects</h3>
|
||||
<p>win32com.client now has explicit VARIANT objects which can be used in
|
||||
situations where you need more control over the argument types passed when
|
||||
calling COM methods. See the <a href="html/variant.html">documentation on
|
||||
this object</a>
|
||||
|
||||
<a name="currency"><h3>Important Currency changes</h3></a>
|
||||
<p>
|
||||
In all builds prior to 204, a COM currency value was returned as a tuple of
|
||||
integers. Working with 2 integers to represent a currency object was a poor
|
||||
choice, but the alternative was never clear. Now Python ships with the
|
||||
<a href="http://www.python.org/dev/doc/devel/lib/module-decimal.html">decimal</a>
|
||||
module, the alternative has arrived!
|
||||
</p>
|
||||
<p>
|
||||
Up until build 212, code could set <code>pythoncom.__future_currency__ = True</code>
|
||||
to force use of the decimal module, with a warning issued otherwise. In
|
||||
builds 213 and later, the decimal module is unconditionally used when
|
||||
pythoncon returns you a currency value.
|
||||
</p>
|
||||
|
||||
<h3>Recent Changes</h3>
|
||||
|
||||
<h4>Lots of internal changes on the road to py3k</h4>
|
||||
|
||||
<h4>win32com.axcontrol and win2con.internet</h4>
|
||||
Many more interfaces for hosting AX controls and the interfaces
|
||||
used by Internet Explorer.
|
||||
|
||||
<h4>win32com.shell</h4>
|
||||
The shell interfaces have undergone a number of enhancements and changes.
|
||||
A couple of methods have changed signature between the first build with shell support (200) and later builds.
|
||||
SHGetFileInfo was broken in its result handling, so had to be changed - this
|
||||
is the only function used by the samples that changed, but others not used by the samples also have changed.
|
||||
These shell interfaces are now generally stable.
|
||||
<h4>New win32com.taskscheduler module</h4>
|
||||
Roger Upole has contributed an interface to the Windows task scheduler. This is actually very neat, and it allows
|
||||
Python to edit the task list as shown by Windows Control Panel. Property page suppport may even appear later,
|
||||
now that the win32 library has the new win32rcparser module.
|
||||
<h4>ActiveX Scripting </h4>
|
||||
|
||||
<p>Python only supports "trusted" execution hosts - thus, it will no longer work
|
||||
as an engine inside IE (Python itself no longer has a restricted execution environment).
|
||||
Python continues to work fine as an Active Scripting Engine in all other
|
||||
applications, including Windows Scripting Host, and ASP.
|
||||
|
||||
<p>There is also support for Python as an ActiveX Scripting Host.</p>
|
||||
|
||||
<p>Active Debugging seems to be fully functional.</p>
|
||||
|
||||
<h4>Older stuff</h4>
|
||||
<ul>
|
||||
</li>
|
||||
<li>Unexpected exceptions in Python COM objects will generally now dump
|
||||
the exception and traceback to stdout. This is useful for debugging
|
||||
and testing - it means that in some cases there will be no need to register
|
||||
an object with <span style="font-style: italic;">--debug</span> to see these
|
||||
tracebacks. Note that COM objects used by server processes (such as
|
||||
ASP) generally have no valid stdout, so will still need to use <span
|
||||
style="font-style: italic;">--debug</span> as usual.<br>
|
||||
</li>
|
||||
<li>universal gateway support has been improved - we can now work as an
|
||||
Outlook Addin<br>
|
||||
</li>
|
||||
|
||||
</body>
|
||||
</html>
|
1
venv/Lib/site-packages/win32com/server/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# Empty __init__ file to designate a sub-package.
|
65
venv/Lib/site-packages/win32com/server/connect.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
"""Utilities for Server Side connections.
|
||||
|
||||
A collection of helpers for server side connection points.
|
||||
"""
|
||||
import pythoncom
|
||||
from .exception import Exception
|
||||
import winerror
|
||||
from win32com import olectl
|
||||
import win32com.server.util
|
||||
|
||||
# Methods implemented by the interfaces.
|
||||
IConnectionPointContainer_methods = ["EnumConnectionPoints","FindConnectionPoint"]
|
||||
IConnectionPoint_methods = ["EnumConnections","Unadvise","Advise","GetConnectionPointContainer","GetConnectionInterface"]
|
||||
|
||||
class ConnectableServer:
|
||||
_public_methods_ = IConnectionPointContainer_methods + IConnectionPoint_methods
|
||||
_com_interfaces_ = [pythoncom.IID_IConnectionPoint, pythoncom.IID_IConnectionPointContainer]
|
||||
# Clients must set _connect_interfaces_ = [...]
|
||||
def __init__(self):
|
||||
self.cookieNo = 0
|
||||
self.connections = {}
|
||||
# IConnectionPoint interfaces
|
||||
def EnumConnections(self):
|
||||
raise Exception(winerror.E_NOTIMPL)
|
||||
def GetConnectionInterface(self):
|
||||
raise Exception(winerror.E_NOTIMPL)
|
||||
def GetConnectionPointContainer(self):
|
||||
return win32com.server.util.wrap(self)
|
||||
def Advise(self, pUnk):
|
||||
# Creates a connection to the client. Simply allocate a new cookie,
|
||||
# find the clients interface, and store it in a dictionary.
|
||||
try:
|
||||
interface = pUnk.QueryInterface(self._connect_interfaces_[0],pythoncom.IID_IDispatch)
|
||||
except pythoncom.com_error:
|
||||
raise Exception(scode=olectl.CONNECT_E_NOCONNECTION)
|
||||
self.cookieNo = self.cookieNo + 1
|
||||
self.connections[self.cookieNo] = interface
|
||||
return self.cookieNo
|
||||
def Unadvise(self, cookie):
|
||||
# Destroy a connection - simply delete interface from the map.
|
||||
try:
|
||||
del self.connections[cookie]
|
||||
except KeyError:
|
||||
raise Exception(scode=winerror.E_UNEXPECTED)
|
||||
# IConnectionPointContainer interfaces
|
||||
def EnumConnectionPoints(self):
|
||||
raise Exception(winerror.E_NOTIMPL)
|
||||
def FindConnectionPoint(self, iid):
|
||||
# Find a connection we support. Only support the single event interface.
|
||||
if iid in self._connect_interfaces_:
|
||||
return win32com.server.util.wrap(self)
|
||||
|
||||
def _BroadcastNotify(self, broadcaster, extraArgs):
|
||||
# Broadcasts a notification to all connections.
|
||||
# Ignores clients that fail.
|
||||
for interface in self.connections.values():
|
||||
try:
|
||||
broadcaster(*(interface,)+extraArgs)
|
||||
except pythoncom.com_error as details:
|
||||
self._OnNotifyFail(interface, details)
|
||||
|
||||
def _OnNotifyFail(self, interface, details):
|
||||
print("Ignoring COM error to connection - %s" % (repr(details)))
|
||||
|
||||
|
270
venv/Lib/site-packages/win32com/server/dispatcher.py
Normal file
|
@ -0,0 +1,270 @@
|
|||
"""Dispatcher
|
||||
|
||||
Please see policy.py for a discussion on dispatchers and policies
|
||||
"""
|
||||
import pythoncom, traceback, win32api
|
||||
from sys import exc_info
|
||||
|
||||
#
|
||||
from win32com.server.exception import IsCOMServerException
|
||||
from win32com.util import IIDToInterfaceName
|
||||
import win32com
|
||||
|
||||
class DispatcherBase:
|
||||
""" The base class for all Dispatchers.
|
||||
|
||||
This dispatcher supports wrapping all operations in exception handlers,
|
||||
and all the necessary delegation to the policy.
|
||||
|
||||
This base class supports the printing of "unexpected" exceptions. Note, however,
|
||||
that exactly where the output of print goes may not be useful! A derived class may
|
||||
provide additional semantics for this.
|
||||
"""
|
||||
def __init__(self, policyClass, object):
|
||||
self.policy = policyClass(object)
|
||||
# The logger we should dump to. If None, we should send to the
|
||||
# default location (typically 'print')
|
||||
self.logger = getattr(win32com, "logger", None)
|
||||
|
||||
# Note the "return self._HandleException_()" is purely to stop pychecker
|
||||
# complaining - _HandleException_ will itself raise an exception for the
|
||||
# pythoncom framework, so the result will never be seen.
|
||||
def _CreateInstance_(self, clsid, reqIID):
|
||||
try:
|
||||
self.policy._CreateInstance_(clsid, reqIID)
|
||||
return pythoncom.WrapObject(self, reqIID)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _QueryInterface_(self, iid):
|
||||
try:
|
||||
return self.policy._QueryInterface_(iid)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _Invoke_(self, dispid, lcid, wFlags, args):
|
||||
try:
|
||||
return self.policy._Invoke_(dispid, lcid, wFlags, args)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetIDsOfNames_(self, names, lcid):
|
||||
try:
|
||||
return self.policy._GetIDsOfNames_(names, lcid)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetTypeInfo_(self, index, lcid):
|
||||
try:
|
||||
return self.policy._GetTypeInfo_(index, lcid)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetTypeInfoCount_(self):
|
||||
try:
|
||||
return self.policy._GetTypeInfoCount_()
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetDispID_(self, name, fdex):
|
||||
try:
|
||||
return self.policy._GetDispID_(name, fdex)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
|
||||
try:
|
||||
return self.policy._InvokeEx_(dispid, lcid, wFlags, args, kwargs, serviceProvider)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _DeleteMemberByName_(self, name, fdex):
|
||||
try:
|
||||
return self.policy._DeleteMemberByName_(name, fdex)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _DeleteMemberByDispID_(self, id):
|
||||
try:
|
||||
return self.policy._DeleteMemberByDispID_(id)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetMemberProperties_(self, id, fdex):
|
||||
try:
|
||||
return self.policy._GetMemberProperties_(id, fdex)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetMemberName_(self, dispid):
|
||||
try:
|
||||
return self.policy._GetMemberName_(dispid)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetNextDispID_(self, fdex, flags):
|
||||
try:
|
||||
return self.policy._GetNextDispID_(fdex, flags)
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _GetNameSpaceParent_(self):
|
||||
try:
|
||||
return self.policy._GetNameSpaceParent_()
|
||||
except:
|
||||
return self._HandleException_()
|
||||
|
||||
def _HandleException_(self):
|
||||
"""Called whenever an exception is raised.
|
||||
|
||||
Default behaviour is to print the exception.
|
||||
"""
|
||||
# If not a COM exception, print it for the developer.
|
||||
if not IsCOMServerException():
|
||||
if self.logger is not None:
|
||||
self.logger.exception("pythoncom server error")
|
||||
else:
|
||||
traceback.print_exc()
|
||||
# But still raise it for the framework.
|
||||
raise
|
||||
|
||||
def _trace_(self, *args):
|
||||
if self.logger is not None:
|
||||
record = " ".join(map(str, args))
|
||||
self.logger.debug(record)
|
||||
else:
|
||||
for arg in args[:-1]:
|
||||
print(arg, end=' ')
|
||||
print(args[-1])
|
||||
|
||||
class DispatcherTrace(DispatcherBase):
|
||||
"""A dispatcher, which causes a 'print' line for each COM function called.
|
||||
"""
|
||||
def _QueryInterface_(self, iid):
|
||||
rc = DispatcherBase._QueryInterface_(self, iid)
|
||||
if not rc:
|
||||
self._trace_("in %s._QueryInterface_ with unsupported IID %s (%s)" % (repr(self.policy._obj_), IIDToInterfaceName(iid),iid))
|
||||
return rc
|
||||
|
||||
def _GetIDsOfNames_(self, names, lcid):
|
||||
self._trace_("in _GetIDsOfNames_ with '%s' and '%d'\n" % (names, lcid))
|
||||
return DispatcherBase._GetIDsOfNames_(self, names, lcid)
|
||||
|
||||
def _GetTypeInfo_(self, index, lcid):
|
||||
self._trace_("in _GetTypeInfo_ with index=%d, lcid=%d\n" % (index, lcid))
|
||||
return DispatcherBase._GetTypeInfo_(self, index, lcid)
|
||||
|
||||
def _GetTypeInfoCount_(self):
|
||||
self._trace_("in _GetTypeInfoCount_\n")
|
||||
return DispatcherBase._GetTypeInfoCount_(self)
|
||||
|
||||
def _Invoke_(self, dispid, lcid, wFlags, args):
|
||||
self._trace_("in _Invoke_ with", dispid, lcid, wFlags, args)
|
||||
return DispatcherBase._Invoke_(self, dispid, lcid, wFlags, args)
|
||||
|
||||
def _GetDispID_(self, name, fdex):
|
||||
self._trace_("in _GetDispID_ with", name, fdex)
|
||||
return DispatcherBase._GetDispID_(self, name, fdex)
|
||||
|
||||
def _InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider):
|
||||
self._trace_("in %r._InvokeEx_-%s%r [%x,%s,%r]" % (self.policy._obj_, dispid, args, wFlags, lcid, serviceProvider))
|
||||
return DispatcherBase._InvokeEx_(self, dispid, lcid, wFlags, args, kwargs, serviceProvider)
|
||||
|
||||
def _DeleteMemberByName_(self, name, fdex):
|
||||
self._trace_("in _DeleteMemberByName_ with", name, fdex)
|
||||
return DispatcherBase._DeleteMemberByName_(self, name, fdex)
|
||||
|
||||
def _DeleteMemberByDispID_(self, id):
|
||||
self._trace_("in _DeleteMemberByDispID_ with", id)
|
||||
return DispatcherBase._DeleteMemberByDispID_(self, id)
|
||||
|
||||
def _GetMemberProperties_(self, id, fdex):
|
||||
self._trace_("in _GetMemberProperties_ with", id, fdex)
|
||||
return DispatcherBase._GetMemberProperties_(self, id, fdex)
|
||||
|
||||
def _GetMemberName_(self, dispid):
|
||||
self._trace_("in _GetMemberName_ with", dispid)
|
||||
return DispatcherBase._GetMemberName_(self, dispid)
|
||||
|
||||
def _GetNextDispID_(self, fdex, flags):
|
||||
self._trace_("in _GetNextDispID_ with", fdex, flags)
|
||||
return DispatcherBase._GetNextDispID_(self, fdex, flags)
|
||||
|
||||
def _GetNameSpaceParent_(self):
|
||||
self._trace_("in _GetNameSpaceParent_")
|
||||
return DispatcherBase._GetNameSpaceParent_(self)
|
||||
|
||||
|
||||
class DispatcherWin32trace(DispatcherTrace):
|
||||
"""A tracing dispatcher that sends its output to the win32trace remote collector.
|
||||
|
||||
"""
|
||||
def __init__(self, policyClass, object):
|
||||
DispatcherTrace.__init__(self, policyClass, object)
|
||||
if self.logger is None:
|
||||
# If we have no logger, setup our output.
|
||||
import win32traceutil # Sets up everything.
|
||||
self._trace_("Object with win32trace dispatcher created (object=%s)" % repr(object))
|
||||
|
||||
|
||||
class DispatcherOutputDebugString(DispatcherTrace):
|
||||
"""A tracing dispatcher that sends its output to win32api.OutputDebugString
|
||||
|
||||
"""
|
||||
def _trace_(self, *args):
|
||||
for arg in args[:-1]:
|
||||
win32api.OutputDebugString(str(arg)+" ")
|
||||
win32api.OutputDebugString(str(args[-1])+"\n")
|
||||
|
||||
|
||||
class DispatcherWin32dbg(DispatcherBase):
|
||||
"""A source-level debugger dispatcher
|
||||
|
||||
A dispatcher which invokes the debugger as an object is instantiated, or
|
||||
when an unexpected exception occurs.
|
||||
|
||||
Requires Pythonwin.
|
||||
"""
|
||||
def __init__(self, policyClass, ob):
|
||||
# No one uses this, and it just causes py2exe to drag all of
|
||||
# pythonwin in.
|
||||
#import pywin.debugger
|
||||
pywin.debugger.brk()
|
||||
print("The DispatcherWin32dbg dispatcher is deprecated!")
|
||||
print("Please let me know if this is a problem.")
|
||||
print("Uncomment the relevant lines in dispatcher.py to re-enable")
|
||||
# DEBUGGER Note - You can either:
|
||||
# * Hit Run and wait for a (non Exception class) exception to occur!
|
||||
# * Set a breakpoint and hit run.
|
||||
# * Step into the object creation (a few steps away!)
|
||||
DispatcherBase.__init__(self, policyClass, ob)
|
||||
|
||||
def _HandleException_(self):
|
||||
""" Invoke the debugger post mortem capability """
|
||||
# Save details away.
|
||||
typ, val, tb = exc_info()
|
||||
#import pywin.debugger, pywin.debugger.dbgcon
|
||||
debug = 0
|
||||
try:
|
||||
raise typ(val)
|
||||
except Exception: # AARG - What is this Exception???
|
||||
# Use some inside knowledge to borrow a Debugger option which dictates if we
|
||||
# stop at "expected" exceptions.
|
||||
debug = pywin.debugger.GetDebugger().get_option(pywin.debugger.dbgcon.OPT_STOP_EXCEPTIONS)
|
||||
except:
|
||||
debug = 1
|
||||
if debug:
|
||||
try:
|
||||
pywin.debugger.post_mortem(tb, typ, val) # The original exception
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
# But still raise it.
|
||||
del tb
|
||||
raise
|
||||
|
||||
try:
|
||||
import win32trace
|
||||
DefaultDebugDispatcher = DispatcherWin32trace
|
||||
except ImportError: # no win32trace module - just use a print based one.
|
||||
DefaultDebugDispatcher = DispatcherTrace
|
91
venv/Lib/site-packages/win32com/server/exception.py
Normal file
|
@ -0,0 +1,91 @@
|
|||
"""Exception Handling
|
||||
|
||||
Exceptions
|
||||
|
||||
To better support COM exceptions, the framework allows for an instance to be
|
||||
raised. This instance may have a certain number of known attributes, which are
|
||||
translated into COM exception details.
|
||||
|
||||
This means, for example, that Python could raise a COM exception that includes details
|
||||
on a Help file and location, and a description for the user.
|
||||
|
||||
This module provides a class which provides the necessary attributes.
|
||||
|
||||
"""
|
||||
import sys, pythoncom
|
||||
|
||||
# Note that we derive from com_error, which derives from exceptions.Exception
|
||||
# Also note that we dont support "self.args", as we dont support tuple-unpacking
|
||||
class COMException(pythoncom.com_error):
|
||||
"""An Exception object that is understood by the framework.
|
||||
|
||||
If the framework is presented with an exception of type class,
|
||||
it looks for certain known attributes on this class to provide rich
|
||||
error information to the caller.
|
||||
|
||||
It should be noted that the framework supports providing this error
|
||||
information via COM Exceptions, or via the ISupportErrorInfo interface.
|
||||
|
||||
By using this class, you automatically provide rich error information to the
|
||||
server.
|
||||
"""
|
||||
def __init__(self, description = None, scode = None,
|
||||
source = None, helpfile = None, helpContext = None,
|
||||
desc = None, hresult = None):
|
||||
"""Initialize an exception
|
||||
**Params**
|
||||
|
||||
description -- A string description for the exception.
|
||||
scode -- An integer scode to be returned to the server, if necessary.
|
||||
The pythoncom framework defaults this to be DISP_E_EXCEPTION if not specified otherwise.
|
||||
source -- A string which identifies the source of the error.
|
||||
helpfile -- A string which points to a help file which contains details on the error.
|
||||
helpContext -- An integer context in the help file.
|
||||
desc -- A short-cut for description.
|
||||
hresult -- A short-cut for scode.
|
||||
"""
|
||||
|
||||
# convert a WIN32 error into an HRESULT
|
||||
scode = scode or hresult
|
||||
if scode and scode != 1: # We dont want S_FALSE mapped!
|
||||
if scode >= -32768 and scode < 32768:
|
||||
# this is HRESULT_FROM_WIN32()
|
||||
scode = -2147024896 | (scode & 0x0000FFFF)
|
||||
self.scode = scode
|
||||
|
||||
self.description = description or desc
|
||||
if scode==1 and not self.description:
|
||||
self.description = "S_FALSE"
|
||||
elif scode and not self.description:
|
||||
self.description = pythoncom.GetScodeString(scode)
|
||||
|
||||
self.source = source
|
||||
self.helpfile = helpfile
|
||||
self.helpcontext = helpContext
|
||||
|
||||
# todo - fill in the exception value
|
||||
pythoncom.com_error.__init__(self, scode, self.description, None, -1)
|
||||
|
||||
def __repr__(self):
|
||||
return "<COM Exception - scode=%s, desc=%s>" % (self.scode, self.description)
|
||||
|
||||
# Old name for the COMException class.
|
||||
# Do NOT use the name Exception, as it is now a built-in
|
||||
# COMException is the new, official name.
|
||||
Exception = COMException
|
||||
|
||||
def IsCOMException(t = None):
|
||||
if t is None:
|
||||
t = sys.exc_info()[0]
|
||||
try:
|
||||
return issubclass(t, pythoncom.com_error)
|
||||
except TypeError: # 1.5 in -X mode?
|
||||
return t is pythoncon.com_error
|
||||
|
||||
def IsCOMServerException(t = None):
|
||||
if t is None:
|
||||
t = sys.exc_info()[0]
|
||||
try:
|
||||
return issubclass(t, COMException)
|
||||
except TypeError: # String exception
|
||||
return 0
|
22
venv/Lib/site-packages/win32com/server/factory.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Class factory utilities.
|
||||
import pythoncom
|
||||
|
||||
def RegisterClassFactories(clsids, flags = None, clsctx = None):
|
||||
"""Given a list of CLSID, create and register class factories.
|
||||
|
||||
Returns a list, which should be passed to RevokeClassFactories
|
||||
"""
|
||||
if flags is None: flags = pythoncom.REGCLS_MULTIPLEUSE|pythoncom.REGCLS_SUSPENDED
|
||||
if clsctx is None: clsctx = pythoncom.CLSCTX_LOCAL_SERVER
|
||||
ret = []
|
||||
for clsid in clsids:
|
||||
# Some server append '-Embedding' etc
|
||||
if clsid[0] not in ['-', '/']:
|
||||
factory = pythoncom.MakePyFactory(clsid)
|
||||
regId = pythoncom.CoRegisterClassObject(clsid, factory, clsctx, flags)
|
||||
ret.append((factory, regId))
|
||||
return ret
|
||||
|
||||
def RevokeClassFactories(infos):
|
||||
for factory, revokeId in infos:
|
||||
pythoncom.CoRevokeClassObject(revokeId)
|
49
venv/Lib/site-packages/win32com/server/localserver.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
# LocalServer .EXE support for Python.
|
||||
#
|
||||
# This is designed to be used as a _script_ file by pythonw.exe
|
||||
#
|
||||
# In some cases, you could also use Python.exe, which will create
|
||||
# a console window useful for debugging.
|
||||
#
|
||||
# NOTE: When NOT running in any sort of debugging mode,
|
||||
# 'print' statements may fail, as sys.stdout is not valid!!!
|
||||
|
||||
#
|
||||
# Usage:
|
||||
# wpython.exe LocalServer.py clsid [, clsid]
|
||||
import sys
|
||||
sys.coinit_flags = 2
|
||||
import pythoncom
|
||||
import win32api
|
||||
from win32com.server import factory
|
||||
|
||||
usage = """\
|
||||
Invalid command line arguments
|
||||
|
||||
This program provides LocalServer COM support
|
||||
for Python COM objects.
|
||||
|
||||
It is typically run automatically by COM, passing as arguments
|
||||
The ProgID or CLSID of the Python Server(s) to be hosted
|
||||
"""
|
||||
|
||||
def serve(clsids):
|
||||
infos = factory.RegisterClassFactories(clsids)
|
||||
|
||||
pythoncom.EnableQuitMessage(win32api.GetCurrentThreadId())
|
||||
pythoncom.CoResumeClassObjects()
|
||||
|
||||
pythoncom.PumpMessages()
|
||||
|
||||
factory.RevokeClassFactories( infos )
|
||||
|
||||
pythoncom.CoUninitialize()
|
||||
|
||||
def main():
|
||||
if len(sys.argv)==1:
|
||||
win32api.MessageBox(0, usage, "Python COM Server")
|
||||
sys.exit(1)
|
||||
serve(sys.argv[1:])
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|