Ctypes,调用外部函数函数
我想在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
我认为你的问题可能会在这里:
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
那么一个非零整数(似乎是一个有效的指针)。
感谢您的回复,这实际上有很大意义。但是我仍然通过调用'mecab_dll = ctypes.CDLL(r“C:\ libmecab.dll”)'得到相同的结果。它会抛出'NULL指针访问错误。 – umutto
我只是做了几个更新,可能会有所帮助 - 它也看起来像你传递一个指向字符串(char **)的指针而不是字符串(char *)到你的mecab_new2函数。 – iUknwn
再次感谢您的回复!不知道该怎么做,卡住了我能找到的每个解决方案=)。但可悲的结果并没有改变与编辑,仍然返回一个NULL指针。 – umutto