質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

15576閲覧

python で dll の関数を呼び出すとき、引数が「配列のポインタ」のときのコードについて

GuielNo4

総合スコア88

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2017/03/30 02:47

###前提・実現したいこと
ctypes を利用して dll の関数の引数経由で配列のポインタを取得することが目的なのですが、
エラーが発生してしました。
多分カッコの解釈でタプルなのか範囲なのか、はたまたリストにすべき部分で間違えていると思い、
さまざまの解説ページを見ているのですが、いまいち理解できない状況が続いており、
質問することに致しました。
動作するコードを教えていただけると助かります。

またひょっとして、c_int_p が用意されていないということは、
pythonの仕様として
「配列のポインタ」という機能はなくて、
「構造体のポインタ」で行うことが前提だったりしますでしょうか?

###発生している問題・エラーメッセージ
argument 1: <class 'TypeError'>: expected LP_c_long instance instead of _ctypes.PyCPointerType

###該当のソースコード
【python】
from ctypes import *
userdll = windll.LoadLibrary('userdll.dll')
userdll.FunctionTypeB.restype = c_int
userdll.FunctionTypeB.argtypes = [POINTER(c_int), (c_int)]
length = c_int(16)
buffer = c_int * 16
p_buffer = POINTER(buffer)
result = userdll.FunctionTypeB( p_buffer , length) ← ここでエラー

【DLL】
extern "C" __declspec(dllexport) int FunctionTypeB(int* buffer, int length)
{
for (int index = 0; index < length; index++)
{
buffer[index] = index;
}
return 1;
}

###補足情報(言語/FW/ツール等のバージョンなど)
visual studio 2013
python 3.6.0 :: Anaconda cuntum (64-bit)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以下の修正で、こちらの環境(Win10x64, python=3.5.2, DLL=VS2010にて64bitANSIビルド)では正しく動作しました。

  • classではなくobjectを得る
  • castする

Python

1 userdll = windll.LoadLibrary('MyDLL.dll') 2 userdll.Sum.restype = c_int 3 userdll.Sum.argtypes = [POINTER(c_int), (c_int)] 4 5 length = c_int(16) 6 7 #buffer = c_int * 16 8 #buffer = <class '__main__.c_long_Array_16'> 9 #p_buffer = POINTER(buffer) 10 #p_buffer = <class '__main__.LP_c_long_Array_16'> 11 12 buffer = (c_int * 16)() 13 #buffr = <__main__.c_long_Array_16 object at 0x0000016931FBC1C8> 14 p_buffer = cast(buffer, POINTER(c_int)) 15 #p_buffer = <__main__.LP_c_long object at 0x0000016931FBC248> 16 17 result = userdll.Sum( p_buffer, length) 18 print(result)

MyDLL.h

C++

1#ifdef MYDLL_EXPORTS 2#define MYDLL_API __declspec(dllexport) 3#else 4#define MYDLL_API __declspec(dllimport) 5#endif 6MYDLL_API int WINAPI Sum( int *pn, int count);

MyDLL.cpp

C++

1#define MYDLL_EXPORTS 2#include "MyDLL.h" 3MYDLL_API int WINAPI Sum( int *pn, int count) 4{ 5 int ret = 0; 6 for( int i = 0; i < count; i++){ 7 pn[i] = i+1; 8 ret += pn[i]; 9 } 10 return ret; 11}

参考:Mutate an integer array using ctypes

投稿2017/03/30 04:24

編集2017/03/30 04:40
can110

総合スコア38262

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

GuielNo4

2017/03/30 05:08

コードと解説コメント、有難うございました。 こちらの環境でもエラーが発生せず動作させられました。 python には 変数 が内部でクラスやオブジェクトとして区分されるルールがあることがよくわかりました。 カッコのように同一文字なのに意味や解釈が異なる部分の理解をもう少し学習しないといけないですね… ありがとうございました。
can110

2017/03/30 05:16

私も最初は混乱しましたが、「c_int * 16」はc_long_Array_16 クラスを指しており「(c_int * 16)()」でそのインスタンスを生成していると理解すればよいかと思います。
GuielNo4

2017/03/30 05:40

よくよく考えれば、Cのインタフェースなので、コードの内部処理をCに置き換えることを意識しなければいけないですね… アドバイスありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問