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