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