2017-04-18 125 views
1

我想在Windows上使用Python3从外部dll调用一些函数。图书馆和我想要使用的功能如下:Ctypes,调用外部函数函数

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

我需要首先调用mecab_new2,从它的回归得到的指针,并用它在mecab_sparse_tostr,然后通过调用mecab_destroy使用相同的指针最终处置它。

我发现,在C#以下工作(如果它有助于为参考):

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

但是在Python不能工作了类似的方式。我已经尝试了以下与不同的restypes和argtypes。但mecab_new2函数总是返回0(我认为它是空的?)。

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 

如果我删除restype参数,返回0,与restype = ctypes.POINTER(ctypes.c_int)它返回一个空指针。

我浏览过类似的问题和文档,但找不到方法。对C++非常不好,因此也对ctypes很不好。

谢谢。


编辑:我试图从库,一个不需要任何参数另一个函数,它工作正常进行。所以我假设我的问题与参数不匹配?或者图书馆被打破了?

头文件

MECAB_DLL_EXTERN const char* mecab_version(); 

Python代码:

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

回答

2

我认为你的问题可能会在这里:

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

WINDLL意味着使用Windows DLL调用约定(STDCALL)。然而,在C#中,你用C调用约定(CDECL):

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

如果你的C#代码的工作,尝试重新写你的ctypes这样调用:

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

编辑:你也做了很多工作来将该字符串传递给你的函数。你应该能够简单地做这个(我不是100%肯定这将在Python3工作 - 它完美的作品在Python2):

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

Python是相当聪明有关确定对外职能类型 - 你不该”除非你在做一些不寻常的事情,否则不得不宣布它们。

编辑2这对我来说,使用Python 2,32位: 我从交互式提示做到这一点。工作目录是C:\Program Files (x86)\MeCab\bin

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

res那么一个非零整数(似乎是一个有效的指针)。

+0

感谢您的回复,这实际上有很大意义。但是我仍然通过调用'mecab_dll = ctypes.CDLL(r“C:\ libmecab.dll”)'得到相同的结果。它会抛出'NULL指针访问错误。 – umutto

+1

我只是做了几个更新,可能会有所帮助 - 它也看起来像你传递一个指向字符串(char **)的指针而不是字符串(char *)到你的mecab_new2函数。 – iUknwn

+0

再次感谢您的回复!不知道该怎么做,卡住了我能找到的每个解决方案=)。但可悲的结果并没有改变与编辑,仍然返回一个NULL指针。 – umutto