06-20-2014 01:02 AM
現在、DLLを使用したC++のプログラムをLabViewに移植しようとしています。
(LabView上でもDLLを参照する)
ですがDLLを参照した時の引数のやり取りで難航しています。
*DLLをインポートして作成されたVIを使用していますが
そのまま実行すると強制終了してしまいます。
C++のプログラムは以下に記述します。
------------------------------------------------------------
/* DLL内の関数 */
void InitConfig( unsigned int * config );
void InitBuff( unsigned char * buff );
void SetWord( char* word );
------------------------------------------------------------
int main()
{
int Size;
unsigned int *ConfigData;
unsigned char* Buff;
/* 1. */
Size = 2000;
ConfigData = (unsigned int*)malloc((long)Size * sizeof(unsigned int ));
Buff = (unsigned char*)malloc((long)Size * sizeof(unsigned char ));
/* 2. */
InitConfig( ConfigBuff );
InitBuff( buff );
/* 3. */
SetWord( "ABCDEFG" );
}
------------------------------------------------------------
上記の処理的には以下になります。
1. サイズ分だけメモリを確保する
2. 確保したメモリの先頭アドレスをDLLの関数に渡す
3. DLLの関数に文字列を渡す
難航している個所として
・「1.」でLabView上でメモリ確保する場合は、どのような処理になるのか?
・「2.」でLabView上で先頭アドレスを渡す場合は、どのような処理になるのか?
・「3.」でLabView上で文字列を渡す場合は文字列配列を渡すことになるのか?
よろしくお願いします。
解決済! 解決策の投稿を見る。
06-20-2014 08:11 AM
例えば、このようになるかと思います。
今、dllが、以下のような感じに実装されていると仮定しますが、
(int は、実装によりサイズが何とも言えないので long で書きました。また、呼び出し形式は _cdecl と仮定)
void InitConfig(unsigned long *config) に、longで2000個分の領域をmallocっぽくエリアを確保して
その先頭アドレスを渡したい、ということであれば、LabVIEW上では、「要素数2000で、とりあえず値がゼロ」
の「I32の配列」を渡せばよいです。この時、渡すときのCall Library Functionでは、「I32の配列」で
配列へのデータポインタとして渡します。
void InitBuff(unsigned char *buff) に対しても同様で、この場合は、U8の配列として渡しても良いですが、
もう1つ、それを文字列にcastしてから、文字列として渡す、という方法もあります。
この場合は、Call Library Functionでは、「文字列(C文字列ポインタ)」で渡すことが出来ます。
(U8の配列で配列へのデータポインタとして渡しても良いし、C文字列ポインタで渡しても良いし、
※別途何らかのdllから「ポインタの値そのもの」がU32で得られていたりして、そのポインタ値をそのまま
次のdllの関数に渡したいなら、Call Library Functionの引数を「U32の値」として、そのまま値で配線してもOKです。
要は、Cは、宣言がポインタなら内部では「U32」で渡しているのと同じなので(Cにはそもそも参照渡しは存在せず、
ポインタで渡しているものは基本は32ビット整数を値渡ししているので)、論理的に合っていれば、
元のdllの宣言と違っていても問題ないです)
void SetWord(char *word) は、上と同じです。
これらを、vi的に表現すると、こんな感じです。
LabVIEWのversionにより、Call Library Functionの設定形式がちょっと違うかも知れませんが。
確保したメモリとしてのバッファの用意の仕方、配線の仕方、Call Library Functionの設定と
先のcppの宣言の仕方とを、比較して頂ければ。
ここでは要素数は「200」ですが、先に確保したいバッファの大きさに応じて、設定して下さい。
上に挙げたcppをコンパイルしたdllで呼び出すと、InitConfig() は、渡した配列の最初の2個の要素に
10000と20000を入れていますので、返ってきた配列はそうなって表示されます。
InitBuff() は、"12345"の文字列がコピーされますので、返ってきた文字列は"12345" になります。
(このとき、後ろの部分はバッファとしてカットされることに注意。これを維持する場合は、数値の配列で渡す)
SetWord() は、特に何もしません。
おまけの SampleFunc() は、srcに元の文字列、destにコピー用バッファ、lenにバッファサイズを指定して、
内部でlstrcpyn を呼び出しているので、srcがdestにコピーされて返ってきます。
ご参考下さい。
06-25-2014 12:02 AM
詳細な説明、サンプルコードありがとうございます。
大変参考になりました。
「C : メモリ確保 = LabView : 配列確保」は盲点でした。
(LabViewでもmallocのようにメモリ確保する機能があると思っていました)
DLL関数とのやり取りも、LabView上でのプロパティから
「配列」、「ポインタ」などの設定を合うように変更すればよかったのですね。
(最初の設定で固定だと思っていました・・・こちらも勘違い)
難航していた個所はサンプルを元にコーディングして、
実際に機能していることが確認できたので問題はすべて解決しました。
ありがとうございました。
06-26-2014 08:36 AM
とりあえず解決とのことで、良かったです。
ちなみに、先のご説明の中で、void InitConfig(unsigned long *config) に渡すところを
LabVIEW上では、「要素数2000で、とりあえず値がゼロ」の「I32の配列」を渡せばよい、
と書きましたが、「I32の配列」ではなくて、「U32の配列」、でした・・・ (unsignedですので、、、)
念のため、訂正いたします。