ctypes-commit Mailing List for ctypes (Page 42)
Brought to you by:
theller
You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(8) |
May
(90) |
Jun
(143) |
Jul
(106) |
Aug
(94) |
Sep
(84) |
Oct
(163) |
Nov
(60) |
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(128) |
Feb
(79) |
Mar
(227) |
Apr
(192) |
May
(179) |
Jun
(41) |
Jul
(53) |
Aug
(103) |
Sep
(28) |
Oct
(38) |
Nov
(81) |
Dec
(17) |
2006 |
Jan
(184) |
Feb
(111) |
Mar
(188) |
Apr
(67) |
May
(58) |
Jun
(123) |
Jul
(73) |
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
From: Thomas H. <th...@us...> - 2005-08-19 14:59:46
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12691 Modified Files: Tag: branch_1_0 _ctypes.c Log Message: Fix two problems that will show up on platforms where sizeof(int) != sizeof(void *). Get pointer values by PyLong_AsVoidPtr. Fix a bug when paramflags are specified as [], so the numerical flag value is 0. Index: _ctypes.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/_ctypes.c,v retrieving revision 1.226.2.19 retrieving revision 1.226.2.20 diff -C2 -d -r1.226.2.19 -r1.226.2.20 *** _ctypes.c 19 Aug 2005 07:06:38 -0000 1.226.2.19 --- _ctypes.c 19 Aug 2005 14:59:35 -0000 1.226.2.20 *************** *** 227,237 **** if (!obj) return NULL; ! if (!PyInt_Check(obj)) { ! /* XXX Error */ Py_DECREF(obj); return NULL; } ! handle = (void *)PyInt_AS_LONG(obj); Py_DECREF(obj); #ifdef MS_WIN32 --- 227,243 ---- if (!obj) return NULL; ! if (!PyInt_Check(obj) && !PyLong_Check(obj)) { ! PyErr_SetString(PyExc_TypeError, ! "the _handle attribute of the second argument must be an integer"); Py_DECREF(obj); return NULL; } ! handle = (void *)PyLong_AsVoidPtr(obj); Py_DECREF(obj); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "could not convert the _handle attribute to a pointer"); + return NULL; + } #ifdef MS_WIN32 *************** *** 601,605 **** } } ! return CDataType_from_param(type, value); } --- 607,611 ---- } } ! return CDataType_from_param(type, value); } *************** *** 2292,2296 **** if (!obj) return NULL; ! if (!PyInt_Check(obj)) { PyErr_SetString(PyExc_TypeError, "the _handle attribute of the second argument must be an integer"); --- 2298,2302 ---- if (!obj) return NULL; ! if (!PyInt_Check(obj) && !PyLong_Check(obj)) { PyErr_SetString(PyExc_TypeError, "the _handle attribute of the second argument must be an integer"); *************** *** 2298,2303 **** return NULL; } ! handle = (void *)PyInt_AS_LONG(obj); Py_DECREF(obj); #ifdef MS_WIN32 --- 2304,2314 ---- return NULL; } ! handle = (void *)PyLong_AsVoidPtr(obj); Py_DECREF(obj); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "could not convert the _handle attribute to a pointer"); + return NULL; + } #ifdef MS_WIN32 *************** *** 2610,2614 **** } switch (flag & (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)) { - case 0: case PARAMFLAG_FIN | PARAMFLAG_FLCID: /* ['in', 'lcid'] parameeter. Always taken from defval */ --- 2621,2624 ---- *************** *** 2616,2619 **** --- 2626,2630 ---- PyTuple_SET_ITEM(callargs, i, defval); break; + case 0: case PARAMFLAG_FIN: /* 'in' parameter. Copy it from inargs. */ |
From: Thomas H. <th...@us...> - 2005-08-19 07:07:56
|
Update of /cvsroot/ctypes/ctypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11504 Modified Files: Tag: branch_1_0 ChangeLog Log Message: Index: ChangeLog =================================================================== RCS file: /cvsroot/ctypes/ctypes/ChangeLog,v retrieving revision 1.86.2.9 retrieving revision 1.86.2.10 diff -C2 -d -r1.86.2.9 -r1.86.2.10 *** ChangeLog 18 Aug 2005 20:03:34 -0000 1.86.2.9 --- ChangeLog 19 Aug 2005 07:07:48 -0000 1.86.2.10 *************** *** 1,2 **** --- 1,7 ---- + 2005-08-19 Thomas Heller <th...@py...> + + * source\_ctypes.c: Add a CFuncPtr_repr which gives more useful + output when the instance is a COM method. + 2005-08-18 Thomas Heller <th...@py...> |
From: Thomas H. <th...@us...> - 2005-08-19 07:06:45
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11182 Modified Files: Tag: branch_1_0 _ctypes.c Log Message: Add CFuncPtr_repr, which gives more useful info when the instance is a COM method. Index: _ctypes.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/_ctypes.c,v retrieving revision 1.226.2.18 retrieving revision 1.226.2.19 diff -C2 -d -r1.226.2.18 -r1.226.2.19 *** _ctypes.c 17 Aug 2005 15:54:24 -0000 1.226.2.18 --- _ctypes.c 19 Aug 2005 07:06:38 -0000 1.226.2.19 *************** *** 2918,2921 **** --- 2918,2936 ---- } + static PyObject * + CFuncPtr_repr(CFuncPtrObject *self) + { + #ifdef MS_WIN32 + if (self->index) + return PyString_FromFormat("<COM method offset %d: %s at %p>", + self->index - 0x1000, + self->ob_type->tp_name, + self); + #endif + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, + self); + } + PyTypeObject CFuncPtr_Type = { PyObject_HEAD_INIT(NULL) *************** *** 2929,2933 **** 0, /* tp_setattr */ 0, /* tp_compare */ ! 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ --- 2944,2948 ---- 0, /* tp_setattr */ 0, /* tp_compare */ ! (reprfunc)CFuncPtr_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ |
From: Thomas H. <th...@us...> - 2005-08-18 20:04:25
|
Update of /cvsroot/ctypes/ctypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15145 Modified Files: Tag: branch_1_0 ChangeLog Log Message: Index: ChangeLog =================================================================== RCS file: /cvsroot/ctypes/ctypes/ChangeLog,v retrieving revision 1.86.2.8 retrieving revision 1.86.2.9 diff -C2 -d -r1.86.2.8 -r1.86.2.9 *** ChangeLog 20 May 2005 20:14:36 -0000 1.86.2.8 --- ChangeLog 18 Aug 2005 20:03:34 -0000 1.86.2.9 *************** *** 1,2 **** --- 1,26 ---- + 2005-08-18 Thomas Heller <th...@py...> + + * Finally committed a patch from Mike Fletcher which allows to use + the RTLD_GLOBAL flag to load libraries. + + 2005-08-17 Thomas Heller <th...@py...> + + * source\*.[ch]: Implement rich error reporting for COM method + calls (on Windows). + + CFuncPtrObject gets a new 'iid' slot which stores a pointer to the + guid of the interface this method belongs to. When iid is != + NULL, use IErrorInfo to get rich error information from the com + object. + + Add a COMError class, and implement custom __init__ and __str__ + methods. + + 2005-08-12 Thomas Heller <th...@py...> + + * source\callbacks.c: A buffer allocated for callbacks was too + small. This could lead to crashed when callbacks were garbage + collected. Problem reported by Mike Fletcher. + 2005-05-20 Thomas Heller <th...@py...> |
From: Thomas H. <th...@us...> - 2005-08-18 19:46:20
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11287 Modified Files: Tag: branch_1_0 test_posix.py Log Message: Add at least one test for the 'mode' flag. Index: test_posix.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/unittests/test_posix.py,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -C2 -d -r1.2 -r1.2.2.1 *** test_posix.py 18 Mar 2005 17:41:27 -0000 1.2 --- test_posix.py 18 Aug 2005 19:45:50 -0000 1.2.2.1 *************** *** 2,5 **** --- 2,15 ---- from ctypes import * + if os.name == "posix" and sys.platform == "linux2": + # I don't really know on which platforms this works, + # later it should use the find_library stuff to avoid + # hardcoding the names. + + class TestRTLD_GLOBAL(unittest.TestCase): + def test_GL(self): + CDLL('libGL.so', mode=RTLD_GLOBAL) + CDLL('libGLU.so') + ##if os.name == "posix" and sys.platform != "darwin": |
From: Thomas H. <th...@us...> - 2005-08-18 19:07:02
|
Update of /cvsroot/ctypes/ctypes/ctypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30965 Modified Files: Tag: branch_1_0 __init__.py Log Message: Finally commit the patch from Mike Fletcher. Index: __init__.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/ctypes/__init__.py,v retrieving revision 1.61.2.8 retrieving revision 1.61.2.9 diff -C2 -d -r1.61.2.8 -r1.61.2.9 *** __init__.py 28 Jul 2005 08:51:58 -0000 1.61.2.8 --- __init__.py 18 Aug 2005 19:06:32 -0000 1.61.2.9 *************** *** 15,18 **** --- 15,22 ---- from _ctypes import CFuncPtr as _CFuncPtr from _ctypes import __version__ as _ctypes_version + try: + from _ctypes import RTLD_LOCAL, RTLD_GLOBAL + except (ImportError, AttributeError): + RTLD_GLOBAL = RTLD_LOCAL = None from _ctypes import ArgumentError *************** *** 319,326 **** _handle = 0 ! def __init__(self, name, handle=None): self._name = name if handle is None: ! self._handle = _LoadLibrary(self._name) else: self._handle = handle --- 323,330 ---- _handle = 0 ! def __init__(self, name, handle=None, mode=RTLD_LOCAL): self._name = name if handle is None: ! self._handle = _LoadLibrary(self._name, mode) else: self._handle = handle |
From: Thomas H. <th...@us...> - 2005-08-18 18:00:07
|
Update of /cvsroot/ctypes/ctypes/comtypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv566 Modified Files: Tag: branch_1_0 typeinfo.py safearray.py connectionpoints.py automation.py __init__.py Log Message: Sync with upstream version. Fix several bugs. New functions and more functionality in comtypes and comtypes.client. Index: typeinfo.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/typeinfo.py,v retrieving revision 1.3.2.7 retrieving revision 1.3.2.8 diff -C2 -d -r1.3.2.7 -r1.3.2.8 *** typeinfo.py 10 Aug 2005 13:14:04 -0000 1.3.2.7 --- typeinfo.py 18 Aug 2005 14:42:04 -0000 1.3.2.8 *************** *** 1,2 **** --- 1,4 ---- + # XXX Should convert from STDMETHOD to COMMETHOD. + # generated by 'xml2py' # flags '..\tools\windows.xml -m comtypes -m comtypes.automation -w -r .*TypeLibEx -r .*TypeLib -o typeinfo.py' Index: connectionpoints.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/Attic/connectionpoints.py,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** connectionpoints.py 10 Aug 2005 13:17:53 -0000 1.1.2.1 --- connectionpoints.py 18 Aug 2005 14:42:04 -0000 1.1.2.2 *************** *** 24,31 **** --- 24,49 ---- _idlflags_ = [] + def __iter__(self): + return self + + def next(self): + cp, fetched = self.Next(1) + if fetched == 0: + raise StopIteration + return cp + class IEnumConnectionPoints(IUnknown): _iid_ = GUID('{B196B285-BAB4-101A-B69C-00AA00341D07}') _idlflags_ = [] + def __iter__(self): + return self + + def next(self): + cp, fetched = self.Next(1) + if fetched == 0: + raise StopIteration + return cp + ################################################################ Index: automation.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/automation.py,v retrieving revision 1.12.2.13 retrieving revision 1.12.2.14 diff -C2 -d -r1.12.2.13 -r1.12.2.14 *** automation.py 17 Aug 2005 16:29:37 -0000 1.12.2.13 --- automation.py 18 Aug 2005 14:42:04 -0000 1.12.2.14 *************** *** 319,322 **** --- 319,325 ---- value = property(_get_value, _set_value) + def __ctypes_from_outparam__(self): + return self.value + VARIANT = tagVARIANT VARIANTARG = VARIANT *************** *** 446,451 **** _iid_ = GUID("{00020400-0000-0000-C000-000000000046}") _methods_ = [ ! STDMETHOD(HRESULT, 'GetTypeInfoCount', [POINTER(UINT)]), ! STDMETHOD(HRESULT, 'GetTypeInfo', [UINT, LCID, POINTER(c_void_p)]), STDMETHOD(HRESULT, 'GetIDsOfNames', [POINTER(IID), POINTER(c_wchar_p), UINT, LCID, POINTER(DISPID)]), --- 449,461 ---- _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)]), *************** *** 455,471 **** ] ! def GetTypeInfoCount(self): ! """Return the number of type informations for this interface.""" ! r = c_uint() ! self.__com_GetTypeInfoCount(byref(r)) ! return r.value ! ! def GetTypeInfo(self, index=0, lcid=0): ! "Return type information for this interface" ! # index=0 specifies typeinfo for IDispatch ! from typeinfo import ITypeInfo ! p = POINTER(ITypeInfo)() ! self.__com_GetTypeInfo(index, lcid, byref(p)) ! return p def GetIDsOfNames(self, *names, **kw): --- 465,474 ---- ] ! def GetTypeInfo(self, index, lcid=0): ! """Return type information. Index 0 specifies typeinfo for IDispatch""" ! import comtypes.typeinfo ! # we could also use cast instead of QueryInterface. Does it matter? ! result = self._GetTypeInfo(index, lcid) ! return result.QueryInterface(comtypes.typeinfo.ITypeInfo) def GetIDsOfNames(self, *names, **kw): *************** *** 487,490 **** --- 490,494 ---- # 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) Index: __init__.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/__init__.py,v retrieving revision 1.25.2.25 retrieving revision 1.25.2.26 diff -C2 -d -r1.25.2.25 -r1.25.2.26 *** __init__.py 17 Aug 2005 16:29:37 -0000 1.25.2.25 --- __init__.py 18 Aug 2005 14:42:04 -0000 1.25.2.26 *************** *** 193,196 **** --- 193,197 ---- setattr(self, name, named_property(*methods)) else: + assert len(methods) <= 2 setattr(self, name, property(*methods)) *************** *** 223,226 **** --- 224,228 ---- def _disp_property(self, memid, idlflags): + # XXX doc string missing in property def get(obj): return obj.Invoke(memid, _invkind=2) # DISPATCH_PROPERTYGET *************** *** 331,335 **** for (name, doc, nargs), methods in properties.items(): if nargs == 0: ! prop = property(*methods + [doc]) else: # Hm, must be a descriptor where the __get__ method --- 333,337 ---- for (name, doc, nargs), methods in properties.items(): if nargs == 0: ! prop = property(*methods + [None, doc]) else: # Hm, must be a descriptor where the __get__ method *************** *** 444,451 **** # IDL stuff ! class helpstring(object): "Specifies the helpstring for a COM method or property." - def __init__(self, text): - self.text = text class defaultvalue(object): --- 446,451 ---- # IDL stuff ! class helpstring(unicode): "Specifies the helpstring for a COM method or property." class defaultvalue(object): *************** *** 456,460 **** class dispid(int): "Specifies the DISPID of a method or property." ! pass def STDMETHOD(restype, name, argtypes=()): --- 456,462 ---- class dispid(int): "Specifies the DISPID of a method or property." ! ! # XXX STDMETHOD, COMMETHOD, DISPMETHOD, and DISPPROPERTY should return ! # instances with methods, or at least accessors instead of tuple. def STDMETHOD(restype, name, argtypes=()): *************** *** 523,531 **** # collect all helpstring instances # We should suppress docstrings when Python is started with -OO ! helptext = [t.text for t in idlflags if isinstance(t, helpstring)] # join them together(does this make sense?) and replace by None if empty. helptext = "".join(helptext) or None ! VARIANT = _VARIANT_type_hack # more pretty name for our hack for item in argspec: --- 525,533 ---- # collect all helpstring instances # We should suppress docstrings when Python is started with -OO ! helptext = [t for t in idlflags if isinstance(t, helpstring)] # join them together(does this make sense?) and replace by None if empty. helptext = "".join(helptext) or None ! VARIANT = _VARIANT_type_hack # more pretty local name for our hack for item in argspec: *************** *** 665,670 **** ################################################################ ! def CoCreateInstance(clsid, interface=IUnknown, clsctx=None, punkouter=None): """The basic windows api to create a COM class object and return a pointer to an interface. --- 667,684 ---- ################################################################ + def CoGetObject(displayname, interface): + """Convert a displayname to a moniker, then bind and return the object + identified by the moniker.""" + if interface is None: + interface = IUnknown + punk = POINTER(interface)() + # Do we need a way to specify the BIND_OPTS parameter? + _ole32.CoGetObject(unicode(displayname), + None, + byref(interface._iid_), + byref(punk)) + return punk ! def CoCreateInstance(clsid, interface=None, clsctx=None, punkouter=None): """The basic windows api to create a COM class object and return a pointer to an interface. *************** *** 672,675 **** --- 686,691 ---- if clsctx is None: clsctx = CLSCTX_SERVER + if interface is None: + interface = IUnknown p = POINTER(interface)() iid = interface._iid_ *************** *** 677,680 **** --- 693,704 ---- return p + def GetActiveObject(clsid, interface=None): + """Retrieves a pointer to a running object""" + p = POINTER(IUnknown)() + oledll.oleaut32.GetActiveObject(byref(clsid), None, byref(p)) + if interface is not None: + p = p.QueryInterface(interface) + return p + class MULTI_QI(Structure): _fields_ = [("pIID", POINTER(GUID)), *************** *** 688,692 **** ("dwReserved2", c_ulong)] ! def CoCreateInstanceEx(clsid, interface=IUnknown, clsctx=None, machine=None): --- 712,716 ---- ("dwReserved2", c_ulong)] ! def CoCreateInstanceEx(clsid, interface=None, clsctx=None, machine=None): *************** *** 702,705 **** --- 726,731 ---- else: psi = None + if interface is None: + interface = IUnknown multiqi = MULTI_QI() multiqi.pIID = pointer(interface._iid_) *************** *** 743,746 **** --- 769,773 ---- # virtual function table, and leave out the 'object' base class. for interface in itf.__mro__[-2::-1]: + iids.append(interface._iid_.hashcode()) for m in interface._methods_: restype, mthname, argtypes, paramflags, idlflags, helptext = m *************** *** 755,759 **** ## print "# Method %s.%s not implemented" % (interface.__name__, mthname) methods.append(proto(mth)) - iids.append(interface._iid_.hashcode()) class Vtbl(Structure): _fields_ = fields --- 782,785 ---- *************** *** 806,811 **** def IUnknown_QueryInterface(self, this, riid, ppvObj): ptr = self._com_pointers_.get(riid[0].hashcode(), None) ! ## print "QI(%s) -> %s" % (riid[0], bool(ptr)) ! if ptr: # CopyComPointer(src, dst) calls AddRef! return CopyComPointer(ptr, ppvObj) --- 832,838 ---- def IUnknown_QueryInterface(self, this, riid, ppvObj): ptr = self._com_pointers_.get(riid[0].hashcode(), None) ! ## print "QI(%s) -> %s" % (riid[0], ptr) ! # XXX Can we switch to QueryInterface(self)? ! if ptr is not None: # CopyComPointer(src, dst) calls AddRef! return CopyComPointer(ptr, ppvObj) *************** *** 821,825 **** ################################################################ ! if __name__ == "__main__": # a helper function. Not sure if it is needed, except for testing. --- 848,852 ---- ################################################################ ! if 0 and __name__ == "__main__": # a helper function. Not sure if it is needed, except for testing. Index: safearray.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/Attic/safearray.py,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -C2 -d -r1.1.2.3 -r1.1.2.4 *** safearray.py 17 Aug 2005 16:29:37 -0000 1.1.2.3 --- safearray.py 18 Aug 2005 14:42:04 -0000 1.1.2.4 *************** *** 45,48 **** --- 45,51 ---- def SafeArray_FromSequence(seq): + """Create a one dimensional safearray of type VT_VARIANT from a + sequence of Python objects + """ psa = oledll.oleaut32.SafeArrayCreateVectorEx(VT_VARIANT, 0, len(seq), None) for index, elem in enumerate(seq): *************** *** 51,54 **** --- 54,59 ---- def SafeArray_FromArray(arr): + """Create a one dimensional safearray of a numeric type from an + array instance""" TYPECODE = { "d": VT_R8, *************** *** 122,126 **** def UnpackSafeArray(psa): ! """Unpack a SAFEARRAY into a Python list.""" dim = oledll.oleaut32.SafeArrayGetDim(psa) indexes = [_get_lbound(psa, d) for d in range(dim)] --- 127,131 ---- def UnpackSafeArray(psa): ! """Unpack a SAFEARRAY into a Python tuple.""" dim = oledll.oleaut32.SafeArrayGetDim(psa) indexes = [_get_lbound(psa, d) for d in range(dim)] *************** *** 129,175 **** return _get_row(_get_datatype(psa)(), psa, 0, indexes, upperbounds) if __name__ == "__main__": ! dim = 3 ! if dim == 2: ! rgsa = (SAFEARRAYBOUND * 2)() ! rgsa[0].lLbound = 3 ! rgsa[0].cElements = 9 ! rgsa[1].lLbound = 7 ! rgsa[1].cElements = 6 ! elif dim == 1: ! rgsa = (SAFEARRAYBOUND * 1)() ! rgsa[0].lLbound = 3 ! rgsa[0].cElements = 9 ! elif dim == 3: ! ! rgsa = (SAFEARRAYBOUND * 3)() ! rgsa[0].lLbound = 1 ! rgsa[0].cElements = 6 ! rgsa[1].lLbound = 2 ! rgsa[1].cElements = 5 ! rgsa[2].lLbound = 3 ! rgsa[2].cElements = 4 ! else: ! raise ValueError("dim %d not supported" % dim) ! windll.oleaut32.SafeArrayCreate.restype = POINTER(SAFEARRAY) ! psa = windll.oleaut32.SafeArrayCreate(VT_I4, len(rgsa), rgsa) ! n = 1 ! for b in rgsa: ! n *= b.cElements ! print "%d total elements" % n ! ptr = POINTER(c_int)() ! oledll.oleaut32.SafeArrayAccessData(psa, byref(ptr)) ! array = (c_int * n)(*range(n)) ! memmove(ptr, array, sizeof(array)) ! oledll.oleaut32.SafeArrayUnaccessData(psa) ! import pprint ! pprint.pprint(UnpackSafeArray(psa)) ## v = VARIANT() --- 134,182 ---- return _get_row(_get_datatype(psa)(), psa, 0, indexes, upperbounds) + ################################################################ + if __name__ == "__main__": ! for dim in range(1, 4): ! if dim == 2: ! rgsa = (SAFEARRAYBOUND * 2)() ! rgsa[0].lLbound = 3 ! rgsa[0].cElements = 9 ! rgsa[1].lLbound = 7 ! rgsa[1].cElements = 6 ! elif dim == 1: ! rgsa = (SAFEARRAYBOUND * 1)() ! rgsa[0].lLbound = 3 ! rgsa[0].cElements = 9 ! elif dim == 3: ! rgsa = (SAFEARRAYBOUND * 3)() ! rgsa[0].lLbound = 1 ! rgsa[0].cElements = 6 ! rgsa[1].lLbound = 2 ! rgsa[1].cElements = 5 ! rgsa[2].lLbound = 3 ! rgsa[2].cElements = 4 ! else: ! raise ValueError("dim %d not supported" % dim) ! windll.oleaut32.SafeArrayCreate.restype = POINTER(SAFEARRAY) ! psa = windll.oleaut32.SafeArrayCreate(VT_I4, len(rgsa), rgsa) ! n = 1 ! for b in rgsa: ! n *= b.cElements ! print "%d total elements" % n ! ptr = POINTER(c_int)() ! oledll.oleaut32.SafeArrayAccessData(psa, byref(ptr)) ! array = (c_int * n)(*range(n)) ! memmove(ptr, array, sizeof(array)) ! oledll.oleaut32.SafeArrayUnaccessData(psa) ! ! import pprint ! pprint.pprint(UnpackSafeArray(psa)) ## v = VARIANT() |
From: Thomas H. <th...@us...> - 2005-08-17 16:59:16
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2045 Modified Files: Tag: branch_1_0 callproc.c Log Message: Fix compilation on linux. Index: callproc.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/callproc.c,v retrieving revision 1.127.2.7 retrieving revision 1.127.2.8 diff -C2 -d -r1.127.2.7 -r1.127.2.8 *** callproc.c 17 Aug 2005 15:54:24 -0000 1.127.2.7 --- callproc.c 17 Aug 2005 16:59:08 -0000 1.127.2.8 *************** *** 923,940 **** n = argcount = PyTuple_GET_SIZE(argtuple); /* an optional COM object this pointer */ if (pIunk) ++argcount; args = (struct argument *)alloca(sizeof(struct argument) * argcount); memset(args, 0, sizeof(struct argument) * argcount); argtype_count = argtypes ? PyTuple_GET_SIZE(argtypes) : 0; if (pIunk) { args[0].ffi_type = &ffi_type_pointer; args[0].value.p = pIunk; pa = &args[1]; ! } else { pa = &args[0]; - } /* Convert the arguments */ --- 923,943 ---- n = argcount = PyTuple_GET_SIZE(argtuple); + #ifdef MS_WIN32 /* an optional COM object this pointer */ if (pIunk) ++argcount; + #endif args = (struct argument *)alloca(sizeof(struct argument) * argcount); memset(args, 0, sizeof(struct argument) * argcount); argtype_count = argtypes ? PyTuple_GET_SIZE(argtypes) : 0; + #ifdef MS_WIN32 if (pIunk) { args[0].ffi_type = &ffi_type_pointer; args[0].value.p = pIunk; pa = &args[1]; ! } else ! #endif pa = &args[0]; /* Convert the arguments */ |
From: Thomas H. <th...@us...> - 2005-08-17 16:32:17
|
Update of /cvsroot/ctypes/ctypes/comtypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28257 Modified Files: Tag: branch_1_0 test_typeinfo.py test_safearray.py test_excel.py test_client.py test_basic.py test_GUID.py test_DISPPARAMS.py runtests.py Added Files: Tag: branch_1_0 ut.py test_ie.py Log Message: Update tests. Add the comtypes.unittests.ut hack. --- NEW FILE: test_ie.py --- import ut from comtypes.client import CreateObject, GetEvents, ReleaseEvents class EventSink: def __init__(self): self._events = [] # some DWebBrowserEvents def OnVisible(self, this, *args): ## print "OnVisible", args self._events.append("OnVisible") def BeforeNavigate(self, this, *args): ## print "BeforeNavigate", args self._events.append("BeforeNavigate") def NavigateComplete(self, this, *args): ## print "NavigateComplete", args self._events.append("NavigateComplete") # some DWebBrowserEvents2 def BeforeNavigate2(self, this, *args): ## print "BeforeNavigate2", args self._events.append("BeforeNavigate2") def NavigateComplete2(self, this, *args): ## print "NavigateComplete2", args self._events.append("NavigateComplete2") def DocumentComplete(self, this, *args): ## print "DocumentComplete", args self._events.append("DocumentComplete") class Test(ut.TestCase): def tearDown(self): import gc gc.collect() import time time.sleep(2) def test_default_eventinterface(self): sink = EventSink() ie = CreateObject("InternetExplorer.Application", wrapper="shdocvw_tlb", sink=sink) ie.Visible = True ie.Navigate("http://www.python.org/") import pythoncom import time for i in range(30): pythoncom.PumpWaitingMessages() time.sleep(0.1) ie.Visible = False ie.Quit() self.failUnlessEqual(sink._events, ['OnVisible', 'BeforeNavigate2', 'NavigateComplete2', 'DocumentComplete', 'OnVisible']) del ie import comtypes.client self.failUnlessEqual(comtypes.client._active_events, {}) def test_nondefault_eventinterface(self): sink = EventSink() ie = CreateObject("InternetExplorer.Application", wrapper="shdocvw_tlb") import comtypes.gen.shdocvw_tlb as mod GetEvents(ie, sink, interface=mod.DWebBrowserEvents) ie.Visible = True ie.Navigate("http://www.python.org/") import pythoncom import time for i in range(30): pythoncom.PumpWaitingMessages() time.sleep(0.1) ie.Visible = False ie.Quit() self.failUnlessEqual(sink._events, ['BeforeNavigate', 'NavigateComplete']) del ie import comtypes.client self.failUnlessEqual(comtypes.client._active_events, {}) if __name__ == "__main__": ut.main() --- NEW FILE: ut.py --- import unittest def main(): import sys if "-F" in sys.argv: sys.argv.remove("-F") return unittest.main() class TextTestRunner(unittest.TextTestRunner): def run(self, *args): result = super(TextTestRunner, self).run(*args) global failures_ignored if failures_ignored: self.stream.writeln("(%d marked failures ignored)" % failures_ignored) return result unittest.TextTestRunner = TextTestRunner class TestCase(unittest.TestCase): pass ################################################################ # monkeypatching unittest ;-) # The idea is to mark failing tests by prepending a 'FAIL_' to the # method. Example: self.failUnless(..) -> self.FAIL_failUnless(..) # # Depending on how the test is run (where to configure it?), the # meaning of the test methods is then reversed ;-). # these method names are pairs containing positive and negative tests NAMES = """ failIf failUnless failUnlessEqual failIfEqual failUnlessAlmostEqual failIfAlmostEqual """.split() # names which are aliased to the last name in each line. not yet # patched, so the FAIL_ magic will not work with them. ALIASES = """ assertEqual = assertEquals = failUnlessEqual assertNotEqual = assertNotEquals = failIfEqual assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual assert_ = failUnless """.strip().splitlines() # these require special treatment ##failUnlessRaises ##assertRaises = failUnlessRaises ################################################################ failures_ignored = 0 def count(func): # return a function which counts reversed tests in a global. def doit(*args, **kw): global failures_ignored failures_ignored += 1 return func(*args, **kw) return doit import sys if "-F" in sys.argv: sys.argv.remove("-F") for i in range(len(NAMES)/2): pos, neg = NAMES[2*i], NAMES[2*i+1] func = getattr(TestCase, neg) setattr(TestCase, "FAIL_%s" % pos, count(func)) func = getattr(TestCase, pos) setattr(TestCase, "FAIL_%s" % neg, count(func)) else: for name in NAMES: setattr(TestCase, "FAIL_%s" % name, getattr(TestCase, name)) ##print NAMES ##print ALIASES Index: test_basic.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/test_basic.py,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -C2 -d -r1.5 -r1.5.2.1 *** test_basic.py 11 Mar 2005 19:23:34 -0000 1.5 --- test_basic.py 17 Aug 2005 16:32:07 -0000 1.5.2.1 *************** *** 1,3 **** ! import unittest from ctypes import windll, POINTER, byref, HRESULT from comtypes import IUnknown, STDMETHOD, GUID --- 1,3 ---- ! import ut from ctypes import windll, POINTER, byref, HRESULT from comtypes import IUnknown, STDMETHOD, GUID *************** *** 7,11 **** for base in interface.__mro__]) ! class BasicTest(unittest.TestCase): def test_IUnknown(self): from comtypes import IUnknown --- 7,11 ---- for base in interface.__mro__]) ! class BasicTest(ut.TestCase): def test_IUnknown(self): from comtypes import IUnknown *************** *** 93,98 **** IDerived._methods_ = [] ! ## def test_identity(self): if __name__ == "__main__": ! unittest.main() --- 93,127 ---- IDerived._methods_ = [] ! def test_identity(self): ! # COM indentity rules ! ! # these should be identical ! a = POINTER(IUnknown)() ! b = POINTER(IUnknown)() ! self.failUnlessEqual(a, b) ! self.failUnlessEqual(hash(a), hash(b)) ! ! from comtypes.typeinfo import CreateTypeLib ! ! # we do not save the lib, so no file will be created. ! # these should NOT be identical ! a = CreateTypeLib(u"blahblah") ! b = CreateTypeLib(u"spam") ! ! self.failIfEqual(a, b) ! self.failIfEqual(hash(a), hash(b)) ! ! a = a.QueryInterface(IUnknown) ! b = b.QueryInterface(IUnknown) ! ! self.failIfEqual(a, b) ! self.failIfEqual(hash(a), hash(b)) ! ! # These must be identical ! c = a.QueryInterface(IUnknown) ! self.failUnlessEqual(a, c) ! self.failUnlessEqual(hash(a), hash(c)) ! if __name__ == "__main__": ! ut.main() Index: test_GUID.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/test_GUID.py,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -C2 -d -r1.2 -r1.2.2.1 *** test_GUID.py 24 Feb 2005 16:49:54 -0000 1.2 --- test_GUID.py 17 Aug 2005 16:32:07 -0000 1.2.2.1 *************** *** 1,6 **** ! import unittest from comtypes import GUID ! class Test(unittest.TestCase): def test(self): self.failUnlessEqual(GUID(), GUID()) --- 1,6 ---- ! import ut from comtypes import GUID ! class Test(ut.TestCase): def test(self): self.failUnlessEqual(GUID(), GUID()) *************** *** 27,29 **** if __name__ == "__main__": ! unittest.main() --- 27,29 ---- if __name__ == "__main__": ! ut.main() Index: runtests.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/runtests.py,v retrieving revision 1.1 retrieving revision 1.1.2.1 diff -C2 -d -r1.1 -r1.1.2.1 *** runtests.py 12 Jan 2005 20:54:05 -0000 1.1 --- runtests.py 17 Aug 2005 16:32:07 -0000 1.1.2.1 *************** *** 8,11 **** --- 8,12 ---- """ import glob, os, sys, unittest, getopt + import ut def get_suite(mask): Index: test_DISPPARAMS.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/Attic/test_DISPPARAMS.py,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -C2 -d -r1.1.2.3 -r1.1.2.4 *** test_DISPPARAMS.py 10 Aug 2005 13:14:16 -0000 1.1.2.3 --- test_DISPPARAMS.py 17 Aug 2005 16:32:07 -0000 1.1.2.4 *************** *** 1,5 **** ! import unittest ! class TestCase(unittest.TestCase): def test(self): from comtypes.automation import DISPPARAMS, VARIANT --- 1,5 ---- ! import ut ! class TestCase(ut.TestCase): def test(self): from comtypes.automation import DISPPARAMS, VARIANT *************** *** 18,23 **** self.failUnlessEqual(dp.rgvarg[0].value, 42) ! self.failUnlessEqual(dp.rgvarg[1].value, "spam") ! self.failUnlessEqual(dp.rgvarg[2].value, "foo") def X_test_2(self): --- 18,23 ---- self.failUnlessEqual(dp.rgvarg[0].value, 42) ! self.FAIL_failUnlessEqual(dp.rgvarg[1].value, "spam") ! self.FAIL_failUnlessEqual(dp.rgvarg[2].value, "foo") def X_test_2(self): *************** *** 38,40 **** if __name__ == "__main__": ! unittest.main() --- 38,40 ---- if __name__ == "__main__": ! ut.main() Index: test_client.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/Attic/test_client.py,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** test_client.py 3 Aug 2005 10:05:55 -0000 1.1.2.1 --- test_client.py 17 Aug 2005 16:32:07 -0000 1.1.2.2 *************** *** 1,11 **** ! import unittest import comtypes.client from ctypes import POINTER # create the typelib wrapper and import it ! comtypes.client.make_module("msscript.ocx", friendly_name="msscript") from comtypes.gen import msscript ! class Test(unittest.TestCase): def test_progid(self): # create from ProgID --- 1,11 ---- ! import ut import comtypes.client from ctypes import POINTER # create the typelib wrapper and import it ! comtypes.client.make_module("msscript.ocx", wrapper="msscript") from comtypes.gen import msscript ! class Test(ut.TestCase): def test_progid(self): # create from ProgID *************** *** 34,36 **** if __name__ == "__main__": ! unittest.main() --- 34,36 ---- if __name__ == "__main__": ! ut.main() Index: test_excel.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/Attic/test_excel.py,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** test_excel.py 10 Aug 2005 13:18:09 -0000 1.1.2.1 --- test_excel.py 17 Aug 2005 16:32:07 -0000 1.1.2.2 *************** *** 1,9 **** # -*- coding: latin-1 -*- ! import unittest import datetime from comtypes.client import CreateObject ! class Test(unittest.TestCase): def setUp(self): self.xl = CreateObject("Excel.Application") --- 1,16 ---- # -*- coding: latin-1 -*- ! import ut import datetime from comtypes.client import CreateObject ! class Test(ut.TestCase): ! first_time = True def setUp(self): + if self.first_time: + try: + import comtypes.gen._00020813_0000_0000_C000_000000000046_0_1_2 + except ImportError: + print "\n(Generating the EXCEL typelib wrapper may require some time, please be patient)" + self.first_time = False self.xl = CreateObject("Excel.Application") *************** *** 17,33 **** wb = xl.Workbooks.Add() ! xl.Range("A1", "C1").Value = [1,"2",3.14] xl.Range("A2:C2").Value = ('x','y','z') xl.Range("A3:C3").Value = ('3','2','1') self.failUnlessEqual(xl.Range("A1:C3").Value, ! [[1.0, 2.0, 3.14], ! ["x", "y", "z"], ! [3.0, 2.0, 1.0]]) self.failUnlessEqual(xl.Range("A1", "C3").Value, ! [[1.0, 2.0, 3.14], ! ["x", "y", "z"], ! [3.0, 2.0, 1.0]]) for i in xrange(20): --- 24,40 ---- wb = xl.Workbooks.Add() ! xl.Range("A1", "C1").Value = (1,"2",3.14) xl.Range("A2:C2").Value = ('x','y','z') xl.Range("A3:C3").Value = ('3','2','1') self.failUnlessEqual(xl.Range("A1:C3").Value, ! ((1.0, 2.0, 3.14), ! ("x", "y", "z"), ! (3.0, 2.0, 1.0))) self.failUnlessEqual(xl.Range("A1", "C3").Value, ! ((1.0, 2.0, 3.14), ! ("x", "y", "z"), ! (3.0, 2.0, 1.0))) for i in xrange(20): *************** *** 71,73 **** if __name__ == "__main__": ! unittest.main() --- 78,80 ---- if __name__ == "__main__": ! ut.main() Index: test_safearray.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/Attic/test_safearray.py,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** test_safearray.py 10 Aug 2005 13:18:09 -0000 1.1.2.1 --- test_safearray.py 17 Aug 2005 16:32:07 -0000 1.1.2.2 *************** *** 1,11 **** ! import unittest from comtypes.automation import VARIANT, VT_ARRAY, VT_VARIANT, VT_I4, VT_R4, VT_R8 ! class TestCase(unittest.TestCase): def test_1(self): v = VARIANT() v.value = ((1, 2, 3), ("foo", "bar", None)) self.failUnlessEqual(v.vt, VT_ARRAY | VT_VARIANT) ! self.failUnlessEqual(v.value, [[1, 2, 3], ["foo", "bar", None]]) def test_double_array(self): --- 1,11 ---- ! import ut from comtypes.automation import VARIANT, VT_ARRAY, VT_VARIANT, VT_I4, VT_R4, VT_R8 ! class TestCase(ut.TestCase): def test_1(self): v = VARIANT() v.value = ((1, 2, 3), ("foo", "bar", None)) self.failUnlessEqual(v.vt, VT_ARRAY | VT_VARIANT) ! self.failUnlessEqual(v.value, ((1, 2, 3), ("foo", "bar", None))) def test_double_array(self): *************** *** 14,18 **** v = VARIANT(a) self.failUnlessEqual(v.vt, VT_ARRAY | VT_R8) ! self.failUnlessEqual(a.tolist(), v.value) def test_float_array(self): --- 14,18 ---- v = VARIANT(a) self.failUnlessEqual(v.vt, VT_ARRAY | VT_R8) ! self.failUnlessEqual(tuple(a.tolist()), v.value) def test_float_array(self): *************** *** 21,26 **** v = VARIANT(a) self.failUnlessEqual(v.vt, VT_ARRAY | VT_R4) ! self.failUnlessEqual(a.tolist(), v.value) if __name__ == "__main__": ! unittest.main() --- 21,26 ---- v = VARIANT(a) self.failUnlessEqual(v.vt, VT_ARRAY | VT_R4) ! self.failUnlessEqual(tuple(a.tolist()), v.value) if __name__ == "__main__": ! ut.main() Index: test_typeinfo.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/unittests/test_typeinfo.py,v retrieving revision 1.3.2.2 retrieving revision 1.3.2.3 diff -C2 -d -r1.3.2.2 -r1.3.2.3 *** test_typeinfo.py 3 Aug 2005 10:05:09 -0000 1.3.2.2 --- test_typeinfo.py 17 Aug 2005 16:32:07 -0000 1.3.2.3 *************** *** 1,10 **** ! import unittest from ctypes import POINTER, byref ! from comtypes import GUID from comtypes.automation import DISPATCH_METHOD from comtypes.typeinfo import LoadTypeLibEx, LoadRegTypeLib, \ QueryPathOfRegTypeLib, TKIND_INTERFACE, TKIND_DISPATCH, TKIND_ENUM ! class Test(unittest.TestCase): def test_LoadTypeLibEx(self): self.assertRaises(WindowsError, lambda: LoadTypeLibEx("<xxx.xx>")) --- 1,10 ---- ! import ut from ctypes import POINTER, byref ! from comtypes import GUID, COMError from comtypes.automation import DISPATCH_METHOD from comtypes.typeinfo import LoadTypeLibEx, LoadRegTypeLib, \ QueryPathOfRegTypeLib, TKIND_INTERFACE, TKIND_DISPATCH, TKIND_ENUM ! class Test(ut.TestCase): def test_LoadTypeLibEx(self): self.assertRaises(WindowsError, lambda: LoadTypeLibEx("<xxx.xx>")) *************** *** 37,41 **** self.failUnlessEqual(index, i) ! self.assertRaises(WindowsError, lambda: tlib.GetTypeInfoOfGuid(GUID())) self.failUnless(tlib.GetTypeInfoOfGuid(GUID("{EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B}"))) --- 37,41 ---- self.failUnlessEqual(index, i) ! self.assertRaises(COMError, lambda: tlib.GetTypeInfoOfGuid(GUID())) self.failUnless(tlib.GetTypeInfoOfGuid(GUID("{EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B}"))) *************** *** 66,68 **** if __name__ == "__main__": ! unittest.main() --- 66,68 ---- if __name__ == "__main__": ! ut.main() |
From: Thomas H. <th...@us...> - 2005-08-17 16:30:54
|
Update of /cvsroot/ctypes/ctypes/comtypes/tools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27949 Modified Files: Tag: branch_1_0 tlbparser.py Log Message: Use COMError. Index: tlbparser.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/tools/tlbparser.py,v retrieving revision 1.4.2.19 retrieving revision 1.4.2.20 diff -C2 -d -r1.4.2.19 -r1.4.2.20 *** tlbparser.py 10 Aug 2005 13:14:10 -0000 1.4.2.19 --- tlbparser.py 17 Aug 2005 16:30:46 -0000 1.4.2.20 *************** *** 1,4 **** ! import sys ! from comtypes import automation, typeinfo from comtypes.tools import typedesc --- 1,3 ---- ! from comtypes import automation, typeinfo, COMError from comtypes.tools import typedesc *************** *** 520,524 **** # of a dispinterface, if it is dual href = tinfo.GetRefTypeOfImplType(-1) ! except WindowsError: # no dual interface return self.ParseDispatch(tinfo, ta) --- 519,523 ---- # of a dispinterface, if it is dual href = tinfo.GetRefTypeOfImplType(-1) ! except COMError: # no dual interface return self.ParseDispatch(tinfo, ta) |
From: Thomas H. <th...@us...> - 2005-08-17 16:29:53
|
Update of /cvsroot/ctypes/ctypes/comtypes/client In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27691 Added Files: Tag: branch_1_0 __init__.py .cvsignore Log Message: Lots of changes. In short: - make POINTER(<cominterface>) hashable. - registries for cominterfaces and coclasses. - allow a CoClass instance as function parameter when a POINTER(<cominterface>) is required - this calls QueryInterface. - first steps for using the restype in IDispatch.Invoke calls. - Use _ctypes rich COM error reporting by using the _iid_ of an interface when the methods are constructed. - Fix memory management of BSTR, and hopefully also DISPPARAM and VARIANT. - Provide a base class COMObject for implementing COM objects. So far this is only used to implement receivers for COM notifications. The COMObject class implements only the IUnknown interface. - More complete VARIANT support. - Make comtypes.client a package. - Provide a workaround for a buggy(?) safearray function on win2k. --- NEW FILE: .cvsignore --- *.pyc *.pyo --- NEW FILE: __init__.py --- ################################################################ # # TODO: # # - rename wrap # # - rename make_module (generate_module, build_support, build_wrapper, get_wrapper... # # - beautify the code generator output (import statements at the top) # # - should CreateObject accept an interface name? What should it do # when the wrapper cannot be created because no typeinfo is # available? # ################################################################ # comtypes.client # XXX clean up docstring. '''High level client level COM support module. CreateObject(progid, machine=None, clsctx=None, wrapper=None, sink=None, sourceinterface=None) Create a COM object, generating the Python typelibrary wrapper on demand. A pointer to the default interface for the object specified by progid will be returned. wrap(comobj, wrapper=None) make_module(typelib, wrapper=None) Generate a Python wrapper for a COM typelibrary, import and return the module. gen_dir The directory where modules are created, this is the usually the 'comtypes.gen' package directory. In a frozen exe, gen_dir is set to None, and modules are only created in memory. GetObject(displayname, ...) Python wrappers for typelibraries are generated on demand in the comtypes/gen directory. The names of these modules are derived from typelibrary attributes - file names look like this _00020430_0000_0000_C000_000000000046_0_2_0.py so they are not really human readable. The wrapper optional argument to the CreateObject() and the make_module() functions specifies the name for an alias module which will contain everything that the typelib wrapper contains, but the import statement could be written much easier. The friendly name must be a valid Python module name, and the module is also created inside the comtypes.gen package. For example, calling make_module("stdole2.tlb", wrapper="stdole2_tlb") would generate the modules comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0 and comtypes.gen.stdole2_tlb Another example uses the CreateObject function to create an instance of Internet Explorer, generates the typelib wrapper for it, and makes it available as comtypes.gen.IE_typelib module: obj = CreateObject("InternetExplorer.Application", wrapper="IE_typelib") from comtypes.gen import IE_typelib The imported typelib wrapper can be used to access COM constants, for example, and has also the advantage that py2exe would pick up the typelib to include it in the executable. It is possible to create an exe file without importing the typelib with a friendly name. py2exe includes the typelib parser and code generation stuff into the executable, so the typelib wrapper would then be generated at runtime, but only in memory. ''' import sys, os, new, imp import weakref import ctypes ##from ctypes import POINTER, pointer, byref, oledll from comtypes import GUID, CoCreateInstance, CoCreateInstanceEx, COMObject, COMError from comtypes.automation import IDispatch from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2, \ LoadTypeLibEx, LoadRegTypeLib from comtypes.connectionpoints import IConnectionPointContainer ################################################################ # Determine the directory where generated modules live. # Creates the directory if it doesn't exist - if possible. def _find_gen_dir(): if hasattr(sys, "frozen"): try: import comtypes.gen except ImportError: import comtypes module = sys.modules["comtypes.gen"] = new.module("comtypes.gen") comtypes.gen = module return None # determine the place where generated modules live import comtypes comtypes_path = os.path.join(comtypes.__path__[0], "gen") if not os.path.exists(comtypes_path): os.mkdir(comtypes_path) comtypes_init = os.path.join(comtypes_path, "__init__.py") if not os.path.exists(comtypes_init): ofi = open(comtypes_init, "w") ofi.write("# comtypes.gen package, directory for generated files.\n") ofi.close() from comtypes import gen return gen.__path__[0] gen_dir = _find_gen_dir() import comtypes.gen ### for testing ##gen_dir = None ################################################################ def _my_import(fullname): # helper function to import dotted modules return __import__(fullname, globals(), locals(), ['DUMMY']) def _my_findmodule(fullname): # Use imp.find_module to find out whether a module exists or not. # Raise ImportError if it doesn't exist. # # Hm, couldn'w we directly look for the .py or .pyc/.pyo files? name, rest = fullname.split(".", 1) file_, pathname, desc = imp.find_module(name) if file_: file_.close() for name in rest.split("."): file_, pathname, desc = imp.find_module(name, [pathname]) if file_: file_.close() def _name_module(tlib): # Determine the name of a typelib wrapper module. libattr = tlib.GetLibAttr() modname = "_%s_%s_%s_%s" % \ (str(libattr.guid)[1:-1].replace("-", "_"), libattr.lcid, libattr.wMajorVerNum, libattr.wMinorVerNum) return "comtypes.gen." + modname def make_module(tlib, wrapper=None): """Create a module wrapping a COM typelibrary on demand. 'tlib' must be an ITypeLib COM pointer instance, the pathname of a type library, or a tuple/list specifying the arguments to a comtypes.typeinfo.LoadRegTypeLib call: (libid, wMajorVerNum, wMinorVerNum, lcid=0) 'wrapper' allows to specify a name for an alias module which will also be created on demand inside the comtypes.gen package. If 'wrapper' is given and the module corresponding to that can be imported it is returned without trying to load the type library, so it CAN work without the type library actually being present. This function determines the module name from the typelib attributes, then tries to import it. If that fails because the module doesn't exist, the module is generated in the comtypes.gen package. It is possible to delete the whole comtypes\gen directory to remove all generated modules, the directory and the __init__.py file in it will be recreated when needed. If comtypes.gen __path__ is not a directory (in a frozen executable it lives in a zip archive), generated modules are only created in memory without writing them to the file system. Example: make_module("shdocvw.dll", wrapper="IE_typelib") would create a module named comtypes.gen._EAB22AC0_30C1_11CF_A7EB_0000C05BAE0B_0_1_1 containing the wrapper code for the type library used by Internet Explorer. The 'comtypes.gen.IE_typelib' module is created as an alias. """ if wrapper: try: return _my_import("comtypes.gen." + wrapper) except: pass if isinstance(tlib, basestring): # we accept filenames as well tlib = LoadTypeLibEx(tlib) elif isinstance(tlib, (tuple, list)): tlib = LoadRegTypeLib(*tlib) # determine the Python module name fullname = _name_module(tlib) # create and import the module mod = _make_module(tlib, fullname) if wrapper is None: return mod # create and import the friendly-named module try: return _my_import("comtypes.gen." + wrapper) except: # this way, the module is always regenerated if importing it # fails. It would probably be better to check for the # existance of the module first with imp.find_module (but # beware of dotted names), and only regenerate if if not # found. Other errors while importing should probably make # this function fail. print "# Generating comtypes.gen.%s" % wrapper modname = fullname.split(".")[-1] code = "from comtypes.gen import %s\nglobals().update(%s.__dict__)\n" % (modname, modname) code += "__name__ = 'comtypes.gen.%s'" % wrapper if gen_dir is None: mod = new.module("comtypes.gen." + wrapper) exec code in mod.__dict__ sys.modules["comtypes.gen." + wrapper] = mod setattr(comtypes.gen, wrapper, mod) return mod # create in file system, and import it ofi = open(os.path.join(gen_dir, wrapper + ".py"), "w") ofi.write(code) ofi.close() return _my_import("comtypes.gen." + wrapper) def _make_module(tlib, fullname): # helper which creates and imports the real typelib wrapper module. try: return _my_import(fullname) except Exception: # we could not import the module. What was the reason? try: _my_findmodule(fullname) except ImportError: # module does not exist, generate it pass else: # any other error: fail raise # We generate the module since it doesn't exist from comtypes.tools.tlbparser import generate_module modname = fullname.split(".")[-1] if gen_dir is None: import cStringIO ofi = cStringIO.StringIO() else: ofi = open(os.path.join(gen_dir, modname + ".py"), "w") # use warnings.warn, maybe? print "# Generating comtypes.gen.%s" % modname generate_module(tlib, ofi, make_module, _name_module) if gen_dir is None: code = ofi.getvalue() mod = new.module(fullname) exec code in mod.__dict__ sys.modules[fullname] = mod setattr(comtypes.gen, modname, mod) else: ofi.close() mod = _my_import(fullname) reload(mod) return mod # XXX rename this! def wrap(punk, wrapper=None): """Try to QueryInterface a COM pointer to the 'most useful' interface. Get type information for the provided object, either via IDispatch.GetTypeInfo(), or via IProvideClassInfo.GetClassInfo(). Generate a wrapper module for the typelib, and QI for the interface found. """ if not punk: # NULL COM pointer return punk # or should we return None? # find the typelib and the interface name try: pci = punk.QueryInterface(IProvideClassInfo) tinfo = pci.GetClassInfo() # TypeInfo for the CoClass # find the interface marked as default for index in range(tinfo.GetTypeAttr().cImplTypes): if tinfo.GetImplTypeFlags(index) == 1: break else: # should we simply use the first interface now? raise TypeError, "No default interface found" href = tinfo.GetRefTypeOfImplType(index) tinfo = tinfo.GetRefTypeInfo(href) except COMError: try: pdisp = punk.QueryInterface(IDispatch) if pdisp.GetTypeInfoCount() == 0: # no further chance to find typeinfo, and IDispatch is # more useful than IUnknown. return pdisp tinfo = pdisp.GetTypeInfo() except COMError: return punk itf_name = tinfo.GetDocumentation(-1)[0] # interface name tlib = tinfo.GetContainingTypeLib()[0] # typelib # import the wrapper, generating it on demand mod = make_module(tlib, wrapper) # Python interface class interface = getattr(mod, itf_name) # QI for this interface return punk.QueryInterface(interface) # Should we do this for POINTER(IUnknown) also? ctypes.POINTER(IDispatch).__ctypes_from_outparam__ = wrap # XXX move into comtypes def _getmemid(idlflags): # get the dispid from the idlflags sequence return [memid for memid in idlflags if isinstance(memid, int)][0] # XXX move into comtypes? def _get_dispmap(interface): # return a dictionary mapping dispid numbers to method names assert issubclass(interface, IDispatch) dispmap = {} if "dual" in interface._idlflags_: # It would be nice if that would work: ## for info in interface._methods_: ## mth = getattr(interface, info.name) ## memid = mth.im_func.memid # See also MSDN docs for the 'defaultvtable' idl flag, or # IMPLTYPEFLAG_DEFAULTVTABLE. This is not a flag of the # interface, but of the coclass! # # Use the _methods_ list assert not hasattr(interface, "_disp_methods_") for restype, name, argtypes, paramflags, idlflags, helpstring in interface._methods_: memid = _getmemid(idlflags) dispmap[memid] = name else: # Use _disp_methods_ # tag, name, idlflags, restype(?), argtypes(?) for tag, name, idlflags, restype, argtypes in interface._disp_methods_: memid = _getmemid(idlflags) dispmap[memid] = name return dispmap def GetEvents(source, sink, interface=None): """Receive COM events from 'source'. Events will call methods on the 'sink' object. 'interface' is the source interface to use. """ if interface is None: # Untested, but should work. try: pci = source.QueryInterface(IProvideClassInfo2) except COMError: raise TypeError("cannot determine source interface") # another try: block needed? guid = pci.GetGUID(1) interface = comtypes.com_interface_registry[str(guid)] class EventReceiver(COMObject): _com_interfaces_ = [interface] def IDispatch_Invoke(self, this, memid, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr): dp = pDispParams[0] # DISPPARAMS contains the arguments in reverse order args = [dp.rgvarg[i].value for i in range(dp.cArgs)] self.dispmap[memid](None, *args[::-1]) return 0 rcv = EventReceiver() dispmap = _get_dispmap(interface) rcv.dispmap = dispmap for memid, name in dispmap.iteritems(): # find methods to call, if not found ignore event mth = getattr(sink, "%s.%s" % (interface.__name__, name), None) if mth is None: mth = getattr(sink, name, lambda *args: 0) dispmap[memid] = mth cpc = source.QueryInterface(IConnectionPointContainer) cp = cpc.FindConnectionPoint(ctypes.byref(interface._iid_)) cookie = cp.Advise(rcv) def release(ref): cp.Unadvise(cookie) del _active_events[(ref, sink, interface)] # clean up when the source goes away. guard = weakref.ref(source, release) _active_events[(guard, sink, interface)] = release _active_events = {} def ReleaseEvents(source, sink=None, interface=None): """Don't any longer receive events from source. If 'sink' and/or 'interface' is also specified, only those are removed. """ count = 0 # make a copy since we will delete entries for (ref, s, itf), release in _active_events.copy().iteritems(): if ref() == source: if sink is None or s == sink: if interface is None or interface == itf: release(ref) count += 1 # Should count == 0 be an error? return count def CreateObject(progid, machine=None, clsctx=None, wrapper=None, sink=None, sourceinterface=None): """Create a COM object from 'progid', and try to QueryInterface() it to the most useful interface, generating typelib support on demand. A pointer to this interface is returned. 'progid' may be a string like "InternetExplorer.Application", a string specifying a clsid, a GUID instance, or an object with a _clsid_ attribute. 'machine' allows to specify a remote machine to create the object on. 'clsctx' specifies how to create the object. 'wrapper' allows to specify a readable alias name for the typelib wrapper. 'sink' specifies an optional object to receive COM events. 'sourceinterface' is the interface that sends events. If not specified, the default source interface is used. """ clsid = GUID.from_progid(progid) ## clsid = get_clsid(progid) if machine is None: punk = CoCreateInstance(clsid, clsctx=clsctx) else: punk = CoCreateInstanceEx(clsid, clsctx=clsctx, machine=machine) obj = wrap(punk, wrapper) if sink is not None: if sourceinterface is None: # use default outgoing interface sourceinterface = comtypes.com_coclass_registry[str(clsid)]._outgoing_interfaces_[0] GetEvents(obj, sink, sourceinterface) return obj def GetObject(displayName, wrapper=None): """Call CoGetObject(displayname). Additional parameters have the same meaning as in CreateObject(). """ pdisp = ctypes.POINTER(IDispatch)() # Do we need a way to specify the BIND_OPTS parameter? ctypes.oledll.ole32.CoGetObject(unicode(displayName), None, ctypes.byref(IDispatch._iid_), ctypes.byref(pdisp)) ## pci = pdisp.QueryInterface(IProvideClassInfo) ## print pci.GetClassInfo() return wrap(pdisp, wrapper=wrapper) # XXX update __all__ = ["CreateObject", "GetObject", "make_module", "wrap"] ################################################################ if __name__ == "__main__": class Sink(object): def PropertyChanged(self, this, *args): print "PropertyChanged", args ReleaseEvents(m, self) def PropertyDeleted(self, this, *args): print "PropertyDeleted", args def PropertyAdded(self, this, *args): print "PropertyAdded", args ## if args[0].startswith("Measurement"): ## ReleaseEvents(m, self) m = CreateObject("IONTOF.Measurement") GetEvents(m, Sink()) m.Initialize("RetrospectiveAnalysis") m.Uninitialize() del m if 0 and __name__ == "__main__": def test_wmi(): wmi = GetObject("winmgmts:") disks = wmi.InstancesOf("Win32_LogicalDisk") print disks print disks.Count print len(disks) for disk in wmi.InstancesOf("Win32_LogicalDisk"): # XXX This prints VARIANT(u'C:'), not 'C:' print disk.Properties_["DeviceID"].Value print disk.Properties_["DeviceID"] test_wmi() |
From: Thomas H. <th...@us...> - 2005-08-17 16:29:46
|
Update of /cvsroot/ctypes/ctypes/comtypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27659 Modified Files: Tag: branch_1_0 safearray.py automation.py _meta.py __init__.py Removed Files: Tag: branch_1_0 client.py Log Message: Lots of changes. In short: - make POINTER(<cominterface>) hashable. - registries for cominterfaces and coclasses. - allow a CoClass instance as function parameter when a POINTER(<cominterface>) is required - this calls QueryInterface. - first steps for using the restype in IDispatch.Invoke calls. - Use _ctypes rich COM error reporting by using the _iid_ of an interface when the methods are constructed. - Fix memory management of BSTR, and hopefully also DISPPARAM and VARIANT. - Provide a base class COMObject for implementing COM objects. So far this is only used to implement receivers for COM notifications. The COMObject class implements only the IUnknown interface. - More complete VARIANT support. - Make comtypes.client a package. - Provide a workaround for a buggy(?) safearray function on win2k. --- client.py DELETED --- Index: safearray.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/Attic/safearray.py,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -C2 -d -r1.1.2.2 -r1.1.2.3 *** safearray.py 10 Aug 2005 13:14:04 -0000 1.1.2.2 --- safearray.py 17 Aug 2005 16:29:37 -0000 1.1.2.3 *************** *** 15,19 **** def dump(self): print "cDims", self.cDims ! print "fFeatures", self.fFeatures print "cLocks", self.cLocks print "cbElements", self.cbElements --- 15,19 ---- def dump(self): print "cDims", self.cDims ! print "fFeatures 0x%x" % self.fFeatures print "cLocks", self.cLocks print "cbElements", self.cbElements *************** *** 37,44 **** yield data.value ix.value += 1 ! def SafeArray_FromSequence(seq): ! psa = oledll.oleaut32.SafeArrayCreateVector(VT_VARIANT, 0, len(seq)) for index, elem in enumerate(seq): oledll.oleaut32.SafeArrayPutElement(psa, byref(c_long(index)), byref(VARIANT(elem))) --- 37,49 ---- yield data.value ix.value += 1 ! ! # XXX For whatever reason, oleaut32.SafeArrayCreateVector does not seem to work correctly ! # on the Win2k system I have. The result cannot be passed successfully to SafeArrayGetVartype, ! # the call fails with E_INVALIDARG because FADF_HAVEVARTYPE is not set. ! # SafeArrayCreateEx DOES work, as it seems. ! # BTW: A C program has the same behaviour. def SafeArray_FromSequence(seq): ! psa = oledll.oleaut32.SafeArrayCreateVectorEx(VT_VARIANT, 0, len(seq), None) for index, elem in enumerate(seq): oledll.oleaut32.SafeArrayPutElement(psa, byref(c_long(index)), byref(VARIANT(elem))) *************** *** 59,63 **** } vt = TYPECODE[arr.typecode] ! psa = oledll.oleaut32.SafeArrayCreateVector(vt, 0, len(arr)) ptr = c_void_p() oledll.oleaut32.SafeArrayAccessData(psa, byref(ptr)) --- 64,68 ---- } vt = TYPECODE[arr.typecode] ! psa = windll.oleaut32.SafeArrayCreateVectorEx(vt, 0, len(arr), None) ptr = c_void_p() oledll.oleaut32.SafeArrayAccessData(psa, byref(ptr)) *************** *** 82,86 **** result.append(_get_row(ctype, psa, dim+1, indices, upperbounds)) indices[dim] = restore ! return result def _get_ubound(psa, dim): --- 87,91 ---- result.append(_get_row(ctype, psa, dim+1, indices, upperbounds)) indices[dim] = restore ! return tuple(result) # for compatibility with pywin32. def _get_ubound(psa, dim): Index: automation.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/automation.py,v retrieving revision 1.12.2.12 retrieving revision 1.12.2.13 diff -C2 -d -r1.12.2.12 -r1.12.2.13 *** automation.py 10 Aug 2005 13:14:04 -0000 1.12.2.12 --- automation.py 17 Aug 2005 16:29:37 -0000 1.12.2.13 *************** *** 2,6 **** from ctypes import * from _ctypes import CopyComPointer ! from comtypes import IUnknown, GUID, IID, STDMETHOD, BSTR, COMMETHOD, dispid import datetime # for VT_DATE, standard in Python 2.3 and up import array --- 2,6 ---- from ctypes import * from _ctypes import CopyComPointer ! from comtypes import IUnknown, GUID, IID, STDMETHOD, BSTR, COMMETHOD, dispid, COMError import datetime # for VT_DATE, standard in Python 2.3 and up import array *************** *** 49,52 **** --- 49,53 ---- _VariantClear = oledll.oleaut32.VariantClear _SysAllocStringLen = oledll.oleaut32.SysAllocStringLen + _VariantCopyInd = oledll.oleaut32.VariantCopyInd # 30. December 1899, midnight. For VT_DATE. *************** *** 148,152 **** def __del__(self): ! if not self._b_base_: _VariantClear(byref(self)) --- 149,153 ---- def __del__(self): ! if self._b_needsfree_: _VariantClear(byref(self)) *************** *** 277,281 **** # see also c:/sf/pywin32/com/win32com/src/oleargs.cpp elif vt == VT_BYREF|VT_VARIANT: ! return self._.pvarVal[0].value elif self.vt & VT_ARRAY: from comtypes.safearray import UnpackSafeArray --- 278,289 ---- # see also c:/sf/pywin32/com/win32com/src/oleargs.cpp elif vt == VT_BYREF|VT_VARIANT: ! # apparently VariantCopyInd doesn't work with ! # VT_BREF|VT_VARIANT, so do it manually. ! v = cast(self._.c_void_p, POINTER(VARIANT))[0] ! return v.value ! elif self.vt & VT_BYREF: ! v = VARIANT() ! _VariantCopyInd(byref(v), byref(self)) ! return v.value elif self.vt & VT_ARRAY: from comtypes.safearray import UnpackSafeArray *************** *** 419,423 **** ] def __del__(self): ! if not self._b_base_: for i in range(self.cArgs): self.rgvarg[i].value = None --- 427,431 ---- ] def __del__(self): ! if self._b_needsfree_: for i in range(self.cArgs): self.rgvarg[i].value = None *************** *** 472,475 **** --- 480,490 ---- 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. + # _invkind = kw.pop("_invkind", 1) # DISPATCH_METHOD _lcid = kw.pop("_lcid", 0) *************** *** 514,529 **** self.__com_Invoke(dispid, riid_null, _lcid, _invkind, byref(dp), byref(result), byref(excepinfo), byref(argerr)) ! except WindowsError: # , details: ! # we should parse exception information now, depending on ! # the errno we got. XXX Problem (?): error numbers are ! # signed integers, although in C the HRESULT values are ! # normally written in hex notation. ! print "ARGERR", argerr ! print excepinfo raise - return result.value ! # Hm, maybe we should provide separate methods for _METHOD, _PROPERTYGET and _PROPERTYPUT # all the DISP_E_ values from windows.h --- 529,558 ---- self.__com_Invoke(dispid, riid_null, _lcid, _invkind, byref(dp), byref(result), byref(excepinfo), byref(argerr)) ! except COMError, (hresult, text, details): ! 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.value ! # XXX Would separate methods for _METHOD, _PROPERTYGET and _PROPERTYPUT be better? # all the DISP_E_ values from windows.h Index: __init__.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/__init__.py,v retrieving revision 1.25.2.24 retrieving revision 1.25.2.25 diff -C2 -d -r1.25.2.24 -r1.25.2.25 *** __init__.py 10 Aug 2005 13:14:04 -0000 1.25.2.24 --- __init__.py 17 Aug 2005 16:29:37 -0000 1.25.2.25 *************** *** 9,12 **** --- 9,13 ---- from sets import Set as set from ctypes import * + from _ctypes import COMError ##class IDLWarning(UserWarning): *************** *** 73,80 **** ################################################################ ! # The metaclasses... com_interface_registry = {} class _cominterface_meta(type): """Metaclass for COM interfaces. Automatically creates high level --- 74,88 ---- ################################################################ ! # global registries. + # allows to find interface classes by guid strings (iid) com_interface_registry = {} + # allows to find coclasses by guid strings (clsid) + com_coclass_registry = {} + + ################################################################ + # The metaclasses... + class _cominterface_meta(type): """Metaclass for COM interfaces. Automatically creates high level *************** *** 105,115 **** _ptr_bases = (cls, POINTER(bases[0])) def from_param(klass, value): - if isinstance(value, klass): - return value if value is None: return None if klass._iid_ == getattr(value, "_iid_", None): return value return value.QueryInterface(cls) --- 113,145 ---- _ptr_bases = (cls, POINTER(bases[0])) + # The following function will be used as POINTER(<cominterface>).from_param. + # + # It fixes the problem when there are multiple python interface types + # wrapping the same COM interface. This could happen because some interfaces + # are contained in multiple typelibs. + # + # It also allows to pass a CoClass instance to an api + # expecting a COM interface. def from_param(klass, value): if value is None: return None + if isinstance(value, klass): + return value + # multiple python interface types for the same COM interface. + # Do we need more checks here? if klass._iid_ == getattr(value, "_iid_", None): return value + # Accept an CoClass instance which exposes the interface required. + # Again, more checks probably needed... + # Although the CoClass has a QueryInterface method, this method + # has a different signature. + try: + mth = value.IUnknown_QueryInterface + except AttributeError: + pass + else: + ptr = POINTER(klass)() + if 0 == mth(None, pointer(klass._iid_), byref(ptr)): + return ptr return value.QueryInterface(cls) *************** *** 165,168 **** --- 195,203 ---- setattr(self, name, property(*methods)) + # Some ideas, (not only) related to disp_methods: + # + # Should the functions/methods we create have restype and/or + # argtypes attributes? + def _disp_method(self, memid, name, idlflags, restype, argspec): if 'propget' in idlflags: *************** *** 174,186 **** return self.Invoke(obj, memid, _invkind=4, *args, **kw) # DISPATCH_PROPERTYPUT return putfunc ! # The following doesn't have the desired effect ! ## args = [] ! ## for a in argspec: ! ## if len(a) == 4: ! ## args.append("%s=%r" % (a[2], a[3])) ! ## else: ! ## args.append(a[2]) ! def func(obj, *args, **kw): ! return self.Invoke(obj, memid, _invkind=1, *args, **kw) # DISPATCH_METHOD return func --- 209,223 ---- return self.Invoke(obj, memid, _invkind=4, *args, **kw) # DISPATCH_PROPERTYPUT return putfunc ! # a first attempt to make use of the restype. Still, support ! # for named arguments and default argument values should be ! # added. ! if hasattr(restype, "__com_interface__"): ! interface = restype.__com_interface__ ! def func(s, *args, **kw): ! result = self.Invoke(s, memid, _invkind=1, *args, **kw) ! return result.QueryInterface(interface) ! else: ! def func(obj, *args, **kw): ! return self.Invoke(obj, memid, _invkind=1, *args, **kw) # DISPATCH_METHOD return func *************** *** 236,246 **** # attach it with a private name (__com_AddRef, for example), # so that custom method implementations can call it. ! raw_func = prototype(i + vtbl_offset, name) setattr(self, "_%s__com_%s" % (self.__name__, name), new.instancemethod(raw_func, None, self)) ! ! # a high level function calling the COM method ! func = prototype(i + vtbl_offset, name, paramflags) func.__doc__ = doc func.__name__ = name # for pyhelp --- 273,290 ---- # attach it with a private name (__com_AddRef, for example), # so that custom method implementations can call it. ! ! # If the method returns a HRESULT, we pass the interface iid, ! # so that we can request error info for the interface. ! if restype == HRESULT: ! ## print "%s.%s" % (self.__name__, name) ! raw_func = prototype(i + vtbl_offset, name, None, self._iid_) ! func = prototype(i + vtbl_offset, name, paramflags, self._iid_) ! else: ! raw_func = prototype(i + vtbl_offset, name, None, None) ! func = prototype(i + vtbl_offset, name, paramflags, None) setattr(self, "_%s__com_%s" % (self.__name__, name), new.instancemethod(raw_func, None, self)) ! # 'func' is a high level function calling the COM method func.__doc__ = doc func.__name__ = name # for pyhelp *************** *** 367,370 **** --- 411,418 ---- return cmp(super(_compointer_base, self).value, super(_compointer_base, other).value) + def __hash__(self): + # hash the pointer values + return hash(super(_compointer_base, self).value) + # override the .value property of c_void_p # *************** *** 390,394 **** def __del__(self, _free=windll.oleaut32.SysFreeString): """If we own the memory, call SysFreeString to free it.""" ! if not self._b_base_: _free(self) --- 438,442 ---- def __del__(self, _free=windll.oleaut32.SysFreeString): """If we own the memory, call SysFreeString to free it.""" ! if not self._b_needsfree_: _free(self) *************** *** 577,581 **** try: result = mth(index) ! except WindowsError: raise IndexError, "invalid index" # Hm, this doesn't look correct... --- 625,629 ---- try: result = mth(index) ! except COMError: raise IndexError, "invalid index" # Hm, this doesn't look correct... *************** *** 666,694 **** ################################################################ # What's a coclass? # a POINTER to a coclass is allowed as parameter in a function declaration: # http://msdn.microsoft.com/library/en-us/midl/midl/oleautomation.asp ! class CoClass(object): from comtypes._meta import _coclass_meta as __metaclass__ ! ################ ! ##class IErrorInfo(IUnknown): ! ## _iid_ = GUID("{1CF2B120-547D-101B-8E65-08002B2BD119}") ! ## _methods_ = [ ! ## # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 5186 ! ## STDMETHOD(HRESULT, 'GetGUID', [POINTER(GUID)]), ! ## STDMETHOD(HRESULT, 'GetSource', [POINTER(BSTR)]), ! ## STDMETHOD(HRESULT, 'GetDescription', [POINTER(BSTR)]), ! ## STDMETHOD(HRESULT, 'GetHelpFile', [POINTER(BSTR)]), ! ## STDMETHOD(HRESULT, 'GetHelpContext', [POINTER(DWORD)]), ! ## ] ! ################ ! ##class ISupportErrorInfo(IUnknown): ! ## _iid_ = GUID("{DF0B3D60-548F-101B-8E65-08002B2BD119}") ! ## _methods_ = [ ! ## # C:/Programme/gccxml/bin/Vc71/PlatformSDK/oaidl.h 5546 ! ## STDMETHOD(HRESULT, 'InterfaceSupportsErrorInfo', [POINTER(IID)]), ! ## ] ! ##__all__ = ["CoClass", "IUnknown", "GUID", "HRESULT", "BSTR", "STDMETHOD", "COMMETHOD"] --- 714,863 ---- ################################################################ + # COM object implementation + from _ctypes import CopyComPointer + + def _not_impl(*args): + return E_NOTIMPL + + def prepare_comobject(inst): + # When a CoClass instance is created, COM pointers to all + # interfaces are created. Also, the CoClass must be kept alive as + # until the COM reference count drops to zero, even if no Python + # code keeps a reference to the object. + # + # The _com_pointers_ instance variable maps string interface iids + # to C compatible COM pointers. + inst._com_pointers_ = {} + # COM refcount starts at zero. + inst._refcnt = c_long(0) + for itf in inst._com_interfaces_[::-1]: + make_interface_pointer(inst, itf) + # keep reference to the object in a class variable. + inst._instances_[inst] = None + + def make_interface_pointer(inst, itf): + methods = [] # method implementations + fields = [] # (name, prototype) for virtual function table + iids = [] # hashcode for interface identifiers. + # iterate over interface inheritance in reverse order to build the + # virtual function table, and leave out the 'object' base class. + for interface in itf.__mro__[-2::-1]: + for m in interface._methods_: + restype, mthname, argtypes, paramflags, idlflags, helptext = m + proto = WINFUNCTYPE(restype, c_void_p, *argtypes) + fields.append((mthname, proto)) + # try the simple name, like 'QueryInterface' + mth = getattr(inst, mthname, None) + if mth is None: + # qualified name, like 'IUnknown_QueryInterface' + mth = getattr(inst, "%s_%s" % (interface.__name__, mthname), _not_impl) + ## if mth is _not_impl: + ## print "# Method %s.%s not implemented" % (interface.__name__, mthname) + methods.append(proto(mth)) + iids.append(interface._iid_.hashcode()) + class Vtbl(Structure): + _fields_ = fields + Vtbl.__name__ = "Vtbl_%s" % itf.__name__ + vtbl = Vtbl(*methods) + for hashcode in iids: + inst._com_pointers_[hashcode] = pointer(pointer(vtbl)) + + _InterlockedIncrement = windll.kernel32.InterlockedIncrement + _InterlockedDecrement = windll.kernel32.InterlockedDecrement + + ################################################################ + # XXX + from ctypes.com.hresult import E_NOINTERFACE + + class COMObject(object): + _instances_ = {} + + def __new__(cls): + self = super(COMObject, cls).__new__(cls) + if isinstance(self, c_void_p): + # We build the VTables only for direct instances of + # CoClass, not for POINTERs to CoClass. + return self + if hasattr(self, "_com_interfaces_"): + prepare_comobject(self) + return self + + ######################################################### + # IUnknown methods implementations + def IUnknown_AddRef(self, this): + # need _factory hooks here + return _InterlockedIncrement(byref(self._refcnt)) + + def IUnknown_Release(self, this, + _InterlockedDecrement=_InterlockedDecrement, + byref=byref): + # need _factory hooks here + + # If this is called at COM shutdown, byref() and + # _InterlockedDecrement() must still be available, although + # module level variables may have been deleted already - so we + # supply them as default arguments. + result = _InterlockedDecrement(byref(self._refcnt)) + if result == 0: + self._com_pointers_.clear() + del self._instances_[self] + return result + + def IUnknown_QueryInterface(self, this, riid, ppvObj): + ptr = self._com_pointers_.get(riid[0].hashcode(), None) + ## print "QI(%s) -> %s" % (riid[0], bool(ptr)) + if ptr: + # CopyComPointer(src, dst) calls AddRef! + return CopyComPointer(ptr, ppvObj) + return E_NOINTERFACE + + ################################################################ # What's a coclass? # a POINTER to a coclass is allowed as parameter in a function declaration: # http://msdn.microsoft.com/library/en-us/midl/midl/oleautomation.asp ! class CoClass(COMObject): from comtypes._meta import _coclass_meta as __metaclass__ ! ################################################################ ! if __name__ == "__main__": ! # a helper function. Not sure if it is needed, except for testing. ! def _get_interface(comobj, interface): ! # return a com interface pointer from a ComObj instance. ! p = POINTER(interface)() ! # It would be nice if the object return by byref() would have a ! # __getitem__ method so that __getitem__(0) returned the contained ! hr = comobj.IUnknown_QueryInterface(None, ! pointer(interface._iid_), ! byref(p)) ! if hr < 0: ! raise WinError(hr) ! return p ! ! from comtypes.persist import IPersistPropertyBag2, IPersist, IPersistPropertyBag ! class MyObj(COMObject): ! _com_interfaces_ = [IUnknown, IPersistPropertyBag2, IPersistPropertyBag] ! ! ## try: ! ## _get_interface(POINTER(MyObj)(), IUnknown) ! ## except AttributeError: ! ## pass ! ## else: ! ## raise RuntimeError, "this should have failed" ! ! ptr = _get_interface(MyObj(), IUnknown) ! ! print ptr.AddRef(), ptr.Release() ! print ptr.QueryInterface(IUnknown) ! print ptr.QueryInterface(IPersist) ! print ptr.QueryInterface(IPersistPropertyBag2) ! try: ! print ptr.QueryInterface(IPersistPropertyBag) ! except COMError, detail: ! if detail.hresult != E_NOINTERFACE: ! raise ! # clean the traceback ! sys.exc_clear() ! ! del ptr Index: _meta.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/Attic/_meta.py,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** _meta.py 1 Jul 2005 08:04:47 -0000 1.1.2.1 --- _meta.py 17 Aug 2005 16:29:37 -0000 1.1.2.2 *************** *** 1,4 **** --- 1,5 ---- # comtypes._meta helper module from ctypes import POINTER, c_void_p, cast + import comtypes ################################################################ *************** *** 35,38 **** --- 36,43 ---- if bases == (object,): return cls + # XXX We should insist that a _clsid_ is present. + if "_clsid_" in namespace: + clsid = namespace["_clsid_"] + comtypes.com_coclass_registry[str(clsid)] = cls PTR = _coclass_pointer_meta("POINTER(%s)" % cls.__name__, (cls, c_void_p), |
From: Thomas H. <th...@us...> - 2005-08-17 16:02:21
|
Update of /cvsroot/ctypes/ctypes/comtypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19405 Modified Files: Tag: branch_1_0 GUID.py Log Message: Let GUID.from_progid accept: - an object having a _clsid_ attribute - an instance of GUID - a string Index: GUID.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/GUID.py,v retrieving revision 1.6.2.2 retrieving revision 1.6.2.3 diff -C2 -d -r1.6.2.2 -r1.6.2.3 *** GUID.py 10 Aug 2005 13:14:04 -0000 1.6.2.2 --- GUID.py 17 Aug 2005 16:02:13 -0000 1.6.2.3 *************** *** 61,68 **** def from_progid(cls, progid): ! "Get guid from progid" ! inst = cls() ! _CLSIDFromProgID(unicode(progid), byref(inst)) ! return inst from_progid = classmethod(from_progid) --- 61,78 ---- def from_progid(cls, progid): ! """Get guid from progid, ... ! """ ! if hasattr(progid, "_clsid_"): ! progid = progid._clsid_ ! if isinstance(progid, cls): ! return progid ! elif isinstance(progid, basestring): ! if progid.startswith("{"): ! return cls(progid) ! inst = cls() ! _CLSIDFromProgID(unicode(progid), byref(inst)) ! return inst ! else: ! raise TypeError("Cannot construct guid from %r" % progid) from_progid = classmethod(from_progid) |
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16973 Modified Files: Tag: branch_1_0 stgdict.c malloc_closure.c ctypes.h cfield.c callproc.c callbacks.c _ctypes.c Log Message: Implement rich error reporting for COM method calls (on Windows). CFuncPtrObject gets a new iid slot which stores a pointer to the guid of the interface this method belongs to. When iid is != NULL, use IErrorInfo to get rich error information from the com object. Add a COMError class, and implement custom __init__ and __str__ methods. Index: ctypes.h =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/ctypes.h,v retrieving revision 1.74.2.2 retrieving revision 1.74.2.3 diff -C2 -d -r1.74.2.2 -r1.74.2.3 *** ctypes.h 28 Jul 2005 08:57:10 -0000 1.74.2.2 --- ctypes.h 17 Aug 2005 15:54:24 -0000 1.74.2.3 *************** *** 84,87 **** --- 84,88 ---- #ifdef MS_WIN32 int index; + GUID *iid; #endif PyObject *paramflags; *************** *** 249,253 **** PyObject *_CallProc(PPROC pProc, PyObject *arguments, ! void *pIUnk, int flags, PyObject *argtypes, --- 250,257 ---- PyObject *_CallProc(PPROC pProc, PyObject *arguments, ! #ifdef MS_WIN32 ! IUnknown *pIUnk, ! GUID *iid, ! #endif int flags, PyObject *argtypes, *************** *** 367,370 **** --- 371,378 ---- extern void _AddTraceback(char *, char *, int); + #ifdef MS_WIN32 + extern PyObject *ComError; + #endif + /* Local Variables: Index: callproc.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/callproc.c,v retrieving revision 1.127.2.6 retrieving revision 1.127.2.7 diff -C2 -d -r1.127.2.6 -r1.127.2.7 *** callproc.c 2 Aug 2005 18:00:56 -0000 1.127.2.6 --- callproc.c 17 Aug 2005 15:54:24 -0000 1.127.2.7 *************** *** 76,89 **** #ifdef MS_WIN32 static char *FormatError(DWORD code) { ! LPVOID lpMsgBuf; ! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, ! NULL, ! code, ! MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language ! (LPSTR) &lpMsgBuf, ! 0, ! NULL); return (char *)lpMsgBuf; } --- 76,97 ---- #ifdef MS_WIN32 + PyObject *ComError; + static char *FormatError(DWORD code) { ! char *lpMsgBuf; ! DWORD n; ! n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, ! NULL, ! code, ! MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language ! (LPSTR) &lpMsgBuf, ! 0, ! NULL); ! if (n) { ! while (isspace(lpMsgBuf[n-1])) ! --n; ! lpMsgBuf[n] = '\0'; /* rstrip() */ ! } return (char *)lpMsgBuf; } *************** *** 826,831 **** #ifdef MS_WIN32 ! #define alloca _alloca #endif /* * Requirements, must be ensured by the caller: --- 834,897 ---- #ifdef MS_WIN32 ! ! static PyObject * ! GetComError(HRESULT errcode, GUID *riid, IUnknown *pIunk) ! { ! HRESULT hr; ! ISupportErrorInfo *psei = NULL; ! IErrorInfo *pei = NULL; ! BSTR descr=NULL, helpfile=NULL, source=NULL; ! GUID guid; ! DWORD helpcontext=0; ! char *text; ! LPOLESTR progid; ! ! hr = pIunk->lpVtbl->QueryInterface(pIunk, &IID_ISupportErrorInfo, (void **)&psei); ! if (FAILED(hr)) ! goto failed; ! hr = psei->lpVtbl->InterfaceSupportsErrorInfo(psei, riid); ! psei->lpVtbl->Release(psei); ! ! if (FAILED(hr)) ! goto failed; ! hr = GetErrorInfo(0, &pei); ! if (hr != S_OK) ! goto failed; ! ! pei->lpVtbl->GetDescription(pei, &descr); ! pei->lpVtbl->GetGUID(pei, &guid); ! pei->lpVtbl->GetHelpContext(pei, &helpcontext); ! pei->lpVtbl->GetHelpFile(pei, &helpfile); ! pei->lpVtbl->GetSource(pei, &source); ! ! failed: ! if (pei) ! pei->lpVtbl->Release(pei); ! ! progid = NULL; ! ProgIDFromCLSID(&guid, &progid); ! /* XXX Free progid with CoTaskMemFree */ ! ! /* XXX Is COMError derived from WindowsError or not? */ ! text = FormatError(errcode); ! PyErr_SetObject(ComError, ! Py_BuildValue("is(uuuiu)", ! errcode, ! FormatError(errcode), ! descr, source, helpfile, helpcontext, ! progid)); ! LocalFree(text); ! ! if (descr) ! SysFreeString(descr); ! if (helpfile) ! SysFreeString(helpfile); ! if (source) ! SysFreeString(source); ! ! return NULL; ! } #endif + /* * Requirements, must be ensured by the caller: *************** *** 837,841 **** PyObject *_CallProc(PPROC pProc, PyObject *argtuple, ! void *pIunk, int flags, PyObject *argtypes, /* misleading name: This is a method, --- 903,910 ---- PyObject *_CallProc(PPROC pProc, PyObject *argtuple, ! #ifdef MS_WIN32 ! IUnknown *pIunk, ! GUID *iid, ! #endif int flags, PyObject *argtypes, /* misleading name: This is a method, *************** *** 924,928 **** #ifdef MS_WIN32 ! if (flags & FUNCFLAG_HRESULT) { if (*(int *)resbuf & 0x80000000) retval = PyErr_SetFromWindowsErr(*(int *)resbuf); --- 993,1002 ---- #ifdef MS_WIN32 ! if (iid && pIunk) { ! if (*(int *)resbuf & 0x80000000) ! retval = GetComError(*(HRESULT *)resbuf, iid, pIunk); ! else ! retval = PyInt_FromLong(*(int *)resbuf); ! } else if (flags & FUNCFLAG_HRESULT) { if (*(int *)resbuf & 0x80000000) retval = PyErr_SetFromWindowsErr(*(int *)resbuf); *************** *** 1042,1046 **** --- 1116,1123 ---- result = _CallProc(lpVtbl[index], arguments, + #ifdef MS_WIN32 pIunk, + NULL, + #endif FUNCFLAG_HRESULT, /* flags */ argtypes, /* self->argtypes */ *************** *** 1158,1162 **** --- 1235,1242 ---- result = _CallProc(func, arguments, + #ifdef MS_WIN32 + NULL, NULL, + #endif 0, /* flags */ NULL, /* self->argtypes */ *************** *** 1186,1190 **** --- 1266,1273 ---- result = _CallProc(func, arguments, + #ifdef MS_WIN32 + NULL, NULL, + #endif FUNCFLAG_CDECL, /* flags */ NULL, /* self->argtypes */ Index: cfield.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/cfield.c,v retrieving revision 1.74 retrieving revision 1.74.2.1 diff -C2 -d -r1.74 -r1.74.2.1 *** cfield.c 9 Mar 2005 15:45:05 -0000 1.74 --- cfield.c 17 Aug 2005 15:54:24 -0000 1.74.2.1 *************** *** 3,10 **** #include <ffi.h> - #include "ctypes.h" #ifdef MS_WIN32 #include <windows.h> #endif /******************************************************************/ --- 3,10 ---- #include <ffi.h> #ifdef MS_WIN32 #include <windows.h> #endif + #include "ctypes.h" /******************************************************************/ Index: stgdict.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/stgdict.c,v retrieving revision 1.32 retrieving revision 1.32.2.1 diff -C2 -d -r1.32 -r1.32.2.1 *** stgdict.c 14 Mar 2005 08:03:47 -0000 1.32 --- stgdict.c 17 Aug 2005 15:54:24 -0000 1.32.2.1 *************** *** 1,4 **** --- 1,7 ---- #include "Python.h" #include <ffi.h> + #ifdef MS_WIN32 + #include <windows.h> + #endif #include "ctypes.h" Index: malloc_closure.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/malloc_closure.c,v retrieving revision 1.10 retrieving revision 1.10.6.1 diff -C2 -d -r1.10 -r1.10.6.1 *** malloc_closure.c 25 Oct 2004 07:56:35 -0000 1.10 --- malloc_closure.c 17 Aug 2005 15:54:24 -0000 1.10.6.1 *************** *** 1,4 **** --- 1,13 ---- #include <Python.h> #include <ffi.h> + #ifdef MS_WIN32 + #include <windows.h> + #else + #include <sys/mman.h> + #include <unistd.h> + # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) + # define MAP_ANONYMOUS MAP_ANON + # endif + #endif #include "ctypes.h" *************** *** 14,27 **** /******************************************************************/ - #ifdef MS_WIN32 - #include <windows.h> - #else - #include <sys/mman.h> - #include <unistd.h> - # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) - # define MAP_ANONYMOUS MAP_ANON - # endif - #endif - typedef union _tagITEM { ffi_closure closure; --- 23,26 ---- Index: _ctypes.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/_ctypes.c,v retrieving revision 1.226.2.17 retrieving revision 1.226.2.18 diff -C2 -d -r1.226.2.17 -r1.226.2.18 *** _ctypes.c 12 Aug 2005 07:25:21 -0000 1.226.2.17 --- _ctypes.c 17 Aug 2005 15:54:24 -0000 1.226.2.18 *************** *** 104,109 **** #include <ffi.h> - #include "ctypes.h" - #ifdef MS_WIN32 #include <windows.h> --- 104,107 ---- *************** *** 111,114 **** --- 109,113 ---- #include <dlfcn.h> #endif + #include "ctypes.h" PyObject *PyExc_ArgError; *************** *** 2354,2359 **** char *name = NULL; PyObject *paramflags = NULL; ! if (!PyArg_ParseTuple(args, "is|O", &index, &name, ¶mflags)) return NULL; if (paramflags == Py_None) --- 2353,2360 ---- char *name = NULL; PyObject *paramflags = NULL; + GUID *iid; + int iid_len; ! if (!PyArg_ParseTuple(args, "is|Oz#", &index, &name, ¶mflags, &iid, &iid_len)) return NULL; if (paramflags == Py_None) *************** *** 2367,2370 **** --- 2368,2373 ---- Py_XINCREF(paramflags); self->paramflags = paramflags; + if (iid_len == sizeof(GUID)) + self->iid = iid; return (PyObject *)self; } *************** *** 2863,2868 **** #ifdef MS_WIN32 piunk, ! #else ! NULL, #endif dict->flags, --- 2866,2870 ---- #ifdef MS_WIN32 piunk, ! self->iid, #endif dict->flags, *************** *** 3875,3878 **** --- 3877,3973 ---- "Create and manipulate C compatible data types in Python."; + #ifdef MS_WIN32 + + static char comerror_doc[] = "Raised when a COM method call failed."; + + static PyObject * + comerror_str(PyObject *ignored, PyObject *self) + { + PyObject *args = PyObject_GetAttrString(self, "args"); + PyObject *result; + if (args == NULL) + return NULL; + result = PyObject_Str(args); + Py_DECREF(args); + return result; + } + + static PyObject * + comerror_init(PyObject *self, PyObject *args) + { + PyObject *hresult, *text, *details; + PyObject *a; + int status; + + if (!PyArg_ParseTuple(args, "OOOO", &self, &hresult, &text, &details)) + return NULL; + + a = PySequence_GetSlice(args, 1, PySequence_Size(args)); + if (!a) + return NULL; + status = PyObject_SetAttrString(self, "args", a); + Py_DECREF(a); + if (status < 0) + return NULL; + + if (PyObject_SetAttrString(self, "hresult", hresult) < 0) + return NULL; + + if (PyObject_SetAttrString(self, "text", text) < 0) + return NULL; + + if (PyObject_SetAttrString(self, "details", details) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + static PyMethodDef comerror_methods[] = { + { "__str__", comerror_str, METH_O }, + { "__init__", comerror_init, METH_VARARGS }, + { NULL, NULL }, + }; + + PyObject *COMError; + + static int + create_comerror(void) + { + PyObject *dict = PyDict_New(); + PyMethodDef *methods = comerror_methods; + PyObject *s; + int status; + + ComError = PyErr_NewException("_ctypes.COMError", + NULL, + dict); + if (ComError == NULL) + return -1; + while (methods->ml_name) { + /* get a wrapper for the built-in function */ + PyObject *func = PyCFunction_New(methods, NULL); + PyObject *meth; + if (func == NULL) + return -1; + meth = PyMethod_New(func, NULL, ComError); + Py_DECREF(func); + if (meth == NULL) + return -1; + PyDict_SetItemString(dict, methods->ml_name, meth); + Py_DECREF(meth); + ++methods; + } + Py_INCREF(ComError); + s = PyString_FromString(comerror_doc); + if (s == NULL) + return -1; + status = PyDict_SetItemString(dict, "__doc__", s); + Py_DECREF(s); + return status; + } + + #endif + DL_EXPORT(void) init_ctypes(void) *************** *** 3985,3988 **** --- 4080,4087 ---- #ifdef MS_WIN32 + if (create_comerror() < 0) + return; + PyModule_AddObject(m, "COMError", ComError); + PyModule_AddObject(m, "FUNCFLAG_HRESULT", PyInt_FromLong(FUNCFLAG_HRESULT)); PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyInt_FromLong(FUNCFLAG_STDCALL)); Index: callbacks.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/callbacks.c,v retrieving revision 1.71.2.1 retrieving revision 1.71.2.2 diff -C2 -d -r1.71.2.1 -r1.71.2.2 *** callbacks.c 12 Aug 2005 07:38:39 -0000 1.71.2.1 --- callbacks.c 17 Aug 2005 15:54:24 -0000 1.71.2.2 *************** *** 4,12 **** #include <ffi.h> - #include "ctypes.h" - #ifdef MS_WIN32 #include <windows.h> #endif /* For 2.3, use the PyGILState_ calls, see PEP 311 */ --- 4,11 ---- #include <ffi.h> #ifdef MS_WIN32 #include <windows.h> #endif + #include "ctypes.h" /* For 2.3, use the PyGILState_ calls, see PEP 311 */ |
From: Thomas H. <th...@us...> - 2005-08-17 15:35:07
|
Update of /cvsroot/ctypes/ctypes/comtypes/client In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12300/client Log Message: Directory /cvsroot/ctypes/ctypes/comtypes/client added to the repository --> Using per-directory sticky tag `branch_1_0' |
From: Thomas H. <th...@us...> - 2005-08-12 07:38:49
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27355 Modified Files: Tag: branch_1_0 callbacks.c Log Message: A buffer allocated for callbacks was too small. Problem reported by Mike Fletcher. Index: callbacks.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/callbacks.c,v retrieving revision 1.71 retrieving revision 1.71.2.1 diff -C2 -d -r1.71 -r1.71.2.1 *** callbacks.c 16 Mar 2005 17:50:25 -0000 1.71 --- callbacks.c 12 Aug 2005 07:38:39 -0000 1.71.2.1 *************** *** 314,318 **** void FreeCallback(THUNK thunk) { ! FreeClosure(*(void **)thunk); PyMem_Free(thunk); } --- 314,318 ---- void FreeCallback(THUNK thunk) { ! FreeClosure(((ffi_info *)thunk)->pcl); PyMem_Free(thunk); } *************** *** 329,333 **** nArgs = PySequence_Size(converters); ! p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * nArgs); if (p == NULL) { PyErr_NoMemory(); --- 329,333 ---- nArgs = PySequence_Size(converters); ! p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs + 1)); if (p == NULL) { PyErr_NoMemory(); |
From: Thomas H. <th...@us...> - 2005-08-12 07:32:22
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26656 Modified Files: Tag: branch_1_0 test_numbers.py Log Message: Adapt the test for Python 2.5 (as in CVS). Index: test_numbers.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/unittests/test_numbers.py,v retrieving revision 1.21 retrieving revision 1.21.6.1 diff -C2 -d -r1.21 -r1.21.6.1 *** test_numbers.py 19 Aug 2004 11:34:52 -0000 1.21 --- test_numbers.py 12 Aug 2005 07:32:14 -0000 1.21.6.1 *************** *** 89,93 **** # _as_parameter_ is readonly! ! self.assertRaises(TypeError, setattr, t(), "_as_parameter_", None) def test_byref(self): --- 89,96 ---- # _as_parameter_ is readonly! ! # ! # Python 2.3 and 2.4 raise a TypeError when trying to set ! # a readonly attribute, 2.5 raises an AttributeError. ! self.assertRaises((AttributeError, TypeError), setattr, t(), "_as_parameter_", None) def test_byref(self): |
From: Thomas H. <th...@us...> - 2005-08-12 07:25:29
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25700 Modified Files: Tag: branch_1_0 _ctypes.c Log Message: Expose the b_needsfree flag to Python - needed for COM memory management. Index: _ctypes.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/_ctypes.c,v retrieving revision 1.226.2.16 retrieving revision 1.226.2.17 diff -C2 -d -r1.226.2.16 -r1.226.2.17 *** _ctypes.c 2 Aug 2005 18:00:52 -0000 1.226.2.16 --- _ctypes.c 12 Aug 2005 07:25:21 -0000 1.226.2.17 *************** *** 1714,1717 **** --- 1714,1720 ---- offsetof(CDataObject, b_base), READONLY, "the base object" }, + { "_b_needsfree_", T_INT, + offsetof(CDataObject, b_needsfree), READONLY, + "whether the object owns the memory or not" }, { "_objects", T_OBJECT, offsetof(CDataObject, b_objects), READONLY, |
From: Thomas H. <th...@us...> - 2005-08-11 20:13:02
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27855 Modified Files: Tag: branch_1_0 test_cast.py Log Message: The fix did work. Index: test_cast.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/unittests/Attic/test_cast.py,v retrieving revision 1.1.2.4 retrieving revision 1.1.2.5 diff -C2 -d -r1.1.2.4 -r1.1.2.5 *** test_cast.py 11 Aug 2005 20:10:36 -0000 1.1.2.4 --- test_cast.py 11 Aug 2005 20:12:47 -0000 1.1.2.5 *************** *** 21,25 **** [0, 42, 0, 17, 0, 2]) - # XXX CRASHES on AMD64 def test_address2pointer(self): array = (c_int * 3)(42, 17, 2) --- 21,24 ---- *************** *** 30,35 **** # on this platform. - address = addressof(array) # So we have to wrap the address into a c_void_p for this to work. ptr = cast(c_void_p(address), POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) --- 29,36 ---- # on this platform. # So we have to wrap the address into a c_void_p for this to work. + # + # XXX Better would be to hide the differences in the cast function. + address = addressof(array) ptr = cast(c_void_p(address), POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) |
From: Thomas H. <th...@us...> - 2005-08-11 20:10:57
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27344 Modified Files: Tag: branch_1_0 test_cast.py Log Message: Try to fix this test for AMD64. Index: test_cast.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/unittests/Attic/test_cast.py,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -C2 -d -r1.1.2.3 -r1.1.2.4 *** test_cast.py 11 Aug 2005 19:57:43 -0000 1.1.2.3 --- test_cast.py 11 Aug 2005 20:10:36 -0000 1.1.2.4 *************** *** 21,29 **** [0, 42, 0, 17, 0, 2]) def test_address2pointer(self): array = (c_int * 3)(42, 17, 2) ! # it works even to cast the address of the array to a pointer. ! ptr = cast(addressof(array), POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) --- 21,36 ---- [0, 42, 0, 17, 0, 2]) + # XXX CRASHES on AMD64 def test_address2pointer(self): array = (c_int * 3)(42, 17, 2) ! # on AMD64, sizeof(int) == 4 and sizeof(void *) == 8. ! # By default, cast would convert a Python int (or long) into ! # a C int, which would be too short to represent a pointer ! # on this platform. ! ! address = addressof(array) ! # So we have to wrap the address into a c_void_p for this to work. ! ptr = cast(c_void_p(address), POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) |
From: Thomas H. <th...@us...> - 2005-08-11 19:57:51
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24374 Modified Files: Tag: branch_1_0 test_cast.py Log Message: Separate the addressof test, it seems to fail on Linux AMD64. Index: test_cast.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/unittests/Attic/test_cast.py,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -C2 -d -r1.1.2.2 -r1.1.2.3 *** test_cast.py 11 Aug 2005 19:49:11 -0000 1.1.2.2 --- test_cast.py 11 Aug 2005 19:57:43 -0000 1.1.2.3 *************** *** 12,19 **** self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) - # it works even to cast the address of the array to a pointer. - ptr = cast(addressof(array), POINTER(c_int)) - self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) - if 2*sizeof(c_short) == sizeof(c_int): ptr = cast(array, POINTER(c_short)) --- 12,15 ---- *************** *** 25,35 **** [0, 42, 0, 17, 0, 2]) def test_ptr2array(self): ! pass ! ## array = (c_int * 3)(42, 17, 2) ## ptr = cast(array, POINTER(c_int)) ## self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) ## print ptr[0], ptr[1], ptr[2] ## ptr = POINTER(c_int).from_address(addressof(array)) --- 21,42 ---- [0, 42, 0, 17, 0, 2]) + def test_address2pointer(self): + array = (c_int * 3)(42, 17, 2) + + # it works even to cast the address of the array to a pointer. + ptr = cast(addressof(array), POINTER(c_int)) + self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) + + def test_ptr2array(self): ! array = (c_int * 3)(42, 17, 2) + ## # Hm, already tested above. ## ptr = cast(array, POINTER(c_int)) ## self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) + # print cast(addressof(array), c_int * 3)[:] + ## ptr = cast(addressof(ptr) + ## print ptr[0], ptr[1], ptr[2] ## ptr = POINTER(c_int).from_address(addressof(array)) |
From: Thomas H. <th...@us...> - 2005-08-11 19:49:29
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22724 Modified Files: Tag: branch_1_0 test_cast.py Log Message: Less verbose, and test more. Index: test_cast.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/unittests/Attic/test_cast.py,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -C2 -d -r1.1.2.1 -r1.1.2.2 *** test_cast.py 11 Aug 2005 19:33:54 -0000 1.1.2.1 --- test_cast.py 11 Aug 2005 19:49:11 -0000 1.1.2.2 *************** *** 3,22 **** import sys - print sys.byteorder - class Test(unittest.TestCase): def test_array2pointer(self): array = (c_int * 3)(42, 17, 2) ptr = cast(array, POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) ! ptr = cast(array, POINTER(c_short)) ! if sys.byteorder == "little": ! self.failUnlessEqual([ptr[i] for i in range(6)], ! [42, 0, 17, 0, 2, 0]) ! else: ! self.failUnlessEqual([ptr[i] for i in range(6)], ! [0, 42, 0, 17, 0, 2]) if __name__ == "__main__": --- 3,39 ---- import sys class Test(unittest.TestCase): + def test_array2pointer(self): array = (c_int * 3)(42, 17, 2) + # casting an array to a pointer works. ptr = cast(array, POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) ! # it works even to cast the address of the array to a pointer. ! ptr = cast(addressof(array), POINTER(c_int)) ! self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) ! ! if 2*sizeof(c_short) == sizeof(c_int): ! ptr = cast(array, POINTER(c_short)) ! if sys.byteorder == "little": ! self.failUnlessEqual([ptr[i] for i in range(6)], ! [42, 0, 17, 0, 2, 0]) ! else: ! self.failUnlessEqual([ptr[i] for i in range(6)], ! [0, 42, 0, 17, 0, 2]) ! ! def test_ptr2array(self): ! pass ! ## array = (c_int * 3)(42, 17, 2) ! ! ## ptr = cast(array, POINTER(c_int)) ! ## self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) ! ! ## print ptr[0], ptr[1], ptr[2] ! ## ptr = POINTER(c_int).from_address(addressof(array)) ! ## # XXX this crashes: ! ## print ptr[0], ptr[1], ptr[2] if __name__ == "__main__": |
From: Thomas H. <th...@us...> - 2005-08-11 19:34:02
|
Update of /cvsroot/ctypes/ctypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19695 Added Files: Tag: branch_1_0 test_cast.py Log Message: Test the cast function. Long overdue. --- NEW FILE: test_cast.py --- from ctypes import * import unittest import sys print sys.byteorder class Test(unittest.TestCase): def test_array2pointer(self): array = (c_int * 3)(42, 17, 2) ptr = cast(array, POINTER(c_int)) self.failUnlessEqual([ptr[i] for i in range(3)], [42, 17, 2]) ptr = cast(array, POINTER(c_short)) if sys.byteorder == "little": self.failUnlessEqual([ptr[i] for i in range(6)], [42, 0, 17, 0, 2, 0]) else: self.failUnlessEqual([ptr[i] for i in range(6)], [0, 42, 0, 17, 0, 2]) if __name__ == "__main__": unittest.main() |
From: Thomas H. <th...@us...> - 2005-08-10 14:54:42
|
Update of /cvsroot/ctypes/ctypes/comtypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28915 Modified Files: Tag: branch_1_0 client.py Log Message: If 'friendly_name' is given in the make_module call and the wrapper module can be imported, the type library is NOT loaded. This allows the code to work without the type library actually being present. Index: client.py =================================================================== RCS file: /cvsroot/ctypes/ctypes/comtypes/Attic/client.py,v retrieving revision 1.1.2.5 retrieving revision 1.1.2.6 diff -C2 -d -r1.1.2.5 -r1.1.2.6 *** client.py 10 Aug 2005 13:14:04 -0000 1.1.2.5 --- client.py 10 Aug 2005 14:54:31 -0000 1.1.2.6 *************** *** 154,157 **** --- 154,161 ---- 'friendly_name' allows to specify a name for an alias module which will also be created on demand inside the comtypes.gen package. + If 'friendly_name' is given and the module corresponding to that + can be imported it is returned without trying to load the type + library, so it CAN work without the type library actually being + present. This function determines the module name from the typelib *************** *** 181,184 **** --- 185,195 ---- alias. """ + if friendly_name: + try: + return _my_import("comtypes.gen." + friendly_name) + except: + import traceback + traceback.print_exc() + pass if isinstance(tlib, basestring): # we accept filenames as well |
From: Thomas H. <th...@us...> - 2005-08-10 13:18:16
|
Update of /cvsroot/ctypes/ctypes/comtypes/unittests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2072 Added Files: Tag: branch_1_0 test_safearray.py test_excel.py Log Message: More tests. --- NEW FILE: test_excel.py --- # -*- coding: latin-1 -*- import unittest import datetime from comtypes.client import CreateObject class Test(unittest.TestCase): def setUp(self): self.xl = CreateObject("Excel.Application") def test_excel(self): xl = self.xl xl.Visible = 0 self.failUnlessEqual(xl.Visible, False) xl.Visible = 1 self.failUnlessEqual(xl.Visible, True) wb = xl.Workbooks.Add() xl.Range("A1", "C1").Value = [1,"2",3.14] xl.Range("A2:C2").Value = ('x','y','z') xl.Range("A3:C3").Value = ('3','2','1') self.failUnlessEqual(xl.Range("A1:C3").Value, [[1.0, 2.0, 3.14], ["x", "y", "z"], [3.0, 2.0, 1.0]]) self.failUnlessEqual(xl.Range("A1", "C3").Value, [[1.0, 2.0, 3.14], ["x", "y", "z"], [3.0, 2.0, 1.0]]) for i in xrange(20): xl.Cells(i+1,i+1).Value = "Hi %d" % i # test dates out with Excel xl.Range("A5").Value = "Excel time" xl.Range("B5").Formula = "=Now()" self.failUnlessEqual(xl.Cells(5,2).Formula, "=NOW()") xl.Range("A6").Calculate() excel_time = xl.Range("B5").Value self.failUnlessEqual(type(excel_time), datetime.datetime) python_time = datetime.datetime.now() self.failUnless(python_time >= excel_time) self.failUnless(python_time - excel_time < datetime.timedelta(seconds=1)) # How does "xl.Cells.Item(1, 2)" work? # xl.Cells is a POINTER(Range) instance. # Callign this is the same as calling it's .Item value: self.failUnlessEqual(xl.Cells.Item(1, 2).Value, xl.Cells(1, 2).Value) # some random code, grabbed from c.l.p sh = wb.Worksheets(1) sh.Cells(1,1).Value = "Hello World!" sh.Cells(3,3).Value = "Hello World!" sh.Range(sh.Cells(1,1),sh.Cells(3,3)).Copy(sh.Cells(4,1)) sh.Range(sh.Cells(4,1),sh.Cells(6,3)).Select() import time time.sleep(2) def tearDown(self): # Close all open workbooks without saving, then quit excel. for wb in self.xl.Workbooks: wb.Close(0) self.xl.Quit() if __name__ == "__main__": unittest.main() --- NEW FILE: test_safearray.py --- import unittest from comtypes.automation import VARIANT, VT_ARRAY, VT_VARIANT, VT_I4, VT_R4, VT_R8 class TestCase(unittest.TestCase): def test_1(self): v = VARIANT() v.value = ((1, 2, 3), ("foo", "bar", None)) self.failUnlessEqual(v.vt, VT_ARRAY | VT_VARIANT) self.failUnlessEqual(v.value, [[1, 2, 3], ["foo", "bar", None]]) def test_double_array(self): import array a = array.array("d", (3.14, 2.78)) v = VARIANT(a) self.failUnlessEqual(v.vt, VT_ARRAY | VT_R8) self.failUnlessEqual(a.tolist(), v.value) def test_float_array(self): import array a = array.array("f", (3.14, 2.78)) v = VARIANT(a) self.failUnlessEqual(v.vt, VT_ARRAY | VT_R4) self.failUnlessEqual(a.tolist(), v.value) if __name__ == "__main__": unittest.main() |