Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
53
venv/Lib/site-packages/win32com/client/CLSIDToClass.py
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
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)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
630
venv/Lib/site-packages/win32com/client/build.py
Normal file
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
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
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
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
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
1074
venv/Lib/site-packages/win32com/client/genpy.py
Normal file
File diff suppressed because it is too large
Load diff
390
venv/Lib/site-packages/win32com/client/makepy.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
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
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
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)
|
Loading…
Add table
Add a link
Reference in a new issue