2016-04-21 21 views
0

Ich habe einen .dll namens my.dll, mit 4 Funktionen aufgerufen, in Python 3.5 verwenden:
myDLL = ctypes.cdll.LoadLibrary(Path:\to\my.dll)Aufruf dll in Python 3 mit LPSTR

Mein Problem eine Funktion aufruft, die LPSTR hat:

#include "stdafx.h" 
#include "newheader.h"  
double _stdcall pain_function(double arg1, double arg2, LPSTR arg_string_with_spaces) 

die anderen 3 Anrufe zu my.dll funktionieren gut.

Unten ist der Code, den ich für die pain_function versucht:

import ctypes 
from ctypes import wintypes 

# Load dll 
myDLL = ctypes.WinDLL(Path:\to\my.dll) 

# Call function 
pain_function = myDLL.pain_function 

# Typecast the arguments 
pain_function.argtypes = [ctypes.c_double, ctypes.c_double, wintypes.LPSTR] 

# Typecast the return 
pain_function.restype = ctypes.c_double 


pain_return = pain_function(arg1, arg2, some_string) 

pain_return kehrt einige unsinnige Zahl. Ich habe versucht, einige Variationen, meist entlang der Linien von:

some_string = ctypes.create_string_buffer(b' ' * 200) 

ich hier unter anderem ausgesehen haben:

  1. python-ctypes-prototype-with-lpcstr-out-parameter

  2. Using String Parameters in DLL Function Calls

Was ist das richtige Weise, um die Zeichenfolge von 200 Leerzeichen an die DLL übergeben?

Vielen Dank im Voraus

+0

'LPSTR' ist ein a Lias von 'c_char_p'. Wenn Sie möchten, können Sie 'from ctypes import wintypes; wintypes.LPSTR'. Da es nicht 'LPCSTR' (eine konstante Zeichenkette) ist, sollten wir davon ausgehen, dass die Funktion den Puffer modifiziert, so dass Sie' create_string_buffer' verwenden können. Es besteht keine Notwendigkeit, den Wert zu "codieren". Verwenden Sie einfach ein 'Bytes' Literal, z.B. 'e = create_string_buffer (b '' * 200)'. Wenn Sie den Wert codieren, verwenden Sie die Kodierung "mbcs" anstelle der Kodierung für harte Codes, Codepage 1252. – eryksun

+0

In Bezug auf die unsinnige Nummer wurde der vollständige Prototyp nicht angezeigt. Wenn 'pain_function' einen 'void'-Rückgabewert hat, setze' pain_function.restype = None'. Wenn es einen "doppelten" Rückgabewert hat, setze 'pain_function.restype = c_double'. Und so weiter. – eryksun

+0

@eryksun Danke! ... Ich glaube, es gab zwei Probleme mit dem Code (1) 'restype', den ich (2) diesen 'LPSTR' korrigiert habe. Jetzt sieht mein Argumenttyp so aus:' pain_function = ['ctypes.c_double, ctypes.c_double, wintypes .LPSTR] 'aber - jetzt gibt es nur ein Double, was fehlt noch? –

Antwort

1

Sie der Prototyp angegeben war:

double _stdcall pain_function(double arg1, double arg2, LPSTR arg_string_with_spaces) 

aber mit:

myDLL = ctypes.cdll.LoadLibrary(Path:\to\my.dll) 

Es sollte für __stdcall Aufrufkonvention:

myDLL = ctypes.WinDLL('Path:\to\my.dll') 
+0

Wahrscheinlich Itay verwendet 64-Bit Python, auf dem es keinen Unterschied macht. Aber es ist immer noch besser, 'WinDLL' zu verwenden, um 32-Bit-Python zu unterstützen. – eryksun

+0

Das ist richtig Ich benutze 64-Bit-Python. Und lustig genug, als ich versuchte, das Problem herauszufinden, versuchte ich beides und es machte keinen Unterschied. Davon abgesehen - ich nehme die Vorschläge auf. –

+0

@ItayLivni, spielt es in 32-Bit-Python eine Rolle. In x86 'stdcall' (d. H.' WinDLL') bereinigt der Angerufene den Stapel bei der Rückgabe, weshalb Sie diese Konvention nicht mit C variadic-Funktionen wie 'printf' verwenden können. ctypes überprüft dies, falls eine 'stdcall'-Funktion irrtümlicherweise als' cdecl' (d. h. 'CDLL') aufgerufen wird. In diesem Fall sollte eine Ausnahme ausgelöst werden, wie z. B. "ValueError: Prozedur, die mit nicht genügend Argumenten (N Bytes fehlen) oder falsche Aufrufkonvention" aufgerufen wird, wobei N die Anzahl der Bytes ist, die der Angerufene vom Stapel entfernt hat. – eryksun