2017-04-18 4 views
1

Ich möchte einige Funktionen von einer externen DLL mit Python3 unter Windows aufrufen. Die Bibliothek und die Funktionen, die ich verwenden möchte, sind wie folgt;Ctypes, Aufruf einer externen windll-Funktion

MECAB_DLL_EXTERN mecab_t*  mecab_new2(const char *arg); 

MECAB_DLL_EXTERN const char* mecab_sparse_tostr(mecab_t *mecab, const char *str); 

MECAB_DLL_EXTERN void   mecab_destroy(mecab_t *mecab); 

Ich brauche ersten mecab_new2 zu nennen, um den Zeiger von seiner Rückkehr bekommen und es auf mecab_sparse_tostr verwenden, dann ist es schließlich entsorgen die gleichen Zeiger mit von mecab_destroy aufrufen.

habe ich gefunden, dass die folgenden Werke in C# (wenn es hilft als Referenz):

[DllImport(@"C:\libmecab.dll", CallingConvention = CallingConvention.Cdecl)] 
private extern static IntPtr mecab_new2(string arg); 
[DllImport(@"C:\libmecab.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] 
private extern static IntPtr mecab_sparse_tostr(IntPtr m, byte[] str); 
... 
{ 
    IntPtr mecab = mecab_new2("-Owakati"); // returns a pointer 
    mecab_sparse_tostr(mecab, Encoding.UTF8.GetBytes(input)); 

konnte aber nicht eine ähnliche Art und Weise in Python trainieren. Ich habe das folgende mit verschiedenen restypes und argtypes versucht. Aber die mecab_new2 Funktion gibt immer 0 zurück (ich nehme an, es ist Null?).

import ctypes 

mecab_dll = ctypes.WinDLL(r"C:\libmecab.dll") 
mecab_new2 = mecab_dll['mecab_new2'] 

mecab_new2.restype = ctypes.POINTER(ctypes.c_int) 
mecab_new2.argtypes = [ctypes.c_char_p] 

p1 = ctypes.c_char_p(b"-Owakati") 
res = mecab_new2(p1) 

print(res.contents) 
# ValueError: NULL pointer access 

Wenn ich entfernen Sie das restype Argument es 0 zurückgibt, mit restype = ctypes.POINTER(ctypes.c_int) es einen Null-Zeiger zurückgibt.

Ich habe ähnliche Fragen und die Dokumentation durchsucht, konnte aber nicht finden, wie. Bin sehr schlecht mit C++ und damit auch mit Ctypes.

Danke.


EDIT: ich eine andere Funktion aus der Bibliothek versucht haben, eine, die keine Argumente benötigen und es funktionierte richtig aus. Also nehme ich an, dass mein Problem mit nicht passenden Argumenten liegt? oder die Bibliothek ist irgendwie kaputt?

Headerdatei:

MECAB_DLL_EXTERN const char* mecab_version(); 

Python-Code:

mecab_ver = mecab_dll["mecab_version"] 
mecab_ver.restype = ctypes.c_char_p 
print(mecab_ver()) # returns b'0.996' which is correct 

Antwort

2

denke ich Ihr Problem hier sein könnte:

mecab_dll = ctypes.WinDLL(r"C:\libmecab.dll") 

WINDLL bedeutet, dass Windows DLL Konvention (stdcall) Aufruf verwenden. Doch in C#, die Sie verwenden C-Aufrufkonvention (cdecl):

[DllImport(@"C:\libmecab.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] 

Wenn Ihr C# Code funktioniert, versuchen Sie neu zu schreiben Ihre ctypes wie folgt aufrufen:

mecab_dll = ctypes.cdll.LoadLibrary(r"C:\libmecab.dll") 

Edit: Du machst auch ziemlich viel Arbeit, um diese Zeichenfolge an deine Funktion zu übergeben. Sie sollten diese in der Lage sein, einfach zu tun (ich bin nicht 100% sicher, dass das in Python3 arbeiten - es funktioniert einwandfrei in Python2):

mecab_dll = ctypes.cdll(r"C:\libmecab.dll") 
res = mcab_dll.mecab_new2(b"-Owakati") 

Python ziemlich intelligent ist über Typen in fremden Funktionen zu bestimmen - Sie shouldn‘ Ich muss sie erklären, es sei denn, du machst etwas Ungewöhnliches.

Bearbeiten 2 Dies funktioniert für mich, mit Python 2, 32bit: Ich mache das von einer interaktiven Eingabeaufforderung.Arbeitsverzeichnis C:\Program Files (x86)\MeCab\bin

mecab = ctypes.cdll.LoadLibrary("libmecab.dll") 
res = mecab.mecab_new2("-Owakati") 

res ist dann eine von Null verschiedene ganze Zahl ist, (erscheint ein gültiger Zeiger zu sein).

+0

Danke für die Antwort, das macht wirklich viel Sinn. Aber ich habe immer noch das gleiche Ergebnis, indem ich 'mecab_dll = ctypes.CDLL (r" C: \ libmecab.dll ")' aufruft. Es wirft 'NULL Zeigerzugriffsfehler 'auf. – umutto

+1

Ich habe gerade ein paar Updates gemacht, die helfen könnten - es sieht auch so aus, als würden Sie einen Zeiger auf eine Zeichenfolge (char **) anstelle einer Zeichenfolge (char *) an Ihre mecab_new2-Funktion übergeben. – iUknwn

+0

Nochmals vielen Dank für Ihre Antwort! Nicht wirklich zu wissen, was zu tun ist, staute jede Lösung, die ich finden kann =). Leider hat sich das Ergebnis beim Editieren nicht geändert, es wird immer noch ein NULL-Zeiger zurückgegeben. – umutto

Verwandte Themen