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