blob: f2ddbaacd92a05fd8baf5a9533e21a2fce4cb263 [file] [log] [blame]
Thomas Hellerbabddfc2006-03-08 19:56:54 +00001"""create and manipulate C data types in Python"""
2
Thomas Hellerbabddfc2006-03-08 19:56:54 +00003import os as _os, sys as _sys
4from itertools import chain as _chain
5
Thomas Wouters477c8d52006-05-27 19:21:47 +00006__version__ = "0.9.9.6"
Thomas Hellerbabddfc2006-03-08 19:56:54 +00007
8from _ctypes import Union, Structure, Array
9from _ctypes import _Pointer
10from _ctypes import CFuncPtr as _CFuncPtr
11from _ctypes import __version__ as _ctypes_version
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000012from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
Thomas Hellerbabddfc2006-03-08 19:56:54 +000013from _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 in ("nt", "ce"):
21 from _ctypes import FormatError
22
23from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
24 FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI
25
Thomas Hellerbabddfc2006-03-08 19:56:54 +000026"""
27WINOLEAPI -> HRESULT
28WINOLEAPI_(type)
29
30STDMETHODCALLTYPE
31
32STDMETHOD(name)
33STDMETHOD_(type, name)
34
35STDAPICALLTYPE
36"""
37
38def create_string_buffer(init, size=None):
39 """create_string_buffer(aString) -> character array
40 create_string_buffer(anInteger) -> character array
41 create_string_buffer(aString, anInteger) -> character array
42 """
43 if isinstance(init, (str, unicode)):
44 if size is None:
45 size = len(init)+1
46 buftype = c_char * size
47 buf = buftype()
48 buf.value = init
49 return buf
50 elif isinstance(init, (int, long)):
51 buftype = c_char * init
52 buf = buftype()
53 return buf
54 raise TypeError, init
55
56def c_buffer(init, size=None):
57## "deprecated, use create_string_buffer instead"
58## import warnings
59## warnings.warn("c_buffer is deprecated, use create_string_buffer instead",
60## DeprecationWarning, stacklevel=2)
61 return create_string_buffer(init, size)
62
63_c_functype_cache = {}
64def CFUNCTYPE(restype, *argtypes):
65 """CFUNCTYPE(restype, *argtypes) -> function prototype.
Tim Peterse8d09e52006-03-09 01:15:05 +000066
Thomas Hellerbabddfc2006-03-08 19:56:54 +000067 restype: the result type
68 argtypes: a sequence specifying the argument types
Tim Peterse8d09e52006-03-09 01:15:05 +000069
Thomas Hellerbabddfc2006-03-08 19:56:54 +000070 The function prototype can be called in three ways to create a
71 callable object:
Tim Peterse8d09e52006-03-09 01:15:05 +000072
Thomas Wouters477c8d52006-05-27 19:21:47 +000073 prototype(integer address) -> foreign function
74 prototype(callable) -> create and return a C callable function from callable
75 prototype(integer index, method name[, paramflags]) -> foreign function calling a COM method
76 prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
77 prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
Thomas Hellerbabddfc2006-03-08 19:56:54 +000078 """
79 try:
80 return _c_functype_cache[(restype, argtypes)]
81 except KeyError:
82 class CFunctionType(_CFuncPtr):
83 _argtypes_ = argtypes
84 _restype_ = restype
85 _flags_ = _FUNCFLAG_CDECL
86 _c_functype_cache[(restype, argtypes)] = CFunctionType
87 return CFunctionType
88
89if _os.name in ("nt", "ce"):
90 from _ctypes import LoadLibrary as _dlopen
91 from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
92 if _os.name == "ce":
93 # 'ce' doesn't have the stdcall calling convention
94 _FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
95
96 _win_functype_cache = {}
97 def WINFUNCTYPE(restype, *argtypes):
98 # docstring set later (very similar to CFUNCTYPE.__doc__)
99 try:
100 return _win_functype_cache[(restype, argtypes)]
101 except KeyError:
102 class WinFunctionType(_CFuncPtr):
103 _argtypes_ = argtypes
104 _restype_ = restype
105 _flags_ = _FUNCFLAG_STDCALL
106 _win_functype_cache[(restype, argtypes)] = WinFunctionType
107 return WinFunctionType
108 if WINFUNCTYPE.__doc__:
109 WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
110
111elif _os.name == "posix":
112 from _ctypes import dlopen as _dlopen
113
114from _ctypes import sizeof, byref, addressof, alignment
115from _ctypes import _SimpleCData
116
117class py_object(_SimpleCData):
118 _type_ = "O"
119
120class c_short(_SimpleCData):
121 _type_ = "h"
122
123class c_ushort(_SimpleCData):
124 _type_ = "H"
125
126class c_long(_SimpleCData):
127 _type_ = "l"
128
129class c_ulong(_SimpleCData):
130 _type_ = "L"
Tim Peterse8d09e52006-03-09 01:15:05 +0000131
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000132if _calcsize("i") == _calcsize("l"):
133 # if int and long have the same size, make c_int an alias for c_long
134 c_int = c_long
135 c_uint = c_ulong
136else:
137 class c_int(_SimpleCData):
138 _type_ = "i"
139
140 class c_uint(_SimpleCData):
141 _type_ = "I"
142
143class c_float(_SimpleCData):
144 _type_ = "f"
Tim Peterse8d09e52006-03-09 01:15:05 +0000145
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000146class c_double(_SimpleCData):
147 _type_ = "d"
148
149if _calcsize("l") == _calcsize("q"):
150 # if long and long long have the same size, make c_longlong an alias for c_long
151 c_longlong = c_long
152 c_ulonglong = c_ulong
153else:
154 class c_longlong(_SimpleCData):
155 _type_ = "q"
156
157 class c_ulonglong(_SimpleCData):
158 _type_ = "Q"
159 ## def from_param(cls, val):
160 ## return ('d', float(val), val)
161 ## from_param = classmethod(from_param)
162
163class c_ubyte(_SimpleCData):
164 _type_ = "B"
165c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte
166# backward compatibility:
167##c_uchar = c_ubyte
168
169class c_byte(_SimpleCData):
170 _type_ = "b"
171c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte
172
173class c_char(_SimpleCData):
174 _type_ = "c"
175c_char.__ctype_le__ = c_char.__ctype_be__ = c_char
176
177class c_char_p(_SimpleCData):
178 _type_ = "z"
179
180class c_void_p(_SimpleCData):
181 _type_ = "P"
182c_voidp = c_void_p # backwards compatibility (to a bug)
183
184# This cache maps types to pointers to them.
185_pointer_type_cache = {}
186
187def POINTER(cls):
188 try:
189 return _pointer_type_cache[cls]
190 except KeyError:
191 pass
192 if type(cls) is str:
193 klass = type(_Pointer)("LP_%s" % cls,
194 (_Pointer,),
195 {})
196 _pointer_type_cache[id(klass)] = klass
197 return klass
198 else:
199 name = "LP_%s" % cls.__name__
200 klass = type(_Pointer)(name,
201 (_Pointer,),
202 {'_type_': cls})
203 _pointer_type_cache[cls] = klass
204 return klass
205
206try:
207 from _ctypes import set_conversion_mode
208except ImportError:
209 pass
210else:
211 if _os.name in ("nt", "ce"):
212 set_conversion_mode("mbcs", "ignore")
213 else:
214 set_conversion_mode("ascii", "strict")
215
216 class c_wchar_p(_SimpleCData):
217 _type_ = "Z"
218
219 class c_wchar(_SimpleCData):
220 _type_ = "u"
221
222 POINTER(c_wchar).from_param = c_wchar_p.from_param #_SimpleCData.c_wchar_p_from_param
223
224 def create_unicode_buffer(init, size=None):
225 """create_unicode_buffer(aString) -> character array
226 create_unicode_buffer(anInteger) -> character array
227 create_unicode_buffer(aString, anInteger) -> character array
228 """
229 if isinstance(init, (str, unicode)):
230 if size is None:
231 size = len(init)+1
232 buftype = c_wchar * size
233 buf = buftype()
234 buf.value = init
235 return buf
236 elif isinstance(init, (int, long)):
237 buftype = c_wchar * init
238 buf = buftype()
239 return buf
240 raise TypeError, init
241
242POINTER(c_char).from_param = c_char_p.from_param #_SimpleCData.c_char_p_from_param
243
244# XXX Deprecated
245def SetPointerType(pointer, cls):
246 if _pointer_type_cache.get(cls, None) is not None:
247 raise RuntimeError, \
248 "This type already exists in the cache"
249 if not _pointer_type_cache.has_key(id(pointer)):
250 raise RuntimeError, \
251 "What's this???"
252 pointer.set_type(cls)
253 _pointer_type_cache[cls] = pointer
254 del _pointer_type_cache[id(pointer)]
255
256
257def pointer(inst):
258 return POINTER(type(inst))(inst)
259
260# XXX Deprecated
261def ARRAY(typ, len):
262 return typ * len
263
264################################################################
265
266
267class CDLL(object):
268 """An instance of this class represents a loaded dll/shared
269 library, exporting functions using the standard C calling
270 convention (named 'cdecl' on Windows).
271
272 The exported functions can be accessed as attributes, or by
273 indexing with the function name. Examples:
274
275 <obj>.qsort -> callable object
276 <obj>['qsort'] -> callable object
277
278 Calling the functions releases the Python GIL during the call and
279 reaquires it afterwards.
280 """
281 class _FuncPtr(_CFuncPtr):
282 _flags_ = _FUNCFLAG_CDECL
283 _restype_ = c_int # default, can be overridden in instances
284
285 def __init__(self, name, mode=RTLD_LOCAL, handle=None):
286 self._name = name
287 if handle is None:
288 self._handle = _dlopen(self._name, mode)
289 else:
290 self._handle = handle
291
292 def __repr__(self):
293 return "<%s '%s', handle %x at %x>" % \
294 (self.__class__.__name__, self._name,
295 (self._handle & (_sys.maxint*2 + 1)),
296 id(self))
297
298 def __getattr__(self, name):
299 if name.startswith('__') and name.endswith('__'):
300 raise AttributeError, name
301 return self.__getitem__(name)
302
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000303 def __getitem__(self, name_or_ordinal):
304 func = self._FuncPtr((name_or_ordinal, self))
305 if not isinstance(name_or_ordinal, (int, long)):
306 func.__name__ = name_or_ordinal
307 setattr(self, name_or_ordinal, func)
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000308 return func
309
310class PyDLL(CDLL):
311 """This class represents the Python library itself. It allows to
312 access Python API functions. The GIL is not released, and
313 Python exceptions are handled correctly.
314 """
315 class _FuncPtr(_CFuncPtr):
316 _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
317 _restype_ = c_int # default, can be overridden in instances
318
319if _os.name in ("nt", "ce"):
Tim Peterse8d09e52006-03-09 01:15:05 +0000320
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000321 class WinDLL(CDLL):
322 """This class represents a dll exporting functions using the
323 Windows stdcall calling convention.
324 """
325 class _FuncPtr(_CFuncPtr):
326 _flags_ = _FUNCFLAG_STDCALL
327 _restype_ = c_int # default, can be overridden in instances
328
329 # XXX Hm, what about HRESULT as normal parameter?
330 # Mustn't it derive from c_long then?
331 from _ctypes import _check_HRESULT, _SimpleCData
332 class HRESULT(_SimpleCData):
333 _type_ = "l"
334 # _check_retval_ is called with the function's result when it
335 # is used as restype. It checks for the FAILED bit, and
336 # raises a WindowsError if it is set.
337 #
338 # The _check_retval_ method is implemented in C, so that the
339 # method definition itself is not included in the traceback
340 # when it raises an error - that is what we want (and Python
341 # doesn't have a way to raise an exception in the caller's
342 # frame).
343 _check_retval_ = _check_HRESULT
Tim Peterse8d09e52006-03-09 01:15:05 +0000344
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000345 class OleDLL(CDLL):
346 """This class represents a dll exporting functions using the
347 Windows stdcall calling convention, and returning HRESULT.
348 HRESULT error values are automatically raised as WindowsError
349 exceptions.
350 """
351 class _FuncPtr(_CFuncPtr):
352 _flags_ = _FUNCFLAG_STDCALL
353 _restype_ = HRESULT
354
Thomas Wouters477c8d52006-05-27 19:21:47 +0000355class LibraryLoader(object):
356 def __init__(self, dlltype):
357 self._dlltype = dlltype
358
359 def __getattr__(self, name):
360 if name[0] == '_':
361 raise AttributeError(name)
362 dll = self._dlltype(name)
363 setattr(self, name, dll)
364 return dll
365
366 def __getitem__(self, name):
367 return getattr(self, name)
368
369 def LoadLibrary(self, name):
370 return self._dlltype(name)
371
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000372cdll = LibraryLoader(CDLL)
373pydll = LibraryLoader(PyDLL)
374
375if _os.name in ("nt", "ce"):
376 pythonapi = PyDLL("python dll", None, _sys.dllhandle)
377elif _sys.platform == "cygwin":
378 pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
379else:
380 pythonapi = PyDLL(None)
381
382
383if _os.name in ("nt", "ce"):
384 windll = LibraryLoader(WinDLL)
385 oledll = LibraryLoader(OleDLL)
386
387 if _os.name == "nt":
388 GetLastError = windll.kernel32.GetLastError
389 else:
390 GetLastError = windll.coredll.GetLastError
391
392 def WinError(code=None, descr=None):
393 if code is None:
394 code = GetLastError()
395 if descr is None:
396 descr = FormatError(code).strip()
397 return WindowsError(code, descr)
398
399_pointer_type_cache[None] = c_void_p
400
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000401if sizeof(c_uint) == sizeof(c_void_p):
402 c_size_t = c_uint
403elif sizeof(c_ulong) == sizeof(c_void_p):
404 c_size_t = c_ulong
405
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000406# functions
407
408from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
409
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000410## void *memmove(void *, const void *, size_t);
411memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
412
413## void *memset(void *, int, size_t)
414memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
415
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000416def PYFUNCTYPE(restype, *argtypes):
417 class CFunctionType(_CFuncPtr):
418 _argtypes_ = argtypes
419 _restype_ = restype
420 _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
421 return CFunctionType
Thomas Wouters477c8d52006-05-27 19:21:47 +0000422_cast = PYFUNCTYPE(py_object, c_void_p, py_object)(_cast_addr)
423
424def cast(obj, typ):
425 result = _cast(obj, typ)
426 result.__keepref = obj
427 return result
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000428
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000429_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
430def string_at(ptr, size=0):
431 """string_at(addr[, size]) -> string
432
433 Return the string at addr."""
434 return _string_at(ptr, size)
435
436try:
437 from _ctypes import _wstring_at_addr
438except ImportError:
439 pass
440else:
441 _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
442 def wstring_at(ptr, size=0):
443 """wstring_at(addr[, size]) -> string
444
445 Return the string at addr."""
446 return _wstring_at(ptr, size)
Tim Peterse8d09e52006-03-09 01:15:05 +0000447
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000448
449if _os.name == "nt": # COM stuff
450 def DllGetClassObject(rclsid, riid, ppv):
451 # First ask ctypes.com.server than comtypes.server for the
452 # class object.
453
454 # trick py2exe by doing dynamic imports
455 result = -2147221231 # CLASS_E_CLASSNOTAVAILABLE
456 try:
457 ctcom = __import__("ctypes.com.server", globals(), locals(), ['*'])
458 except ImportError:
459 pass
460 else:
461 result = ctcom.DllGetClassObject(rclsid, riid, ppv)
462
463 if result == -2147221231: # CLASS_E_CLASSNOTAVAILABLE
464 try:
465 ccom = __import__("comtypes.server", globals(), locals(), ['*'])
466 except ImportError:
467 pass
468 else:
469 result = ccom.DllGetClassObject(rclsid, riid, ppv)
470
471 return result
472
473 def DllCanUnloadNow():
474 # First ask ctypes.com.server than comtypes.server if we can unload or not.
475 # trick py2exe by doing dynamic imports
476 result = 0 # S_OK
477 try:
478 ctcom = __import__("ctypes.com.server", globals(), locals(), ['*'])
479 except ImportError:
480 pass
481 else:
482 result = ctcom.DllCanUnloadNow()
483 if result != 0: # != S_OK
484 return result
485
486 try:
487 ccom = __import__("comtypes.server", globals(), locals(), ['*'])
488 except ImportError:
489 return result
490 try:
491 return ccom.DllCanUnloadNow()
492 except AttributeError:
493 pass
494 return result
495
496from ctypes._endian import BigEndianStructure, LittleEndianStructure
497
498# Fill in specifically-sized types
499c_int8 = c_byte
500c_uint8 = c_ubyte
501for kind in [c_short, c_int, c_long, c_longlong]:
502 if sizeof(kind) == 2: c_int16 = kind
503 elif sizeof(kind) == 4: c_int32 = kind
504 elif sizeof(kind) == 8: c_int64 = kind
505for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
506 if sizeof(kind) == 2: c_uint16 = kind
507 elif sizeof(kind) == 4: c_uint32 = kind
508 elif sizeof(kind) == 8: c_uint64 = kind
509del(kind)