You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/comtypes/automation.py

882 lines
28 KiB

# comtypes.automation module
import array
import datetime
import decimal
from ctypes import *
from ctypes import _Pointer
from _ctypes import CopyComPointer
from comtypes import IUnknown, GUID, IID, STDMETHOD, BSTR, COMMETHOD, COMError
from comtypes.hresult import *
from comtypes.patcher import Patch
from comtypes import npsupport
try:
from comtypes import _safearray
except (ImportError, AttributeError):
class _safearray(object):
tagSAFEARRAY = None
from ctypes.wintypes import DWORD, LONG, UINT, VARIANT_BOOL, WCHAR, WORD
LCID = DWORD
DISPID = LONG
SCODE = LONG
VARTYPE = c_ushort
DISPATCH_METHOD = 1
DISPATCH_PROPERTYGET = 2
DISPATCH_PROPERTYPUT = 4
DISPATCH_PROPERTYPUTREF = 8
tagINVOKEKIND = c_int
INVOKE_FUNC = DISPATCH_METHOD
INVOKE_PROPERTYGET = DISPATCH_PROPERTYGET
INVOKE_PROPERTYPUT = DISPATCH_PROPERTYPUT
INVOKE_PROPERTYPUTREF = DISPATCH_PROPERTYPUTREF
INVOKEKIND = tagINVOKEKIND
################################
# helpers
IID_NULL = GUID()
riid_null = byref(IID_NULL)
_byref_type = type(byref(c_int()))
# 30. December 1899, midnight. For VT_DATE.
_com_null_date = datetime.datetime(1899, 12, 30, 0, 0, 0)
################################################################
# VARIANT, in all it's glory.
VARENUM = c_int # enum
VT_EMPTY = 0
VT_NULL = 1
VT_I2 = 2
VT_I4 = 3
VT_R4 = 4
VT_R8 = 5
VT_CY = 6
VT_DATE = 7
VT_BSTR = 8
VT_DISPATCH = 9
VT_ERROR = 10
VT_BOOL = 11
VT_VARIANT = 12
VT_UNKNOWN = 13
VT_DECIMAL = 14
VT_I1 = 16
VT_UI1 = 17
VT_UI2 = 18
VT_UI4 = 19
VT_I8 = 20
VT_UI8 = 21
VT_INT = 22
VT_UINT = 23
VT_VOID = 24
VT_HRESULT = 25
VT_PTR = 26
VT_SAFEARRAY = 27
VT_CARRAY = 28
VT_USERDEFINED = 29
VT_LPSTR = 30
VT_LPWSTR = 31
VT_RECORD = 36
VT_INT_PTR = 37
VT_UINT_PTR = 38
VT_FILETIME = 64
VT_BLOB = 65
VT_STREAM = 66
VT_STORAGE = 67
VT_STREAMED_OBJECT = 68
VT_STORED_OBJECT = 69
VT_BLOB_OBJECT = 70
VT_CF = 71
VT_CLSID = 72
VT_VERSIONED_STREAM = 73
VT_BSTR_BLOB = 4095
VT_VECTOR = 4096
VT_ARRAY = 8192
VT_BYREF = 16384
VT_RESERVED = 32768
VT_ILLEGAL = 65535
VT_ILLEGALMASKED = 4095
VT_TYPEMASK = 4095
class tagCY(Structure):
_fields_ = [("int64", c_longlong)]
CY = tagCY
CURRENCY = CY
class tagDEC(Structure):
_fields_ = [("wReserved", c_ushort),
("scale", c_ubyte),
("sign", c_ubyte),
("Hi32", c_ulong),
("Lo64", c_ulonglong)]
def as_decimal(self):
""" Convert a tagDEC struct to Decimal.
See http://msdn.microsoft.com/en-us/library/cc234586.aspx for the tagDEC
specification.
"""
digits = (self.Hi32 << 64) + self.Lo64
decimal_str = "{0}{1}e-{2}".format(
'-' if self.sign else '',
digits,
self.scale,
)
return decimal.Decimal(decimal_str)
DECIMAL = tagDEC
# The VARIANT structure is a good candidate for implementation in a C
# helper extension. At least the get/set methods.
class tagVARIANT(Structure):
class U_VARIANT1(Union):
class __tagVARIANT(Structure):
# The C Header file defn of VARIANT is much more complicated, but
# this is the ctypes version - functional as well.
class U_VARIANT2(Union):
class _tagBRECORD(Structure):
_fields_ = [("pvRecord", c_void_p),
("pRecInfo", POINTER(IUnknown))]
_fields_ = [
("VT_BOOL", VARIANT_BOOL),
("VT_I1", c_byte),
("VT_I2", c_short),
("VT_I4", c_long),
("VT_I8", c_longlong),
("VT_INT", c_int),
("VT_UI1", c_ubyte),
("VT_UI2", c_ushort),
("VT_UI4", c_ulong),
("VT_UI8", c_ulonglong),
("VT_UINT", c_uint),
("VT_R4", c_float),
("VT_R8", c_double),
("VT_CY", c_longlong),
("c_wchar_p", c_wchar_p),
("c_void_p", c_void_p),
("pparray", POINTER(POINTER(_safearray.tagSAFEARRAY))),
("bstrVal", BSTR),
("_tagBRECORD", _tagBRECORD),
]
_anonymous_ = ["_tagBRECORD"]
_fields_ = [("vt", VARTYPE),
("wReserved1", c_ushort),
("wReserved2", c_ushort),
("wReserved3", c_ushort),
("_", U_VARIANT2)
]
_fields_ = [("__VARIANT_NAME_2", __tagVARIANT),
("decVal", DECIMAL)]
_anonymous_ = ["__VARIANT_NAME_2"]
_fields_ = [("__VARIANT_NAME_1", U_VARIANT1)]
_anonymous_ = ["__VARIANT_NAME_1"]
def __init__(self, *args):
if args:
self.value = args[0]
def __del__(self):
if self._b_needsfree_:
# XXX This does not work. _b_needsfree_ is never
# set because the buffer is internal to the object.
_VariantClear(self)
def __repr__(self):
if self.vt & VT_BYREF:
return "VARIANT(vt=0x%x, byref(%r))" % (self.vt, self[0])
return "VARIANT(vt=0x%x, %r)" % (self.vt, self.value)
def from_param(cls, value):
if isinstance(value, cls):
return value
return cls(value)
from_param = classmethod(from_param)
def __setitem__(self, index, value):
# This method allows to change the value of a
# (VT_BYREF|VT_xxx) variant in place.
if index != 0:
raise IndexError(index)
if not self.vt & VT_BYREF:
raise TypeError("set_byref requires a VT_BYREF VARIANT instance")
typ = _vartype_to_ctype[self.vt & ~VT_BYREF]
cast(self._.c_void_p, POINTER(typ))[0] = value
# see also c:/sf/pywin32/com/win32com/src/oleargs.cpp 54
def _set_value(self, value):
_VariantClear(self)
if value is None:
self.vt = VT_NULL
elif (hasattr(value, '__len__') and len(value) == 0
and not isinstance(value, str)):
self.vt = VT_NULL
# since bool is a subclass of int, this check must come before
# the check for int
elif isinstance(value, bool):
self.vt = VT_BOOL
self._.VT_BOOL = value
elif isinstance(value, (int, c_int)):
self.vt = VT_I4
self._.VT_I4 = value
elif isinstance(value, int):
u = self._
# try VT_I4 first.
u.VT_I4 = value
if u.VT_I4 == value:
# it did work.
self.vt = VT_I4
return
# try VT_UI4 next.
if value >= 0:
u.VT_UI4 = value
if u.VT_UI4 == value:
# did work.
self.vt = VT_UI4
return
# try VT_I8 next.
if value >= 0:
u.VT_I8 = value
if u.VT_I8 == value:
# did work.
self.vt = VT_I8
return
# try VT_UI8 next.
if value >= 0:
u.VT_UI8 = value
if u.VT_UI8 == value:
# did work.
self.vt = VT_UI8
return
# VT_R8 is last resort.
self.vt = VT_R8
u.VT_R8 = float(value)
elif isinstance(value, (float, c_double)):
self.vt = VT_R8
self._.VT_R8 = value
elif isinstance(value, str):
self.vt = VT_BSTR
# do the c_wchar_p auto unicode conversion
self._.c_void_p = _SysAllocStringLen(value, len(value))
elif isinstance(value, datetime.datetime):
delta = value - _com_null_date
# a day has 24 * 60 * 60 = 86400 seconds
com_days = delta.days + (delta.seconds + delta.microseconds * 1e-6) / 86400.
self.vt = VT_DATE
self._.VT_R8 = com_days
elif npsupport.isdatetime64(value):
com_days = value - npsupport.com_null_date64
com_days /= npsupport.numpy.timedelta64(1, 'D')
self.vt = VT_DATE
self._.VT_R8 = com_days
elif decimal is not None and isinstance(value, decimal.Decimal):
self._.VT_CY = int(round(value * 10000))
self.vt = VT_CY
elif isinstance(value, POINTER(IDispatch)):
CopyComPointer(value, byref(self._))
self.vt = VT_DISPATCH
elif isinstance(value, POINTER(IUnknown)):
CopyComPointer(value, byref(self._))
self.vt = VT_UNKNOWN
elif isinstance(value, (list, tuple)):
obj = _midlSAFEARRAY(VARIANT).create(value)
memmove(byref(self._), byref(obj), sizeof(obj))
self.vt = VT_ARRAY | obj._vartype_
elif isinstance(value, array.array):
vartype = _arraycode_to_vartype[value.typecode]
typ = _vartype_to_ctype[vartype]
obj = _midlSAFEARRAY(typ).create(value)
memmove(byref(self._), byref(obj), sizeof(obj))
self.vt = VT_ARRAY | obj._vartype_
elif npsupport.isndarray(value):
# Try to convert a simple array of basic types.
descr = value.dtype.descr[0][1]
typ = npsupport.numpy.ctypeslib._typecodes.get(descr)
if typ is None:
# Try for variant
obj = _midlSAFEARRAY(VARIANT).create(value)
else:
obj = _midlSAFEARRAY(typ).create(value)
memmove(byref(self._), byref(obj), sizeof(obj))
self.vt = VT_ARRAY | obj._vartype_
elif isinstance(value, Structure) and hasattr(value, "_recordinfo_"):
guids = value._recordinfo_
from comtypes.typeinfo import GetRecordInfoFromGuids
ri = GetRecordInfoFromGuids(*guids)
self.vt = VT_RECORD
# Assigning a COM pointer to a structure field does NOT
# call AddRef(), have to call it manually:
ri.AddRef()
self._.pRecInfo = ri
self._.pvRecord = ri.RecordCreateCopy(byref(value))
elif isinstance(getattr(value, "_comobj", None), POINTER(IDispatch)):
CopyComPointer(value._comobj, byref(self._))
self.vt = VT_DISPATCH
elif isinstance(value, VARIANT):
_VariantCopy(self, value)
elif isinstance(value, c_ubyte):
self._.VT_UI1 = value
self.vt = VT_UI1
elif isinstance(value, c_char):
self._.VT_UI1 = ord(value.value)
self.vt = VT_UI1
elif isinstance(value, c_byte):
self._.VT_I1 = value
self.vt = VT_I1
elif isinstance(value, c_ushort):
self._.VT_UI2 = value
self.vt = VT_UI2
elif isinstance(value, c_short):
self._.VT_I2 = value
self.vt = VT_I2
elif isinstance(value, c_uint):
self.vt = VT_UI4
self._.VT_UI4 = value
elif isinstance(value, c_float):
self.vt = VT_R4
self._.VT_R4 = value
elif isinstance(value, c_int64):
self.vt = VT_I8
self._.VT_I8 = value
elif isinstance(value, c_uint64):
self.vt = VT_UI8
self._.VT_UI8 = value
elif isinstance(value, _byref_type):
ref = value._obj
self._.c_void_p = addressof(ref)
self.__keepref = value
self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
elif isinstance(value, _Pointer):
ref = value.contents
self._.c_void_p = addressof(ref)
self.__keepref = value
self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
else:
raise TypeError("Cannot put %r in VARIANT" % value)
# buffer -> SAFEARRAY of VT_UI1 ?
# c:/sf/pywin32/com/win32com/src/oleargs.cpp 197
def _get_value(self, dynamic=False):
vt = self.vt
if vt in (VT_EMPTY, VT_NULL):
return None
elif vt == VT_I1:
return self._.VT_I1
elif vt == VT_I2:
return self._.VT_I2
elif vt == VT_I4:
return self._.VT_I4
elif vt == VT_I8:
return self._.VT_I8
elif vt == VT_UI8:
return self._.VT_UI8
elif vt == VT_INT:
return self._.VT_INT
elif vt == VT_UI1:
return self._.VT_UI1
elif vt == VT_UI2:
return self._.VT_UI2
elif vt == VT_UI4:
return self._.VT_UI4
elif vt == VT_UINT:
return self._.VT_UINT
elif vt == VT_R4:
return self._.VT_R4
elif vt == VT_R8:
return self._.VT_R8
elif vt == VT_BOOL:
return self._.VT_BOOL
elif vt == VT_BSTR:
return self._.bstrVal
elif vt == VT_DATE:
days = self._.VT_R8
return datetime.timedelta(days=days) + _com_null_date
elif vt == VT_CY:
return self._.VT_CY / decimal.Decimal("10000")
elif vt == VT_UNKNOWN:
val = self._.c_void_p
if not val:
# We should/could return a NULL COM pointer.
# But the code generation must be able to construct one
# from the __repr__ of it.
return None # XXX?
ptr = cast(val, POINTER(IUnknown))
# cast doesn't call AddRef (it should, imo!)
ptr.AddRef()
return ptr.__ctypes_from_outparam__()
elif vt == VT_DECIMAL:
return self.decVal.as_decimal()
elif vt == VT_DISPATCH:
val = self._.c_void_p
if not val:
# See above.
return None # XXX?
ptr = cast(val, POINTER(IDispatch))
# cast doesn't call AddRef (it should, imo!)
ptr.AddRef()
if not dynamic:
return ptr.__ctypes_from_outparam__()
else:
from comtypes.client.dynamic import Dispatch
return Dispatch(ptr)
# see also c:/sf/pywin32/com/win32com/src/oleargs.cpp
elif self.vt & VT_BYREF:
return self
elif vt == VT_RECORD:
from comtypes.client import GetModule
from comtypes.typeinfo import IRecordInfo
# Retrieving a COM pointer from a structure field does NOT
# call AddRef(), have to call it manually:
punk = self._.pRecInfo
punk.AddRef()
ri = punk.QueryInterface(IRecordInfo)
# find typelib
tlib = ri.GetTypeInfo().GetContainingTypeLib()[0]
# load typelib wrapper module
mod = GetModule(tlib)
# retrive the type and create an instance
value = getattr(mod, ri.GetName())()
# copy data into the instance
ri.RecordCopy(self._.pvRecord, byref(value))
return value
elif self.vt & VT_ARRAY:
typ = _vartype_to_ctype[self.vt & ~VT_ARRAY]
return cast(self._.pparray, _midlSAFEARRAY(typ)).unpack()
else:
raise NotImplementedError("typecode %d = 0x%x)" % (vt, vt))
def __getitem__(self, index):
if index != 0:
raise IndexError(index)
if self.vt == VT_BYREF|VT_VARIANT:
v = VARIANT()
# apparently VariantCopyInd doesn't work always with
# VT_BYREF|VT_VARIANT, so do it manually.
v = cast(self._.c_void_p, POINTER(VARIANT))[0]
return v.value
else:
v = VARIANT()
_VariantCopyInd(v, self)
return v.value
# these are missing:
## getter[VT_ERROR]
## getter[VT_ARRAY]
## getter[VT_BYREF|VT_UI1]
## getter[VT_BYREF|VT_I2]
## getter[VT_BYREF|VT_I4]
## getter[VT_BYREF|VT_R4]
## getter[VT_BYREF|VT_R8]
## getter[VT_BYREF|VT_BOOL]
## getter[VT_BYREF|VT_ERROR]
## getter[VT_BYREF|VT_CY]
## getter[VT_BYREF|VT_DATE]
## getter[VT_BYREF|VT_BSTR]
## getter[VT_BYREF|VT_UNKNOWN]
## getter[VT_BYREF|VT_DISPATCH]
## getter[VT_BYREF|VT_ARRAY]
## getter[VT_BYREF|VT_VARIANT]
## getter[VT_BYREF]
## getter[VT_BYREF|VT_DECIMAL]
## getter[VT_BYREF|VT_I1]
## getter[VT_BYREF|VT_UI2]
## getter[VT_BYREF|VT_UI4]
## getter[VT_BYREF|VT_INT]
## getter[VT_BYREF|VT_UINT]
value = property(_get_value, _set_value)
def __ctypes_from_outparam__(self):
# XXX Manual resource management, because of the VARIANT bug:
result = self.value
self.value = None
return result
def ChangeType(self, typecode):
_VariantChangeType(self,
self,
0,
typecode)
VARIANT = tagVARIANT
VARIANTARG = VARIANT
_oleaut32 = OleDLL("oleaut32")
_VariantChangeType = _oleaut32.VariantChangeType
_VariantChangeType.argtypes = (POINTER(VARIANT), POINTER(VARIANT), c_ushort, VARTYPE)
_VariantClear = _oleaut32.VariantClear
_VariantClear.argtypes = (POINTER(VARIANT),)
_SysAllocStringLen = windll.oleaut32.SysAllocStringLen
_SysAllocStringLen.argtypes = c_wchar_p, c_uint
_SysAllocStringLen.restype = c_void_p
_VariantCopy = _oleaut32.VariantCopy
_VariantCopy.argtypes = POINTER(VARIANT), POINTER(VARIANT)
_VariantCopyInd = _oleaut32.VariantCopyInd
_VariantCopyInd.argtypes = POINTER(VARIANT), POINTER(VARIANT)
# some commonly used VARIANT instances
VARIANT.null = VARIANT(None)
VARIANT.empty = VARIANT()
VARIANT.missing = v = VARIANT()
v.vt = VT_ERROR
v._.VT_I4 = 0x80020004
del v
_carg_obj = type(byref(c_int()))
from _ctypes import Array as _CArrayType
@Patch(POINTER(VARIANT))
class _(object):
# Override the default .from_param classmethod of POINTER(VARIANT).
# This allows to pass values which can be stored in VARIANTs as
# function parameters declared as POINTER(VARIANT). See
# InternetExplorer's Navigate2() method, or Word's Close() method, for
# examples.
def from_param(cls, arg):
# accept POINTER(VARIANT) instance
if isinstance(arg, POINTER(VARIANT)):
return arg
# accept byref(VARIANT) instance
if isinstance(arg, _carg_obj) and isinstance(arg._obj, VARIANT):
return arg
# accept VARIANT instance
if isinstance(arg, VARIANT):
return byref(arg)
if isinstance(arg, _CArrayType) and arg._type_ is VARIANT:
# accept array of VARIANTs
return arg
# anything else which can be converted to a VARIANT.
return byref(VARIANT(arg))
from_param = classmethod(from_param)
def __setitem__(self, index, value):
# This is to support the same sematics as a pointer instance:
# variant[0] = value
self[index].value = value
################################################################
# interfaces, structures, ...
class IEnumVARIANT(IUnknown):
_iid_ = GUID('{00020404-0000-0000-C000-000000000046}')
_idlflags_ = ['hidden']
_dynamic = False
def __iter__(self):
return self
def __next__(self):
item, fetched = self.Next(1)
if fetched:
return item
raise StopIteration
def __getitem__(self, index):
self.Reset()
# Does not yet work.
## if isinstance(index, slice):
## self.Skip(index.start or 0)
## return self.Next(index.stop or sys.maxint)
self.Skip(index)
item, fetched = self.Next(1)
if fetched:
return item
raise IndexError
def Next(self, celt):
fetched = c_ulong()
if celt == 1:
v = VARIANT()
self.__com_Next(celt, v, fetched)
return v._get_value(dynamic=self._dynamic), fetched.value
array = (VARIANT * celt)()
self.__com_Next(celt, array, fetched)
result = [v._get_value(dynamic=self._dynamic) for v in array[:fetched.value]]
for v in array:
v.value = None
return result
IEnumVARIANT._methods_ = [
COMMETHOD([], HRESULT, 'Next',
( ['in'], c_ulong, 'celt' ),
( ['out'], POINTER(VARIANT), 'rgvar' ),
( ['out'], POINTER(c_ulong), 'pceltFetched' )),
COMMETHOD([], HRESULT, 'Skip',
( ['in'], c_ulong, 'celt' )),
COMMETHOD([], HRESULT, 'Reset'),
COMMETHOD([], HRESULT, 'Clone',
( ['out'], POINTER(POINTER(IEnumVARIANT)), 'ppenum' )),
]
##from _ctypes import VARIANT_set
##import new
##VARIANT.value = property(VARIANT._get_value, new.instancemethod(VARIANT_set, None, VARIANT))
class tagEXCEPINFO(Structure):
def __repr__(self):
return "<EXCEPINFO %s>" % \
((self.wCode, self.bstrSource, self.bstrDescription, self.bstrHelpFile, self.dwHelpContext,
self.pfnDeferredFillIn, self.scode),)
tagEXCEPINFO._fields_ = [
('wCode', WORD),
('wReserved', WORD),
('bstrSource', BSTR),
('bstrDescription', BSTR),
('bstrHelpFile', BSTR),
('dwHelpContext', DWORD),
('pvReserved', c_void_p),
## ('pfnDeferredFillIn', WINFUNCTYPE(HRESULT, POINTER(tagEXCEPINFO))),
('pfnDeferredFillIn', c_void_p),
('scode', SCODE),
]
EXCEPINFO = tagEXCEPINFO
class tagDISPPARAMS(Structure):
_fields_ = [
# C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 696
('rgvarg', POINTER(VARIANTARG)),
('rgdispidNamedArgs', POINTER(DISPID)),
('cArgs', UINT),
('cNamedArgs', UINT),
]
def __del__(self):
if self._b_needsfree_:
for i in range(self.cArgs):
self.rgvarg[i].value = None
DISPPARAMS = tagDISPPARAMS
DISPID_VALUE = 0
DISPID_UNKNOWN = -1
DISPID_PROPERTYPUT = -3
DISPID_NEWENUM = -4
DISPID_EVALUATE = -5
DISPID_CONSTRUCTOR = -6
DISPID_DESTRUCTOR = -7
DISPID_COLLECT = -8
class IDispatch(IUnknown):
_iid_ = GUID("{00020400-0000-0000-C000-000000000046}")
_methods_ = [
COMMETHOD([], HRESULT, 'GetTypeInfoCount',
(['out'], POINTER(UINT) ) ),
COMMETHOD([], HRESULT, 'GetTypeInfo',
(['in'], UINT, 'index'),
(['in'], LCID, 'lcid', 0),
## Normally, we would declare this parameter in this way:
## (['out'], POINTER(POINTER(ITypeInfo)) ) ),
## but we cannot import comtypes.typeinfo at the top level (recursive imports!).
(['out'], POINTER(POINTER(IUnknown)) ) ),
STDMETHOD(HRESULT, 'GetIDsOfNames', [POINTER(IID), POINTER(c_wchar_p),
UINT, LCID, POINTER(DISPID)]),
STDMETHOD(HRESULT, 'Invoke', [DISPID, POINTER(IID), LCID, WORD,
POINTER(DISPPARAMS), POINTER(VARIANT),
POINTER(EXCEPINFO), POINTER(UINT)]),
]
def GetTypeInfo(self, index, lcid=0):
"""Return type information. Index 0 specifies typeinfo for IDispatch"""
import comtypes.typeinfo
result = self._GetTypeInfo(index, lcid)
return result.QueryInterface(comtypes.typeinfo.ITypeInfo)
def GetIDsOfNames(self, *names, **kw):
"""Map string names to integer ids."""
lcid = kw.pop("lcid", 0)
assert not kw
arr = (c_wchar_p * len(names))(*names)
ids = (DISPID * len(names))()
self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)
return ids[:]
def _invoke(self, memid, invkind, lcid, *args):
var = VARIANT()
argerr = c_uint()
dp = DISPPARAMS()
if args:
array = (VARIANT * len(args))()
for i, a in enumerate(args[::-1]):
array[i].value = a
dp.cArgs = len(args)
if invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF):
dp.cNamedArgs = 1
dp.rgdispidNamedArgs = pointer(DISPID(DISPID_PROPERTYPUT))
dp.rgvarg = array
self.__com_Invoke(memid, riid_null, lcid, invkind,
dp, var, None, argerr)
return var._get_value(dynamic=True)
def Invoke(self, dispid, *args, **kw):
"""Invoke a method or property."""
# Memory management in Dispatch::Invoke calls:
# http://msdn.microsoft.com/library/en-us/automat/htm/chap5_4x2q.asp
# Quote:
# The *CALLING* code is responsible for releasing all strings and
# objects referred to by rgvarg[ ] or placed in *pVarResult.
#
# For comtypes this is handled in DISPPARAMS.__del__ and VARIANT.__del__.
_invkind = kw.pop("_invkind", 1) # DISPATCH_METHOD
_lcid = kw.pop("_lcid", 0)
if kw:
raise ValueError("named parameters not yet implemented")
result = VARIANT()
excepinfo = EXCEPINFO()
argerr = c_uint()
if _invkind in (DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF): # propput
array = (VARIANT * len(args))()
for i, a in enumerate(args[::-1]):
array[i].value = a
dp = DISPPARAMS()
dp.cArgs = len(args)
dp.cNamedArgs = 1
dp.rgvarg = array
dp.rgdispidNamedArgs = pointer(DISPID(DISPID_PROPERTYPUT))
else:
array = (VARIANT * len(args))()
for i, a in enumerate(args[::-1]):
array[i].value = a
dp = DISPPARAMS()
dp.cArgs = len(args)
dp.cNamedArgs = 0
dp.rgvarg = array
try:
self.__com_Invoke(dispid, riid_null, _lcid, _invkind, byref(dp),
byref(result), byref(excepinfo), byref(argerr))
except COMError as err:
(hresult, text, details) = err.args
if hresult == DISP_E_EXCEPTION:
details = (excepinfo.bstrDescription, excepinfo.bstrSource,
excepinfo.bstrHelpFile, excepinfo.dwHelpContext,
excepinfo.scode)
raise COMError(hresult, text, details)
elif hresult == DISP_E_PARAMNOTFOUND:
# MSDN says: You get the error DISP_E_PARAMNOTFOUND
# when you try to set a property and you have not
# initialized the cNamedArgs and rgdispidNamedArgs
# elements of your DISPPARAMS structure.
#
# So, this looks like a bug.
raise COMError(hresult, text, argerr.value)
elif hresult == DISP_E_TYPEMISMATCH:
# MSDN: One or more of the arguments could not be
# coerced.
#
# Hm, should we raise TypeError, or COMError?
raise COMError(hresult, text,
("TypeError: Parameter %s" % (argerr.value + 1),
args))
raise
return result._get_value(dynamic=True)
# XXX Would separate methods for _METHOD, _PROPERTYGET and _PROPERTYPUT be better?
################################################################
# safearrays
# XXX Only one-dimensional arrays are currently implemented
# map ctypes types to VARTYPE values
_arraycode_to_vartype = {
"d": VT_R8,
"f": VT_R4,
"l": VT_I4,
"i": VT_INT,
"h": VT_I2,
"b": VT_I1,
"I": VT_UINT,
"L": VT_UI4,
"H": VT_UI2,
"B": VT_UI1,
}
_ctype_to_vartype = {
c_byte: VT_I1,
c_ubyte: VT_UI1,
c_short: VT_I2,
c_ushort: VT_UI2,
c_long: VT_I4,
c_ulong: VT_UI4,
c_float: VT_R4,
c_double: VT_R8,
c_longlong: VT_I8,
c_ulonglong: VT_UI8,
VARIANT_BOOL: VT_BOOL,
BSTR: VT_BSTR,
VARIANT: VT_VARIANT,
# SAFEARRAY(VARIANT *)
#
# It is unlear to me if this is allowed or not. Apparently there
# are typelibs that define such an argument type, but it may be
# that these are buggy.
#
# Point is that SafeArrayCreateEx(VT_VARIANT|VT_BYREF, ..) fails.
# The MSDN docs for SafeArrayCreate() have a notice that neither
# VT_ARRAY not VT_BYREF may be set, this notice is missing however
# for SafeArrayCreateEx().
#
# We have this code here to make sure that comtypes can import
# such a typelib, although calling ths method will fail because
# such an array cannot be created.
POINTER(VARIANT): VT_BYREF|VT_VARIANT,
# This is needed to import Esri ArcObjects (esriSystem.olb).
POINTER(BSTR): VT_BYREF|VT_BSTR,
# These are not yet implemented:
## POINTER(IUnknown): VT_UNKNOWN,
## POINTER(IDispatch): VT_DISPATCH,
}
_vartype_to_ctype = {}
for c, v in _ctype_to_vartype.items():
_vartype_to_ctype[v] = c
_vartype_to_ctype[VT_INT] = _vartype_to_ctype[VT_I4]
_vartype_to_ctype[VT_UINT] = _vartype_to_ctype[VT_UI4]
_ctype_to_vartype[c_char] = VT_UI1
try:
from comtypes.safearray import _midlSAFEARRAY
except (ImportError, AttributeError):
pass