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