Ctypes,调用外部windll函数
Ctypes, calling an external windll function
我想在 Windows 上使用 Python3 从外部 dll 调用一些函数。我要使用的库和函数如下;
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
,从它的 return 中获取指针并在 mecab_sparse_tostr
上使用它,然后最后通过调用 [=17= 使用相同的指针来处理它].
我发现以下内容在 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
函数总是 returns 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 参数,它 return 是 0,而 restype = ctypes.POINTER(ctypes.c_int)
它 return 是一个空指针。
我浏览过类似的问题和文档,但找不到方法。我对 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
是一个非零整数(看起来是一个有效的指针)。
我想在 Windows 上使用 Python3 从外部 dll 调用一些函数。我要使用的库和函数如下;
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
,从它的 return 中获取指针并在 mecab_sparse_tostr
上使用它,然后最后通过调用 [=17= 使用相同的指针来处理它].
我发现以下内容在 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
函数总是 returns 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 参数,它 return 是 0,而 restype = ctypes.POINTER(ctypes.c_int)
它 return 是一个空指针。
我浏览过类似的问题和文档,但找不到方法。我对 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
是一个非零整数(看起来是一个有效的指针)。