mirror of
https://github.com/aykhans/AzSuicideDataVisualization.git
synced 2025-07-01 22:13:01 +00:00
first commit
This commit is contained in:
57
.venv/Lib/site-packages/win32com/client/CLSIDToClass.py
Normal file
57
.venv/Lib/site-packages/win32com/client/CLSIDToClass.py
Normal file
@ -0,0 +1,57 @@
|
||||
"""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
|
712
.venv/Lib/site-packages/win32com/client/__init__.py
Normal file
712
.venv/Lib/site-packages/win32com/client/__init__.py
Normal file
@ -0,0 +1,712 @@
|
||||
# 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 __dir__(self):
|
||||
return dynamic.CDispatch.__dir__(self)
|
||||
|
||||
|
||||
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__
|
||||
|
||||
def __dir__(self):
|
||||
lst = (
|
||||
list(self.__dict__.keys())
|
||||
+ dir(self.__class__)
|
||||
+ list(self._prop_map_get_.keys())
|
||||
+ list(self._prop_map_put_.keys())
|
||||
)
|
||||
try:
|
||||
lst += [p.Name for p in self.Properties_]
|
||||
except AttributeError:
|
||||
pass
|
||||
return list(set(lst))
|
||||
|
||||
# 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)
|
||||
dispobj = self.__dict__["_dispobj_"] = self.default_interface(oobj)
|
||||
# See comments below re the special methods.
|
||||
for maybe in [
|
||||
"__call__",
|
||||
"__str__",
|
||||
"__int__",
|
||||
"__iter__",
|
||||
"__len__",
|
||||
"__nonzero__",
|
||||
]:
|
||||
if hasattr(dispobj, maybe):
|
||||
setattr(self, maybe, getattr(self, "__maybe" + maybe))
|
||||
|
||||
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
|
||||
|
||||
# Special methods don't use __getattr__ etc, so explicitly delegate here.
|
||||
# Note however, that not all are safe to let bubble up - things like
|
||||
# `bool(ob)` will break if the object defines __int__ but then raises an
|
||||
# attribute error - eg, see #1753.
|
||||
# It depends on what the wrapped COM object actually defines whether these
|
||||
# will exist on the underlying object, so __init__ explicitly checks if they
|
||||
# do and if so, wires them up.
|
||||
|
||||
def __maybe__call__(self, *args, **kwargs):
|
||||
return self.__dict__["_dispobj_"].__call__(*args, **kwargs)
|
||||
|
||||
def __maybe__str__(self, *args):
|
||||
return self.__dict__["_dispobj_"].__str__(*args)
|
||||
|
||||
def __maybe__int__(self, *args):
|
||||
return self.__dict__["_dispobj_"].__int__(*args)
|
||||
|
||||
def __maybe__iter__(self):
|
||||
return self.__dict__["_dispobj_"].__iter__()
|
||||
|
||||
def __maybe__len__(self):
|
||||
return self.__dict__["_dispobj_"].__len__()
|
||||
|
||||
def __maybe__nonzero__(self):
|
||||
return self.__dict__["_dispobj_"].__nonzero__()
|
||||
|
||||
|
||||
# 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)
|
788
.venv/Lib/site-packages/win32com/client/build.py
Normal file
788
.venv/Lib/site-packages/win32com/client/build.py
Normal file
@ -0,0 +1,788 @@
|
||||
"""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 __repr__(self):
|
||||
return (
|
||||
"MapEntry(dispid={s.dispid}, desc={s.desc}, names={s.names}, doc={s.doc!r}, "
|
||||
"resultCLSID={s.resultCLSID}, resultDocumentation={s.resultDocumentation}, "
|
||||
"wasProperty={s.wasProperty}, hidden={s.hidden}"
|
||||
).format(s=self)
|
||||
|
||||
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):
|
||||
assert fdesc.desckind == pythoncom.DESCKIND_FUNCDESC
|
||||
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(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, vardesc, bForUser):
|
||||
### need pythoncom.VARFLAG_FRESTRICTED ...
|
||||
### then check it
|
||||
assert vardesc.desckind == pythoncom.DESCKIND_VARDESC
|
||||
|
||||
if vardesc.varkind == pythoncom.VAR_DISPATCH:
|
||||
id = vardesc.memid
|
||||
names = typeinfo.GetNames(id)
|
||||
# Translate any Alias or Enums in result.
|
||||
typerepr, flags, defval = vardesc.elemdescVar
|
||||
typerepr, resultCLSID, resultDoc = _ResolveType(typerepr, typeinfo)
|
||||
vardesc.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 = (vardesc.wVarFlags & 0x40) != 0 # VARFLAG_FHIDDEN
|
||||
map[names[0]] = MapEntry(
|
||||
vardesc, 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]))
|
||||
|
||||
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")
|
619
.venv/Lib/site-packages/win32com/client/combrowse.py
Normal file
619
.venv/Lib/site-packages/win32com/client/combrowse.py
Normal file
@ -0,0 +1,619 @@
|
||||
"""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(modal=False):
|
||||
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)
|
||||
if modal:
|
||||
dlg.DoModal()
|
||||
else:
|
||||
dlg.CreateWindow()
|
||||
dlg.ShowWindow()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
ni = pythoncom._GetInterfaceCount()
|
||||
ng = pythoncom._GetGatewayCount()
|
||||
if ni or ng:
|
||||
print("Warning - exiting with %d/%d objects alive" % (ni, ng))
|
47
.venv/Lib/site-packages/win32com/client/connect.py
Normal file
47
.venv/Lib/site-packages/win32com/client/connect.py
Normal file
@ -0,0 +1,47 @@
|
||||
"""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
|
709
.venv/Lib/site-packages/win32com/client/dynamic.py
Normal file
709
.venv/Lib/site-packages/win32com/client/dynamic.py
Normal file
@ -0,0 +1,709 @@
|
||||
"""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()
|
||||
|
||||
|
||||
def MakeMethod(func, inst, cls):
|
||||
return types.MethodType(func, inst)
|
||||
|
||||
|
||||
# get the type objects for IDispatch and IUnknown
|
||||
PyIDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
|
||||
PyIUnknownType = pythoncom.TypeIIDs[pythoncom.IID_IUnknown]
|
||||
|
||||
_GoodDispatchTypes = (str, IIDType)
|
||||
_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:
|
||||
if isinstance(IDispatch, str):
|
||||
userName = IDispatch
|
||||
## ??? else userName remains None ???
|
||||
else:
|
||||
userName = str(userName)
|
||||
return (_GetGoodDispatch(IDispatch, clsctx), userName)
|
||||
|
||||
|
||||
def _GetDescInvokeType(entry, invoke_type):
|
||||
# determine the wFlags argument passed as input to IDispatch::Invoke
|
||||
# Only ever called by __getattr__ and __setattr__ from dynamic objects!
|
||||
# * `entry` is a MapEntry with whatever typeinfo we have about the property we are getting/setting.
|
||||
# * `invoke_type` is either INVOKE_PROPERTYGET | INVOKE_PROPERTYSET and really just
|
||||
# means "called by __getattr__" or "called by __setattr__"
|
||||
if not entry or not entry.desc:
|
||||
return invoke_type
|
||||
|
||||
if entry.desc.desckind == pythoncom.DESCKIND_VARDESC:
|
||||
return invoke_type
|
||||
|
||||
# So it's a FUNCDESC - just use what it specifies.
|
||||
return entry.desc.invkind
|
||||
|
||||
|
||||
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__()
|
||||
|
||||
def __dir__(self):
|
||||
lst = list(self.__dict__.keys()) + dir(self.__class__) + self._dir_ole_()
|
||||
try:
|
||||
lst += [p.Name for p in self.Properties_]
|
||||
except AttributeError:
|
||||
pass
|
||||
return list(set(lst))
|
||||
|
||||
def _dir_ole_(self):
|
||||
items_dict = {}
|
||||
for iTI in range(0, self._oleobj_.GetTypeInfoCount()):
|
||||
typeInfo = self._oleobj_.GetTypeInfo(iTI)
|
||||
self._UpdateWithITypeInfo_(items_dict, typeInfo)
|
||||
return list(items_dict.keys())
|
||||
|
||||
def _UpdateWithITypeInfo_(self, items_dict, typeInfo):
|
||||
typeInfos = [typeInfo]
|
||||
# suppress IDispatch and IUnknown methods
|
||||
inspectedIIDs = {pythoncom.IID_IDispatch: None}
|
||||
|
||||
while len(typeInfos) > 0:
|
||||
typeInfo = typeInfos.pop()
|
||||
typeAttr = typeInfo.GetTypeAttr()
|
||||
|
||||
if typeAttr.iid not in inspectedIIDs:
|
||||
inspectedIIDs[typeAttr.iid] = None
|
||||
for iFun in range(0, typeAttr.cFuncs):
|
||||
funDesc = typeInfo.GetFuncDesc(iFun)
|
||||
funName = typeInfo.GetNames(funDesc.memid)[0]
|
||||
if funName not in items_dict:
|
||||
items_dict[funName] = None
|
||||
|
||||
# Inspect the type info of all implemented types
|
||||
# E.g. IShellDispatch5 implements IShellDispatch4 which implements IShellDispatch3 ...
|
||||
for iImplType in range(0, typeAttr.cImplTypes):
|
||||
iRefType = typeInfo.GetRefTypeOfImplType(iImplType)
|
||||
refTypeInfo = typeInfo.GetRefTypeInfo(iRefType)
|
||||
typeInfos.append(refTypeInfo)
|
||||
|
||||
# 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 == pythoncom.DESCKIND_FUNCDESC: # it's a FUNCDESC
|
||||
r = olerepr._AddFunc_(typeinfo, t, 0)
|
||||
elif x == pythoncom.DESCKIND_VARDESC: # 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 retEntry is not 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 retEntry is not 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)
|
||||
)
|
796
.venv/Lib/site-packages/win32com/client/gencache.py
Normal file
796
.venv/Lib/site-packages/win32com/client/gencache.py
Normal file
@ -0,0 +1,796 @@
|
||||
"""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
|
||||
from importlib import reload
|
||||
|
||||
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
|
||||
info = str(typelibclsid), lcid, major, minor
|
||||
dict_modified = False
|
||||
|
||||
def SetTypelibForAllClsids(dict):
|
||||
nonlocal dict_modified
|
||||
for clsid, cls in dict.items():
|
||||
if clsidToTypelib.get(clsid) != info:
|
||||
clsidToTypelib[clsid] = info
|
||||
dict_modified = True
|
||||
|
||||
SetTypelibForAllClsids(mod.CLSIDToClassMap)
|
||||
SetTypelibForAllClsids(mod.CLSIDToPackageMap)
|
||||
SetTypelibForAllClsids(mod.VTablesToClassMap)
|
||||
SetTypelibForAllClsids(mod.VTablesToPackageMap)
|
||||
|
||||
# If this lib was previously redirected, drop it
|
||||
if info in versionRedirectMap:
|
||||
del versionRedirectMap[info]
|
||||
if bFlushNow and dict_modified:
|
||||
_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
|
1409
.venv/Lib/site-packages/win32com/client/genpy.py
Normal file
1409
.venv/Lib/site-packages/win32com/client/genpy.py
Normal file
File diff suppressed because it is too large
Load Diff
455
.venv/Lib/site-packages/win32com/client/makepy.py
Normal file
455
.venv/Lib/site-packages/win32com/client/makepy.py
Normal file
@ -0,0 +1,455 @@
|
||||
# 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, importlib, 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)
|
||||
importlib.invalidate_caches()
|
||||
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")
|
||||
importlib.invalidate_caches()
|
||||
__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)
|
181
.venv/Lib/site-packages/win32com/client/selecttlb.py
Normal file
181
.venv/Lib/site-packages/win32com/client/selecttlb.py
Normal file
@ -0,0 +1,181 @@
|
||||
"""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
|
||||
# Check for both "{lcid}\win32" and "{lcid}\win64" keys.
|
||||
try:
|
||||
key4 = win32api.RegOpenKey(key3, "%s\\win32" % (lcid,))
|
||||
except win32api.error:
|
||||
try:
|
||||
key4 = win32api.RegOpenKey(key3, "%s\\win64" % (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__)
|
280
.venv/Lib/site-packages/win32com/client/tlbrowse.py
Normal file
280
.venv/Lib/site-packages/win32com/client/tlbrowse.py
Normal file
@ -0,0 +1,280 @@
|
||||
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())
|
102
.venv/Lib/site-packages/win32com/client/util.py
Normal file
102
.venv/Lib/site-packages/win32com/client/util.py
Normal file
@ -0,0 +1,102 @@
|
||||
"""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)
|
Reference in New Issue
Block a user