2017-04-18 12 views
1

Windows上のPython3を使用して外部DLLからいくつかの関数を呼び出したいとします。ライブラリと私が使いたい機能は以下の通りです。外部windll関数を呼び出す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_destroyを呼び出すことにより、同じポインタを使用して、それを配置、そのリターンからポインタを取得し、mecab_sparse_tostrにそれを使用する、最初のmecab_new2を呼び出す必要があります。

(これを基準と場合に役立ちます)私は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を返します(私はそのnullを仮定しますか?)。

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引数を削除した場合、それはNULLポインタを返すrestype = ctypes.POINTER(ctypes.c_int)と、0を返します。

私は似たような質問とドキュメントを参照しましたが、方法が見つかりませんでした。 C++では非常に悪いので、ctypesも同様です。

ありがとうございました。


EDIT:私は、ライブラリから別の関数、引数を必要とし、それが正常に働いていないものを試してみました。だから私は問題が一致しない引数で存在すると仮定していますか?またはライブラリは何とか壊れていますか?

ヘッダファイル:

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は大会(STDCALL)を呼び出すWindowsのDLLを使用することを意味します。しかし、C#で、あなたが呼び出し規約Cを使っている(CDECL):

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

編集:あなたのC#のコードが動作する場合

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

、あなたのctypesのは、このように呼んで再書き込みをしてみてくださいまた、その文字列を関数に渡すためにかなりの作業をしています。あなたは(私はこれがのpython3で動作する100%確実ではないよ - それはPython2で完璧に動作します)単純にこれを行うことができるようになります。

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

Pythonは外部関数の型を決定については非常に知的である - あなたは「shouldnあなたが何か珍しいことをしない限り、宣言しなければなりません。

編集2これは私のために、Python 2の32bitを使用しています: 私はこれを対話型のプロンプトからやっています。ディレクトリが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

私はちょっと参考にしました。mecab_new2関数に文字列(char *)の代わりに文字列(char **)へのポインタを渡しているようです。 – iUknwn

+0

返信いただきありがとうございます!本当に何をすべきかを知らず、私が見つけることができるすべての解決法を混乱させる=)。しかし、悲しいことに結果は編集で変更されず、依然としてNULLポインタを返します。 – umutto

関連する問題