Jak mogę użyć pliku DLL z Pythona?

186

Jaki jest najłatwiejszy sposób korzystania z DLLpliku od wewnątrz Python?

W szczególności, w jaki sposób można tego dokonać bez pisania dodatkowego C++kodu opakowania, w którym można by udostępnić funkcjonalność Python?

Natywna Pythonfunkcjonalność jest zdecydowanie lepsza niż korzystanie z biblioteki innej firmy.

Tom Hennen
źródło
@Remuze oznaczyłeś błędne pytanie lub złą odpowiedź? Oba są pythonami, ale nie widzę powodu, dla którego można by je w ogóle znaleźć (i sprawdziłem historię zmian, aby upewnić się, że w pewnym momencie nie była bliższa)
Foon
@foon hmmm tak przepraszam, chciałem oflagować kolejne pytanie jako zduplikowane i umieścić to :) Myślę, że to pokazuje, jak podobne są!
Trev Davies,

Odpowiedzi:

154

Dla ułatwienia użytkowania ctypes jest właściwą drogą.

Poniższy przykład ctypów pochodzi z faktycznego kodu, który napisałem (w Pythonie 2.5). To zdecydowanie najłatwiejszy sposób, w jaki znalazłem robienie tego, o co prosisz.

import ctypes

# Load DLL into memory.

hllDll = ctypes.WinDLL ("c:\\PComm\\ehlapi32.dll")

# Set up prototype and parameters for the desired function call.
# HLLAPI

hllApiProto = ctypes.WINFUNCTYPE (
    ctypes.c_int,      # Return type.
    ctypes.c_void_p,   # Parameters 1 ...
    ctypes.c_void_p,
    ctypes.c_void_p,
    ctypes.c_void_p)   # ... thru 4.
hllApiParams = (1, "p1", 0), (1, "p2", 0), (1, "p3",0), (1, "p4",0),

# Actually map the call ("HLLAPI(...)") to a Python name.

hllApi = hllApiProto (("HLLAPI", hllDll), hllApiParams)

# This is how you can actually call the DLL function.
# Set up the variables and call the Python name with them.

p1 = ctypes.c_int (1)
p2 = ctypes.c_char_p (sessionVar)
p3 = ctypes.c_int (1)
p4 = ctypes.c_int (0)
hllApi (ctypes.byref (p1), p2, ctypes.byref (p3), ctypes.byref (p4))

ctypesMateriał posiada typach danych typu C ( int, char, short, void*, i tak dalej), może przechodzić przez wartość lub odniesienia. Może także zwracać określone typy danych, chociaż mój przykład tego nie robi (interfejs API HLL zwraca wartości poprzez modyfikację zmiennej przekazywanej przez referencję).


Jeśli chodzi o konkretny przykład pokazany powyżej, interfejs EHLLAPI firmy IBM jest dość spójnym interfejsem.

Wszystkie wywołania przekazują cztery puste wskaźniki (EHLLAPI wysyła kod powrotu z powrotem przez czwarty parametr, wskaźnik do inttak, podczas gdy określam intjako typ zwracany, mogę go bezpiecznie zignorować) zgodnie z dokumentacją IBM tutaj . Innymi słowy, wariantem C funkcji byłoby:

int hllApi (void *p1, void *p2, void *p3, void *p4)

To sprawia, że ​​jedna, prosta ctypesfunkcja jest w stanie zrobić wszystko, co zapewnia biblioteka EHLLAPI, ale prawdopodobne jest, że inne biblioteki będą wymagały osobnej ctypeskonfiguracji dla każdej funkcji biblioteki.

Zwracana wartość z WINFUNCTYPEjest prototypem funkcji, ale nadal musisz skonfigurować więcej informacji o parametrach (ponad typami). Każda krotka hllApiParamsma parametr „kierunek” (1 = wejście, 2 = wyjście itd.), Nazwę parametru i wartość domyślną - ctypesszczegółowe informacje można znaleźć w dokumentacji doco

Po uzyskaniu informacji o prototypie i parametrach można utworzyć „wywoływalny” język Python, za hllApipomocą którego można wywołać funkcję. Wystarczy stworzyć niezbędną zmienną ( p1poprzez p4w moim przypadku) i wywołać funkcję z nimi.

paxdiablo
źródło
1
Witam, może minąć dużo czasu, odkąd ktoś tu odpowiedział, ale chciałem się dowiedzieć, aby ta funkcja działała dokładnie w moim programie. Czy możesz mi powiedzieć, co to jest „HLLAPI”? Ponadto, jeśli chcę uzyskać dostęp do mojej biblioteki dll za pomocą funkcji „void BoxProperties (double L, double H, double W, double & A, double & V);” czy możesz mi zasugerować, jakie zmiany powinienem wprowadzić w powyższym kodzie, aby działał? Twoje zdrowie.
Neophile
4
Co dokładnie robi hllApiParams? Jaki jest sens tych krotek? Trudno jest dopasować niektóre elementy w tym przykładzie do dokumentacji.
Jonathon Reinhart
1
@JonathonReinhart, szczegółowo opisałem konkretny przykład z tekstem na dole. Mam nadzieję, że to wyjaśnia to trochę lepiej. Jeśli nie, daj mi znać, a spróbuję ponownie :-)
paxdiablo
1
doskonała odpowiedź, bardzo pomaga 6 lat później :) Gdybym mógł, postawiłbym +100!
Pułkownik Beauvel
1
Jest to bardzo mylące z perspektywy początkujących ctypów. Nie jestem pewien, co się dzieje, nawet z wyjaśnieniem.
DuckPuncher
69

