4 kwietnia 2013

python.ctypes - wołanie funkcji (shared/dynamic libs)

ctypes, to biblioteka pytahon-a umożliwiająca wołanie funkcji z dynamicznych i współdzielonych bibliotek, dla różnych platform. Przydatne linki:
By przekazać wartości przez wskaźnik/referencję można skorzystać z metody byref(), albo pointer() (ta jest jednak wolniejsza, bo tworzy prawdziwy wskaźnik). Link.
Przykład poniżej woła funkcję sscanf() (msvcrt jest Windows-ową biblioteką zawierającą większość funkcji z biblioteki standardowej C).
from ctypes import *
i = c_int()
f = c_float()
s = create_string_buffer('\000' * 32)
ctypes.cdll.msvcrt.sscanf("1 3.14 Hello", "%d %f %s", byref(i), pointer(f), s)

print i.value, f.value, s.value
I wynik:
1 3.1400001049 Hello
Chociaż interesowało mnie jeszcze kilka zagadnień (np. tworzenie struktur, tablic), nie starczyło czasu, by zrobić sobie przykłady. W razie czego, trzeba będzie wrócić do dokumentacji. A tymczasem, postanowiłem pobawić się biblioteką dźwięku BASS. Przykład poniżej, ma za zadanie przez 3 sekundy w pętli odtwarzać zawartość adios.wav.

Jeżeli mamy do czynienia z prostymi wartościami, funkcje z biblioteki możemy wołać bezpośrednio na obiekcie (bassDll).
None, integers, longs, byte strings and unicode strings are the only native Python objects that can directly be used as parameters in these function calls
import ctypes
import time

BASSVERSION      = 0x204
BASS_SAMPLE_LOOP = 4

def HIWORD(value):
    return value >> 16

bassDll = ctypes.WinDLL ("d:\\bass.dll")
if HIWORD(bassDll.BASS_GetVersion()) != BASSVERSION:
    raise Exception("An incorrect version of BASS was loaded")

if not bassDll.BASS_Init(-1, 44100, 0, 0, None):
    raise Exception("Can't initialize device")

chan = bassDll.BASS_StreamCreateFile(False, 'd:\\adios.wav', \
                                     ctypes.c_longlong(0), ctypes.c_longlong(0), \
                                     BASS_SAMPLE_LOOP)
if not chan:
    raise Exception("Can't play the file")

bassDll.BASS_ChannelPlay(chan, False)
time.sleep(3)
bassDll.BASS_Free()
print 'Success!'
W przypadku, gdy mamy do czynienia z bardziej wyrafinowanymi funkcjami, można skorzystać z WINFUNCTYPE (to dla Windows), który stworzy prototyp funkcji. Do środka przekazujemy jako pierwszy "typ zwracany", reszta to parametry jakie pobiera już właściwa funkcja. Tworząc funkcję z prototypu, przekazujemy jako drugi argument parametry właściwego wołania (linijka 13).
Pojedynczy parametr może składać się z trzech pól:
  1. Kombinacja flag określających rodzaj parametru (1 - IN, 2 - OUT, 4 - IN będący int-em ustawionym na 0 (?))
  2. Nazwa parametru (opcjonalna)
  3. Domyślna wartość dla parametru (opcjonalna)
Poniżej niezbyt wyrafinowany przykład, który wywołuje Message Box z tekstem "Hello".
import ctypes
from ctypes.wintypes import HWND, LPCSTR, UINT

# (C++)
#int WINAPI MessageBox(
#  _In_opt_  HWND hWnd,
#  _In_opt_  LPCTSTR lpText,
#  _In_opt_  LPCTSTR lpCaption,
#  _In_      UINT uType
#);

func_prototype = ctypes.WINFUNCTYPE(ctypes.c_int, HWND, LPCSTR, LPCSTR, UINT)
func_param = (1, "hwnd", 0), (1, "text", "Hello"), (1, "caption", None), (1, "flags", 0)
MessageBox = func_prototype(("MessageBoxA", ctypes.windll.user32), func_param)

MessageBox()

Brak komentarzy:

Prześlij komentarz