1#@PydevCodeAnalysisIgnore
2"""create and manipulate C data types in Python"""
3
4import os as _os, sys as _sys
5from itertools import chain as _chain
6
7# special developer support to use ctypes from the CVS sandbox,
8# without installing it
9# XXX Remove this for the python core version
10_magicfile = _os.path.join(_os.path.dirname(__file__), ".CTYPES_DEVEL")
11if _os.path.isfile(_magicfile):
12    execfile(_magicfile)
13del _magicfile
14
15__version__ = "0.9.9.6"
16
17from _ctypes import Union, Structure, Array
18from _ctypes import _Pointer
19from _ctypes import CFuncPtr as _CFuncPtr
20from _ctypes import __version__ as _ctypes_version
21from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
22from _ctypes import ArgumentError
23
24from struct import calcsize as _calcsize
25
26if __version__ != _ctypes_version:
27    raise Exception, ("Version number mismatch", __version__, _ctypes_version)
28
29if _os.name in ("nt", "ce"):
30    from _ctypes import FormatError
31
32from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
33     FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI
34
35"""
36WINOLEAPI -> HRESULT
37WINOLEAPI_(type)
38
39STDMETHODCALLTYPE
40
41STDMETHOD(name)
42STDMETHOD_(type, name)
43
44STDAPICALLTYPE
45"""
46
47def create_string_buffer(init, size=None):
48    """create_string_buffer(aString) -> character array
49    create_string_buffer(anInteger) -> character array
50    create_string_buffer(aString, anInteger) -> character array
51    """
52    if isinstance(init, (str, unicode)):
53        if size is None:
54            size = len(init) + 1
55        buftype = c_char * size
56        buf = buftype()
57        buf.value = init
58        return buf
59    elif isinstance(init, (int, long)):
60        buftype = c_char * init
61        buf = buftype()
62        return buf
63    raise TypeError, init
64
65def c_buffer(init, size=None):
66##    "deprecated, use create_string_buffer instead"
67##    import warnings
68##    warnings.warn("c_buffer is deprecated, use create_string_buffer instead",
69##                  DeprecationWarning, stacklevel=2)
70    return create_string_buffer(init, size)
71
72_c_functype_cache = {}
73def CFUNCTYPE(restype, *argtypes):
74    """CFUNCTYPE(restype, *argtypes) -> function prototype.
75
76    restype: the result type
77    argtypes: a sequence specifying the argument types
78
79    The function prototype can be called in three ways to create a
80    callable object:
81
82    prototype(integer address) -> foreign function
83    prototype(callable) -> create and return a C callable function from callable
84    prototype(integer index, method name[, paramflags]) -> foreign function calling a COM method
85    prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
86    prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
87    """
88    try:
89        return _c_functype_cache[(restype, argtypes)]
90    except KeyError:
91        class CFunctionType(_CFuncPtr):
92            _argtypes_ = argtypes
93            _restype_ = restype
94            _flags_ = _FUNCFLAG_CDECL
95        _c_functype_cache[(restype, argtypes)] = CFunctionType
96        return CFunctionType
97
98if _os.name in ("nt", "ce"):
99    from _ctypes import LoadLibrary as _dlopen
100    from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
101    if _os.name == "ce":
102        # 'ce' doesn't have the stdcall calling convention
103        _FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
104
105    _win_functype_cache = {}
106    def WINFUNCTYPE(restype, *argtypes):
107        # docstring set later (very similar to CFUNCTYPE.__doc__)
108        try:
109            return _win_functype_cache[(restype, argtypes)]
110        except KeyError:
111            class WinFunctionType(_CFuncPtr):
112                _argtypes_ = argtypes
113                _restype_ = restype
114                _flags_ = _FUNCFLAG_STDCALL
115            _win_functype_cache[(restype, argtypes)] = WinFunctionType
116            return WinFunctionType
117    if WINFUNCTYPE.__doc__:
118        WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
119
120elif _os.name == "posix":
121    from _ctypes import dlopen as _dlopen #@UnresolvedImport
122
123from _ctypes import sizeof, byref, addressof, alignment
124from _ctypes import _SimpleCData
125
126class py_object(_SimpleCData):
127    _type_ = "O"
128
129class c_short(_SimpleCData):
130    _type_ = "h"
131
132class c_ushort(_SimpleCData):
133    _type_ = "H"
134
135class c_long(_SimpleCData):
136    _type_ = "l"
137
138class c_ulong(_SimpleCData):
139    _type_ = "L"
140
141if _calcsize("i") == _calcsize("l"):
142    # if int and long have the same size, make c_int an alias for c_long
143    c_int = c_long
144    c_uint = c_ulong
145else:
146    class c_int(_SimpleCData):
147        _type_ = "i"
148
149    class c_uint(_SimpleCData):
150        _type_ = "I"
151
152class c_float(_SimpleCData):
153    _type_ = "f"
154
155class c_double(_SimpleCData):
156    _type_ = "d"
157
158if _calcsize("l") == _calcsize("q"):
159    # if long and long long have the same size, make c_longlong an alias for c_long
160    c_longlong = c_long
161    c_ulonglong = c_ulong
162else:
163    class c_longlong(_SimpleCData):
164        _type_ = "q"
165
166    class c_ulonglong(_SimpleCData):
167        _type_ = "Q"
168    ##    def from_param(cls, val):
169    ##        return ('d', float(val), val)
170    ##    from_param = classmethod(from_param)
171
172class c_ubyte(_SimpleCData):
173    _type_ = "B"
174c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte
175# backward compatibility:
176##c_uchar = c_ubyte
177
178class c_byte(_SimpleCData):
179    _type_ = "b"
180c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte
181
182class c_char(_SimpleCData):
183    _type_ = "c"
184c_char.__ctype_le__ = c_char.__ctype_be__ = c_char
185
186class c_char_p(_SimpleCData):
187    _type_ = "z"
188
189class c_void_p(_SimpleCData):
190    _type_ = "P"
191c_voidp = c_void_p # backwards compatibility (to a bug)
192
193# This cache maps types to pointers to them.
194_pointer_type_cache = {}
195
196def POINTER(cls):
197    try:
198        return _pointer_type_cache[cls]
199    except KeyError:
200        pass
201    if type(cls) is str:
202        klass = type(_Pointer)("LP_%s" % cls,
203                               (_Pointer,),
204                               {})
205        _pointer_type_cache[id(klass)] = klass
206        return klass
207    else:
208        name = "LP_%s" % cls.__name__
209        klass = type(_Pointer)(name,
210                               (_Pointer,),
211                               {'_type_': cls})
212        _pointer_type_cache[cls] = klass
213    return klass
214
215try:
216    from _ctypes import set_conversion_mode
217except ImportError:
218    pass
219else:
220    if _os.name in ("nt", "ce"):
221        set_conversion_mode("mbcs", "ignore")
222    else:
223        set_conversion_mode("ascii", "strict")
224
225    class c_wchar_p(_SimpleCData):
226        _type_ = "Z"
227
228    class c_wchar(_SimpleCData):
229        _type_ = "u"
230
231    POINTER(c_wchar).from_param = c_wchar_p.from_param #_SimpleCData.c_wchar_p_from_param
232
233    def create_unicode_buffer(init, size=None):
234        """create_unicode_buffer(aString) -> character array
235        create_unicode_buffer(anInteger) -> character array
236        create_unicode_buffer(aString, anInteger) -> character array
237        """
238        if isinstance(init, (str, unicode)):
239            if size is None:
240                size = len(init) + 1
241            buftype = c_wchar * size
242            buf = buftype()
243            buf.value = init
244            return buf
245        elif isinstance(init, (int, long)):
246            buftype = c_wchar * init
247            buf = buftype()
248            return buf
249        raise TypeError, init
250
251POINTER(c_char).from_param = c_char_p.from_param #_SimpleCData.c_char_p_from_param
252
253# XXX Deprecated
254def SetPointerType(pointer, cls):
255    if _pointer_type_cache.get(cls, None) is not None:
256        raise RuntimeError, \
257              "This type already exists in the cache"
258    if not _pointer_type_cache.has_key(id(pointer)):
259        raise RuntimeError, \
260              "What's this???"
261    pointer.set_type(cls)
262    _pointer_type_cache[cls] = pointer
263    del _pointer_type_cache[id(pointer)]
264
265
266def pointer(inst):
267    return POINTER(type(inst))(inst)
268
269# XXX Deprecated
270def ARRAY(typ, len):
271    return typ * len
272
273################################################################
274
275
276class CDLL(object):
277    """An instance of this class represents a loaded dll/shared
278    library, exporting functions using the standard C calling
279    convention (named 'cdecl' on Windows).
280
281    The exported functions can be accessed as attributes, or by
282    indexing with the function name.  Examples:
283
284    <obj>.qsort -> callable object
285    <obj>['qsort'] -> callable object
286
287    Calling the functions releases the Python GIL during the call and
288    reaquires it afterwards.
289    """
290    class _FuncPtr(_CFuncPtr):
291        _flags_ = _FUNCFLAG_CDECL
292        _restype_ = c_int # default, can be overridden in instances
293
294    def __init__(self, name, mode=RTLD_LOCAL, handle=None):
295        self._name = name
296        if handle is None:
297            self._handle = _dlopen(self._name, mode)
298        else:
299            self._handle = handle
300
301    def __repr__(self):
302        return "<%s '%s', handle %x at %x>" % \
303               (self.__class__.__name__, self._name,
304                (self._handle & (_sys.maxint * 2 + 1)),
305                id(self))
306
307    def __getattr__(self, name):
308        if name.startswith('__') and name.endswith('__'):
309            raise AttributeError, name
310        return self.__getitem__(name)
311
312    def __getitem__(self, name_or_ordinal):
313        func = self._FuncPtr((name_or_ordinal, self))
314        if not isinstance(name_or_ordinal, (int, long)):
315            func.__name__ = name_or_ordinal
316            setattr(self, name_or_ordinal, func)
317        return func
318
319class PyDLL(CDLL):
320    """This class represents the Python library itself.  It allows to
321    access Python API functions.  The GIL is not released, and
322    Python exceptions are handled correctly.
323    """
324    class _FuncPtr(_CFuncPtr):
325        _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
326        _restype_ = c_int # default, can be overridden in instances
327
328if _os.name in ("nt", "ce"):
329
330    class WinDLL(CDLL):
331        """This class represents a dll exporting functions using the
332        Windows stdcall calling convention.
333        """
334        class _FuncPtr(_CFuncPtr):
335            _flags_ = _FUNCFLAG_STDCALL
336            _restype_ = c_int # default, can be overridden in instances
337
338    # XXX Hm, what about HRESULT as normal parameter?
339    # Mustn't it derive from c_long then?
340    from _ctypes import _check_HRESULT, _SimpleCData
341    class HRESULT(_SimpleCData):
342        _type_ = "l"
343        # _check_retval_ is called with the function's result when it
344        # is used as restype.  It checks for the FAILED bit, and
345        # raises a WindowsError if it is set.
346        #
347        # The _check_retval_ method is implemented in C, so that the
348        # method definition itself is not included in the traceback
349        # when it raises an error - that is what we want (and Python
350        # doesn't have a way to raise an exception in the caller's
351        # frame).
352        _check_retval_ = _check_HRESULT
353
354    class OleDLL(CDLL):
355        """This class represents a dll exporting functions using the
356        Windows stdcall calling convention, and returning HRESULT.
357        HRESULT error values are automatically raised as WindowsError
358        exceptions.
359        """
360        class _FuncPtr(_CFuncPtr):
361            _flags_ = _FUNCFLAG_STDCALL
362            _restype_ = HRESULT
363
364class LibraryLoader(object):
365    def __init__(self, dlltype):
366        self._dlltype = dlltype
367
368    def __getattr__(self, name):
369        if name[0] == '_':
370            raise AttributeError(name)
371        dll = self._dlltype(name)
372        setattr(self, name, dll)
373        return dll
374
375    def __getitem__(self, name):
376        return getattr(self, name)
377
378    def LoadLibrary(self, name):
379        return self._dlltype(name)
380
381cdll = LibraryLoader(CDLL)
382pydll = LibraryLoader(PyDLL)
383
384if _os.name in ("nt", "ce"):
385    pythonapi = PyDLL("python dll", None, _sys.dllhandle)
386elif _sys.platform == "cygwin":
387    pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
388else:
389    pythonapi = PyDLL(None)
390
391
392if _os.name in ("nt", "ce"):
393    windll = LibraryLoader(WinDLL)
394    oledll = LibraryLoader(OleDLL)
395
396    if _os.name == "nt":
397        GetLastError = windll.kernel32.GetLastError
398    else:
399        GetLastError = windll.coredll.GetLastError
400
401    def WinError(code=None, descr=None):
402        if code is None:
403            code = GetLastError()
404        if descr is None:
405            descr = FormatError(code).strip()
406        return WindowsError(code, descr)
407
408_pointer_type_cache[None] = c_void_p
409
410if sizeof(c_uint) == sizeof(c_void_p):
411    c_size_t = c_uint
412elif sizeof(c_ulong) == sizeof(c_void_p):
413    c_size_t = c_ulong
414
415# functions
416
417from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
418
419## void *memmove(void *, const void *, size_t);
420memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
421
422## void *memset(void *, int, size_t)
423memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
424
425def PYFUNCTYPE(restype, *argtypes):
426    class CFunctionType(_CFuncPtr):
427        _argtypes_ = argtypes
428        _restype_ = restype
429        _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
430    return CFunctionType
431_cast = PYFUNCTYPE(py_object, c_void_p, py_object)(_cast_addr)
432
433def cast(obj, typ):
434    result = _cast(obj, typ)
435    result.__keepref = obj
436    return result
437
438_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
439def string_at(ptr, size=0):
440    """string_at(addr[, size]) -> string
441
442    Return the string at addr."""
443    return _string_at(ptr, size)
444
445try:
446    from _ctypes import _wstring_at_addr
447except ImportError:
448    pass
449else:
450    _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
451    def wstring_at(ptr, size=0):
452        """wstring_at(addr[, size]) -> string
453
454        Return the string at addr."""
455        return _wstring_at(ptr, size)
456
457
458if _os.name == "nt": # COM stuff
459    def DllGetClassObject(rclsid, riid, ppv):
460        # First ask ctypes.com.server than comtypes.server for the
461        # class object.
462
463        # trick py2exe by doing dynamic imports
464        result = -2147221231 # CLASS_E_CLASSNOTAVAILABLE
465        try:
466            ctcom = __import__("ctypes.com.server", globals(), locals(), ['*'])
467        except ImportError:
468            pass
469        else:
470            result = ctcom.DllGetClassObject(rclsid, riid, ppv)
471
472        if result == -2147221231: # CLASS_E_CLASSNOTAVAILABLE
473            try:
474                ccom = __import__("comtypes.server", globals(), locals(), ['*'])
475            except ImportError:
476                pass
477            else:
478                result = ccom.DllGetClassObject(rclsid, riid, ppv)
479
480        return result
481
482    def DllCanUnloadNow():
483        # First ask ctypes.com.server than comtypes.server if we can unload or not.
484        # trick py2exe by doing dynamic imports
485        result = 0 # S_OK
486        try:
487            ctcom = __import__("ctypes.com.server", globals(), locals(), ['*'])
488        except ImportError:
489            pass
490        else:
491            result = ctcom.DllCanUnloadNow()
492            if result != 0: # != S_OK
493                return result
494
495        try:
496            ccom = __import__("comtypes.server", globals(), locals(), ['*'])
497        except ImportError:
498            return result
499        try:
500            return ccom.DllCanUnloadNow()
501        except AttributeError:
502            pass
503        return result
504
505from ctypes._endian import BigEndianStructure, LittleEndianStructure
506
507# Fill in specifically-sized types
508c_int8 = c_byte
509c_uint8 = c_ubyte
510for kind in [c_short, c_int, c_long, c_longlong]:
511    if sizeof(kind) == 2: c_int16 = kind
512    elif sizeof(kind) == 4: c_int32 = kind
513    elif sizeof(kind) == 8: c_int64 = kind
514for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
515    if sizeof(kind) == 2: c_uint16 = kind
516    elif sizeof(kind) == 4: c_uint32 = kind
517    elif sizeof(kind) == 8: c_uint64 = kind
518del(kind)
519