2017-04-18 1 views
1

Je souhaite appeler certaines fonctions à partir d'une DLL externe à l'aide de Python3 sous Windows. La bibliothèque et les fonctions que je veux utiliser sont comme ci-dessous;Ctypes, appel d'une fonction windll externe

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); 

Je dois appeler mecab_new2 d'abord, obtenir le pointeur de son retour et l'utiliser sur mecab_sparse_tostr, puis finalement en disposer en utilisant le même pointeur en appelant mecab_destroy.

J'ai trouvé que les travaux suivants en C# (si elle aide comme référence):

[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)); 

Mais ne pouvait pas trouver une manière similaire en python. J'ai essayé ce qui suit avec différents types de restes et argtypes. Mais la fonction mecab_new2 renvoie toujours 0 (je suppose que c'est nul?).

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 

Si je retire l'argument restype retourne 0, avec restype = ctypes.POINTER(ctypes.c_int) il renvoie un pointeur NULL.

J'ai parcouru des questions similaires et la documentation, mais je n'ai pas trouvé comment. Suis très mauvais avec C++ et donc avec ctypes aussi bien.

Merci.


EDIT: J'ai essayé une autre fonction de la bibliothèque, qui n'a pas besoin d'arguments et cela a fonctionné correctement. Donc je suppose que mon problème réside avec des arguments ne correspondant pas? ou la bibliothèque est cassée en quelque sorte?

fichier d'en-tête:

MECAB_DLL_EXTERN const char* mecab_version(); 

code Python:

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

Répondre

2

Je pense que votre problème est peut-être ici:

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

WinDLL signifie utiliser la convention d'appel DLL Windows (stdcall). Cependant, en C#, vous utilisez C convention d'appel (cdecl):

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

Si votre code C# fonctionne, essayez de ré-écrire votre ctypes appeler comme ceci:

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

Edit: Vous faites également un peu de travail pour transmettre cette chaîne à votre fonction. Vous devriez pouvoir simplement faire ceci (je ne suis pas sûr à 100% cela fonctionnera dans python3 - il fonctionne parfaitement dans python2):

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

Python est assez intelligent sur la détermination des types de fonctions étrangères - vous shouldn » Je dois les déclarer à moins que vous ne fassiez quelque chose d'inhabituel.

Éditer 2 Cela fonctionne pour moi, en utilisant Python 2, 32 bits: Je le fais à partir d'une invite interactive.répertoire de travail est C:\Program Files (x86)\MeCab\bin

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

res est alors un entier non nul (semble être un pointeur valide).

+0

Merci pour la réponse, cela fait beaucoup de sens. Mais j'ai toujours le même résultat en appelant 'mecab_dll = ctypes.CDLL (r" C: \ libmecab.dll ")'. Il renvoie l'erreur 'NULL pointer access'. – umutto

+1

Je viens de faire quelques mises à jour qui pourraient aider - il semble aussi que vous passez un pointeur sur une chaîne (char **) au lieu d'une chaîne (char *) à votre fonction mecab_new2. – iUknwn

+0

Merci encore pour votre réponse! Ne sachant pas vraiment quoi faire, brouillé toutes les solutions que je peux trouver =). Mais malheureusement, le résultat n'a pas changé avec l'édition, renvoie toujours un pointeur NULL. – umutto