1"""create and manipulate C data types in Python""" 2 3import os as _os, sys as _sys 4import types as _types 5 6__version__ = "1.1.0" 7 8from _ctypes import Union, Structure, Array 9from _ctypes import _Pointer 10from _ctypes import CFuncPtr as _CFuncPtr 11from _ctypes import __version__ as _ctypes_version 12from _ctypes import RTLD_LOCAL, RTLD_GLOBAL 13from _ctypes import ArgumentError 14 15from struct import calcsize as _calcsize 16 17if __version__ != _ctypes_version: 18 raise Exception("Version number mismatch", __version__, _ctypes_version) 19 20if _os.name == "nt": 21 from _ctypes import FormatError 22 23DEFAULT_MODE = RTLD_LOCAL 24if _os.name == "posix" and _sys.platform == "darwin": 25 # On OS X 10.3, we use RTLD_GLOBAL as default mode 26 # because RTLD_LOCAL does not work at least on some 27 # libraries. OS X 10.3 is Darwin 7, so we check for 28 # that. 29 30 if int(_os.uname().release.split('.')[0]) < 8: 31 DEFAULT_MODE = RTLD_GLOBAL 32 33from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \ 34 FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \ 35 FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \ 36 FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR 37 38# WINOLEAPI -> HRESULT 39# WINOLEAPI_(type) 40# 41# STDMETHODCALLTYPE 42# 43# STDMETHOD(name) 44# STDMETHOD_(type, name) 45# 46# STDAPICALLTYPE 47 48def create_string_buffer(init, size=None): 49 """create_string_buffer(aBytes) -> character array 50 create_string_buffer(anInteger) -> character array 51 create_string_buffer(aBytes, anInteger) -> character array 52 """ 53 if isinstance(init, bytes): 54 if size is None: 55 size = len(init)+1 56 _sys.audit("ctypes.create_string_buffer", init, size) 57 buftype = c_char * size 58 buf = buftype() 59 buf.value = init 60 return buf 61 elif isinstance(init, int): 62 _sys.audit("ctypes.create_string_buffer", None, init) 63 buftype = c_char * init 64 buf = buftype() 65 return buf 66 raise TypeError(init) 67 68# Alias to create_string_buffer() for backward compatibility 69c_buffer = create_string_buffer 70 71_c_functype_cache = {} 72def CFUNCTYPE(restype, *argtypes, **kw): 73 """CFUNCTYPE(restype, *argtypes, 74 use_errno=False, use_last_error=False) -> 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 different 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 flags = _FUNCFLAG_CDECL 89 if kw.pop("use_errno", False): 90 flags |= _FUNCFLAG_USE_ERRNO 91 if kw.pop("use_last_error", False): 92 flags |= _FUNCFLAG_USE_LASTERROR 93 if kw: 94 raise ValueError("unexpected keyword argument(s) %s" % kw.keys()) 95 96 try: 97 return _c_functype_cache[(restype, argtypes, flags)] 98 except KeyError: 99 pass 100 101 class CFunctionType(_CFuncPtr): 102 _argtypes_ = argtypes 103 _restype_ = restype 104 _flags_ = flags 105 _c_functype_cache[(restype, argtypes, flags)] = CFunctionType 106 return CFunctionType 107 108if _os.name == "nt": 109 from _ctypes import LoadLibrary as _dlopen 110 from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL 111 112 _win_functype_cache = {} 113 def WINFUNCTYPE(restype, *argtypes, **kw): 114 # docstring set later (very similar to CFUNCTYPE.__doc__) 115 flags = _FUNCFLAG_STDCALL 116 if kw.pop("use_errno", False): 117 flags |= _FUNCFLAG_USE_ERRNO 118 if kw.pop("use_last_error", False): 119 flags |= _FUNCFLAG_USE_LASTERROR 120 if kw: 121 raise ValueError("unexpected keyword argument(s) %s" % kw.keys()) 122 123 try: 124 return _win_functype_cache[(restype, argtypes, flags)] 125 except KeyError: 126 pass 127 128 class WinFunctionType(_CFuncPtr): 129 _argtypes_ = argtypes 130 _restype_ = restype 131 _flags_ = flags 132 _win_functype_cache[(restype, argtypes, flags)] = WinFunctionType 133 return WinFunctionType 134 if WINFUNCTYPE.__doc__: 135 WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE") 136 137elif _os.name == "posix": 138 from _ctypes import dlopen as _dlopen 139 140from _ctypes import sizeof, byref, addressof, alignment, resize 141from _ctypes import get_errno, set_errno 142from _ctypes import _SimpleCData 143 144def _check_size(typ, typecode=None): 145 # Check if sizeof(ctypes_type) against struct.calcsize. This 146 # should protect somewhat against a misconfigured libffi. 147 from struct import calcsize 148 if typecode is None: 149 # Most _type_ codes are the same as used in struct 150 typecode = typ._type_ 151 actual, required = sizeof(typ), calcsize(typecode) 152 if actual != required: 153 raise SystemError("sizeof(%s) wrong: %d instead of %d" % \ 154 (typ, actual, required)) 155 156class py_object(_SimpleCData): 157 _type_ = "O" 158 def __repr__(self): 159 try: 160 return super().__repr__() 161 except ValueError: 162 return "%s(<NULL>)" % type(self).__name__ 163_check_size(py_object, "P") 164 165class c_short(_SimpleCData): 166 _type_ = "h" 167_check_size(c_short) 168 169class c_ushort(_SimpleCData): 170 _type_ = "H" 171_check_size(c_ushort) 172 173class c_long(_SimpleCData): 174 _type_ = "l" 175_check_size(c_long) 176 177class c_ulong(_SimpleCData): 178 _type_ = "L" 179_check_size(c_ulong) 180 181if _calcsize("i") == _calcsize("l"): 182 # if int and long have the same size, make c_int an alias for c_long 183 c_int = c_long 184 c_uint = c_ulong 185else: 186 class c_int(_SimpleCData): 187 _type_ = "i" 188 _check_size(c_int) 189 190 class c_uint(_SimpleCData): 191 _type_ = "I" 192 _check_size(c_uint) 193 194class c_float(_SimpleCData): 195 _type_ = "f" 196_check_size(c_float) 197 198class c_double(_SimpleCData): 199 _type_ = "d" 200_check_size(c_double) 201 202class c_longdouble(_SimpleCData): 203 _type_ = "g" 204if sizeof(c_longdouble) == sizeof(c_double): 205 c_longdouble = c_double 206 207if _calcsize("l") == _calcsize("q"): 208 # if long and long long have the same size, make c_longlong an alias for c_long 209 c_longlong = c_long 210 c_ulonglong = c_ulong 211else: 212 class c_longlong(_SimpleCData): 213 _type_ = "q" 214 _check_size(c_longlong) 215 216 class c_ulonglong(_SimpleCData): 217 _type_ = "Q" 218 ## def from_param(cls, val): 219 ## return ('d', float(val), val) 220 ## from_param = classmethod(from_param) 221 _check_size(c_ulonglong) 222 223class c_ubyte(_SimpleCData): 224 _type_ = "B" 225c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte 226# backward compatibility: 227##c_uchar = c_ubyte 228_check_size(c_ubyte) 229 230class c_byte(_SimpleCData): 231 _type_ = "b" 232c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte 233_check_size(c_byte) 234 235class c_char(_SimpleCData): 236 _type_ = "c" 237c_char.__ctype_le__ = c_char.__ctype_be__ = c_char 238_check_size(c_char) 239 240class c_char_p(_SimpleCData): 241 _type_ = "z" 242 def __repr__(self): 243 return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value) 244_check_size(c_char_p, "P") 245 246class c_void_p(_SimpleCData): 247 _type_ = "P" 248c_voidp = c_void_p # backwards compatibility (to a bug) 249_check_size(c_void_p) 250 251class c_bool(_SimpleCData): 252 _type_ = "?" 253 254from _ctypes import POINTER, pointer, _pointer_type_cache 255 256class c_wchar_p(_SimpleCData): 257 _type_ = "Z" 258 def __repr__(self): 259 return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value) 260 261class c_wchar(_SimpleCData): 262 _type_ = "u" 263 264def _reset_cache(): 265 _pointer_type_cache.clear() 266 _c_functype_cache.clear() 267 if _os.name == "nt": 268 _win_functype_cache.clear() 269 # _SimpleCData.c_wchar_p_from_param 270 POINTER(c_wchar).from_param = c_wchar_p.from_param 271 # _SimpleCData.c_char_p_from_param 272 POINTER(c_char).from_param = c_char_p.from_param 273 _pointer_type_cache[None] = c_void_p 274 275def create_unicode_buffer(init, size=None): 276 """create_unicode_buffer(aString) -> character array 277 create_unicode_buffer(anInteger) -> character array 278 create_unicode_buffer(aString, anInteger) -> character array 279 """ 280 if isinstance(init, str): 281 if size is None: 282 if sizeof(c_wchar) == 2: 283 # UTF-16 requires a surrogate pair (2 wchar_t) for non-BMP 284 # characters (outside [U+0000; U+FFFF] range). +1 for trailing 285 # NUL character. 286 size = sum(2 if ord(c) > 0xFFFF else 1 for c in init) + 1 287 else: 288 # 32-bit wchar_t (1 wchar_t per Unicode character). +1 for 289 # trailing NUL character. 290 size = len(init) + 1 291 _sys.audit("ctypes.create_unicode_buffer", init, size) 292 buftype = c_wchar * size 293 buf = buftype() 294 buf.value = init 295 return buf 296 elif isinstance(init, int): 297 _sys.audit("ctypes.create_unicode_buffer", None, init) 298 buftype = c_wchar * init 299 buf = buftype() 300 return buf 301 raise TypeError(init) 302 303 304# XXX Deprecated 305def SetPointerType(pointer, cls): 306 if _pointer_type_cache.get(cls, None) is not None: 307 raise RuntimeError("This type already exists in the cache") 308 if id(pointer) not in _pointer_type_cache: 309 raise RuntimeError("What's this???") 310 pointer.set_type(cls) 311 _pointer_type_cache[cls] = pointer 312 del _pointer_type_cache[id(pointer)] 313 314# XXX Deprecated 315def ARRAY(typ, len): 316 return typ * len 317 318################################################################ 319 320 321class CDLL(object): 322 """An instance of this class represents a loaded dll/shared 323 library, exporting functions using the standard C calling 324 convention (named 'cdecl' on Windows). 325 326 The exported functions can be accessed as attributes, or by 327 indexing with the function name. Examples: 328 329 <obj>.qsort -> callable object 330 <obj>['qsort'] -> callable object 331 332 Calling the functions releases the Python GIL during the call and 333 reacquires it afterwards. 334 """ 335 _func_flags_ = _FUNCFLAG_CDECL 336 _func_restype_ = c_int 337 # default values for repr 338 _name = '<uninitialized>' 339 _handle = 0 340 _FuncPtr = None 341 342 def __init__(self, name, mode=DEFAULT_MODE, handle=None, 343 use_errno=False, 344 use_last_error=False, 345 winmode=None): 346 self._name = name 347 flags = self._func_flags_ 348 if use_errno: 349 flags |= _FUNCFLAG_USE_ERRNO 350 if use_last_error: 351 flags |= _FUNCFLAG_USE_LASTERROR 352 if _sys.platform.startswith("aix"): 353 """When the name contains ".a(" and ends with ")", 354 e.g., "libFOO.a(libFOO.so)" - this is taken to be an 355 archive(member) syntax for dlopen(), and the mode is adjusted. 356 Otherwise, name is presented to dlopen() as a file argument. 357 """ 358 if name and name.endswith(")") and ".a(" in name: 359 mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW ) 360 if _os.name == "nt": 361 if winmode is not None: 362 mode = winmode 363 else: 364 import nt 365 mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 366 if '/' in name or '\\' in name: 367 self._name = nt._getfullpathname(self._name) 368 mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 369 370 class _FuncPtr(_CFuncPtr): 371 _flags_ = flags 372 _restype_ = self._func_restype_ 373 self._FuncPtr = _FuncPtr 374 375 if handle is None: 376 self._handle = _dlopen(self._name, mode) 377 else: 378 self._handle = handle 379 380 def __repr__(self): 381 return "<%s '%s', handle %x at %#x>" % \ 382 (self.__class__.__name__, self._name, 383 (self._handle & (_sys.maxsize*2 + 1)), 384 id(self) & (_sys.maxsize*2 + 1)) 385 386 def __getattr__(self, name): 387 if name.startswith('__') and name.endswith('__'): 388 raise AttributeError(name) 389 func = self.__getitem__(name) 390 setattr(self, name, func) 391 return func 392 393 def __getitem__(self, name_or_ordinal): 394 func = self._FuncPtr((name_or_ordinal, self)) 395 if not isinstance(name_or_ordinal, int): 396 func.__name__ = name_or_ordinal 397 return func 398 399class PyDLL(CDLL): 400 """This class represents the Python library itself. It allows 401 accessing Python API functions. The GIL is not released, and 402 Python exceptions are handled correctly. 403 """ 404 _func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI 405 406if _os.name == "nt": 407 408 class WinDLL(CDLL): 409 """This class represents a dll exporting functions using the 410 Windows stdcall calling convention. 411 """ 412 _func_flags_ = _FUNCFLAG_STDCALL 413 414 # XXX Hm, what about HRESULT as normal parameter? 415 # Mustn't it derive from c_long then? 416 from _ctypes import _check_HRESULT, _SimpleCData 417 class HRESULT(_SimpleCData): 418 _type_ = "l" 419 # _check_retval_ is called with the function's result when it 420 # is used as restype. It checks for the FAILED bit, and 421 # raises an OSError if it is set. 422 # 423 # The _check_retval_ method is implemented in C, so that the 424 # method definition itself is not included in the traceback 425 # when it raises an error - that is what we want (and Python 426 # doesn't have a way to raise an exception in the caller's 427 # frame). 428 _check_retval_ = _check_HRESULT 429 430 class OleDLL(CDLL): 431 """This class represents a dll exporting functions using the 432 Windows stdcall calling convention, and returning HRESULT. 433 HRESULT error values are automatically raised as OSError 434 exceptions. 435 """ 436 _func_flags_ = _FUNCFLAG_STDCALL 437 _func_restype_ = HRESULT 438 439class LibraryLoader(object): 440 def __init__(self, dlltype): 441 self._dlltype = dlltype 442 443 def __getattr__(self, name): 444 if name[0] == '_': 445 raise AttributeError(name) 446 dll = self._dlltype(name) 447 setattr(self, name, dll) 448 return dll 449 450 def __getitem__(self, name): 451 return getattr(self, name) 452 453 def LoadLibrary(self, name): 454 return self._dlltype(name) 455 456 __class_getitem__ = classmethod(_types.GenericAlias) 457 458cdll = LibraryLoader(CDLL) 459pydll = LibraryLoader(PyDLL) 460 461if _os.name == "nt": 462 pythonapi = PyDLL("python dll", None, _sys.dllhandle) 463elif _sys.platform == "cygwin": 464 pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2]) 465else: 466 pythonapi = PyDLL(None) 467 468 469if _os.name == "nt": 470 windll = LibraryLoader(WinDLL) 471 oledll = LibraryLoader(OleDLL) 472 473 GetLastError = windll.kernel32.GetLastError 474 from _ctypes import get_last_error, set_last_error 475 476 def WinError(code=None, descr=None): 477 if code is None: 478 code = GetLastError() 479 if descr is None: 480 descr = FormatError(code).strip() 481 return OSError(None, descr, None, code) 482 483if sizeof(c_uint) == sizeof(c_void_p): 484 c_size_t = c_uint 485 c_ssize_t = c_int 486elif sizeof(c_ulong) == sizeof(c_void_p): 487 c_size_t = c_ulong 488 c_ssize_t = c_long 489elif sizeof(c_ulonglong) == sizeof(c_void_p): 490 c_size_t = c_ulonglong 491 c_ssize_t = c_longlong 492 493# functions 494 495from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr 496 497## void *memmove(void *, const void *, size_t); 498memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) 499 500## void *memset(void *, int, size_t) 501memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr) 502 503def PYFUNCTYPE(restype, *argtypes): 504 class CFunctionType(_CFuncPtr): 505 _argtypes_ = argtypes 506 _restype_ = restype 507 _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI 508 return CFunctionType 509 510_cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr) 511def cast(obj, typ): 512 return _cast(obj, obj, typ) 513 514_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) 515def string_at(ptr, size=-1): 516 """string_at(addr[, size]) -> string 517 518 Return the string at addr.""" 519 return _string_at(ptr, size) 520 521try: 522 from _ctypes import _wstring_at_addr 523except ImportError: 524 pass 525else: 526 _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) 527 def wstring_at(ptr, size=-1): 528 """wstring_at(addr[, size]) -> string 529 530 Return the string at addr.""" 531 return _wstring_at(ptr, size) 532 533 534if _os.name == "nt": # COM stuff 535 def DllGetClassObject(rclsid, riid, ppv): 536 try: 537 ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*']) 538 except ImportError: 539 return -2147221231 # CLASS_E_CLASSNOTAVAILABLE 540 else: 541 return ccom.DllGetClassObject(rclsid, riid, ppv) 542 543 def DllCanUnloadNow(): 544 try: 545 ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*']) 546 except ImportError: 547 return 0 # S_OK 548 return ccom.DllCanUnloadNow() 549 550from ctypes._endian import BigEndianStructure, LittleEndianStructure 551from ctypes._endian import BigEndianUnion, LittleEndianUnion 552 553# Fill in specifically-sized types 554c_int8 = c_byte 555c_uint8 = c_ubyte 556for kind in [c_short, c_int, c_long, c_longlong]: 557 if sizeof(kind) == 2: c_int16 = kind 558 elif sizeof(kind) == 4: c_int32 = kind 559 elif sizeof(kind) == 8: c_int64 = kind 560for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]: 561 if sizeof(kind) == 2: c_uint16 = kind 562 elif sizeof(kind) == 4: c_uint32 = kind 563 elif sizeof(kind) == 8: c_uint64 = kind 564del(kind) 565 566_reset_cache() 567