2017-04-18 208 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