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