Ta strona zawiera bardzo prosty przykład wywoływania funkcji z pliku DLL.

Parafrazując szczegóły tutaj dla kompletności:

W Pythonie bardzo łatwo jest wywołać funkcję DLL. Mam samodzielnie utworzony plik DLL z dwiema funkcjami: addi subktóre wymagają dwóch argumentów.

add(a, b)zwraca dodanie dwóch liczb
sub(a, b)zwraca odejmowanie dwóch liczb

Nazwa pliku DLL to „demo.dll”

Program:

from ctypes import*
# give location of dll
mydll = cdll.LoadLibrary("C:\\demo.dll")
result1= mydll.add(10,1)
result2= mydll.sub(10,1)
print "Addition value:"+result1
print "Substraction:"+result2

Wynik:

Addition value:11
Substraction:9

atul
źródło
2
Link w tej odpowiedzi jest zepsuty.
Kaliber64
10
Jeśli link nie działa, nie martw się, jest to bezpośrednia kopia wklej. Nie tracisz żadnych informacji.
bagno
6

Może z Dispatch:

from win32com.client import Dispatch

zk = Dispatch("zkemkeeper.ZKEM") 

Gdzie zkemkeeper jest zarejestrowanym plikiem DLL w systemie ... Następnie możesz uzyskać dostęp do funkcji, wywołując je:

zk.Connect_Net(IP_address, port)
Carlos Gomez
źródło
Pracuję nad tym zkemkeeper.ZKEM, czy wiesz, jak mogę otrzymywać zdarzenia w czasie rzeczywistym w Pythonie?
Sam Ziggler,
4

Budowanie biblioteki DLL i łączenie jej w Pythonie za pomocą ctypes

Przedstawiam w pełni sprawny przykład, w jaki sposób budowanie shared libraryi używanie go Pythonza pomocą ctypes. Rozważam tę Windowssprawę i zajmuję się nią DLLs. Potrzebne są dwa kroki:

  1. Zbuduj bibliotekę DLL za pomocą kompilatora Visual Studio albo z wiersza poleceń, albo z IDE;
  2. Połącz bibliotekę DLL w Pythonie za pomocą ctypes.

Udostępniona biblioteka

shared libraryUważam jest następujący i jest zawarty w testDLL.cpppliku. Jedyna funkcja testDLLwłaśnie odbiera inti drukuje ją.

#include <stdio.h>

extern "C" {

__declspec(dllexport)

void testDLL(const int i) {
    printf("%d\n", i);
}

} // extern "C"

Budowanie biblioteki DLL z wiersza polecenia

Aby zbudować za DLLpomocą Visual Studioz linii poleceń, uruchom

"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\vsdevcmd"

ustawić ścieżkę dołączania, a następnie uruchomić

cl.exe /D_USRDLL /D_WINDLL testDLL.cpp /MT /link /DLL /OUT:testDLL.dll

zbudować DLL.

Budowanie DLLz IDE

Alternatywnie DLLmożna zbudować Visual Studiow następujący sposób:

  1. Plik -> Nowy -> Projekt;
  2. Zainstalowane -> Szablony -> Visual C ++ -> Windows -> Win32 -> Win32Project;
  3. Kolejny;
  4. Typ aplikacji -> DLL;
  5. Dodatkowe opcje -> Pusty projekt (wybierz);
  6. Dodatkowe opcje -> Prekompilowany nagłówek (odznacz);
  7. Projekt -> Właściwości -> Menedżer konfiguracji -> Aktywna platforma rozwiązań: x64;
  8. Projekt -> Właściwości -> Menedżer konfiguracji -> Konfiguracja aktywnego rozwiązania: Wydanie.

Łączenie biblioteki DLL w Pythonie

W obszarze Python wykonaj następujące czynności

import os
import sys
from ctypes import *

lib = cdll.LoadLibrary('testDLL.dll')

lib.testDLL(3)
Latarnia z dyni
źródło
Co jeśli biblioteka DLL w pakiecie python? Jak mogę uzyskać do niego dostęp?
decadenza
3

ctypy będą najłatwiejszą w użyciu, ale (złe) użycie powoduje, że Python ulega awarii. Jeśli próbujesz zrobić coś szybko i jesteś ostrożny, to świetnie.

Zachęcam do sprawdzenia Boost Python . Tak, wymaga napisania kodu C ++ i posiadania kompilatora C ++, ale tak naprawdę nie trzeba uczyć się C ++, aby z niego korzystać, i można uzyskać darmowy (jak w piwie) kompilator C ++ od Microsoft .

David Nehme
źródło
0

Jeśli biblioteka DLL jest typu COM, możesz użyć pythonnet.

pip install pythonnet

Następnie w kodzie python wypróbuj następujące rozwiązania

import clr
clr.AddReference('path_to_your_dll')

następnie utwórz obiekt zgodnie z klasą w bibliotece DLL i uzyskaj dostęp do metod w nim zawartych.

sattva_venu
źródło