- リンクを取得
- ×
- メール
- 他のアプリ
- リンクを取得
- ×
- メール
- 他のアプリ
サンプルプロジェクト (C++, LabVIEW のプロジェクト)
前回から時間が空いてしまいましたが、ブログを更新。
更新してなかったですが、何もしていなかったわけではなく Windows8 やもちろん LabVIEW とも毎日のように戯れていました。
前回で、LabVIEWから DLL 内の関数を呼ぶことが出来ましたが、今回はクラスライブラリを呼びたいと思います。
【前回】LabVIEW から呼ぶことが出来る DLL を生成する(C++)
http://mikioblog.dolphinsystem.jp/2012/05/labview-dll-c.html
【】LabVIEW から呼ぶことが出来る DLL を生成する(クラスライブラリ)
http://mikioblog.dolphinsystem.jp/2012/05/labview-dll.html
関数とクラスライブラリの違い
当たり前の話ですが「関数を呼ぶ」というのは、C の関数を呼ぶと言うことです。
関数にパラメータを与えて、演算結果を返してもらう分にはこれで十分ですね。
しかし C++ 側でクラスが作ってあって、そのメソッドを LabVIEW で呼びたい場合はどうすればいいのでしょうか?
通常クラスライブラリを使うときは、
- クラスのインスタンスを生成
- そのインスタンスのメソッド(関数)を呼ぶ。
- 戻り値は、メソッドから返される場合もあれば、クラス内に保持される場合もある。
という流れで行ないます。
しかし LabVIEW ではあくまで呼べるのは関数ベースです。
クラスライブラリを呼ぶ方法
LabVIEW からは関数しか呼べません。と言うことは関数経由でクラス生成し、メソッドを呼べば良いことになります。
上記の 1. 2. 3. をクリアする方法を考えてみます。
1 のインスタンスを生成。
まずクラスのインスタンスはポインタな訳ですから、関数の中でクラスを生成し、そのポインタを LabVIEW 返すことでインスタンスの生成は出来そうです。
で、「ライブラリ関数の呼び出しノード」を見てみると、データタイプに「符号付きポインタサイズ整数」があります。プロトタイプで見てみると intptr_t なので、ポインタを受けることは出来そうです。
2 のメソッドを呼ぶ。
「ライブラリ関数の呼び出しノード」のパラメータを見てみると、渡すことが出来るデータタイプに「符号付きポインタサイズ整数」がありますので、取得したポインタを渡すことが出来ます。
では、関数にインスタンスのポインタを渡して、その中でメソッドを呼び、戻り値を受けることが出来そうです。
3 クラス内部の値を受け取る
これも「ライブラリ関数の呼び出しノード」にポインタを渡して、クラス内部の値を返してやれば良さそうです。
クラスライブラリを作る
では早速クラスを呼ぶための準備をします。
クラスを追加する
まずはクラスライブラリを作るために、Visual Studio でクラスを追加します。
クラス名は TestClass で生成すると、TestClass.cpp, TestClass.h がプロジェクトに追加されます。
クラスを実装する
TestClass の仕様は、
- クラスメンバ変数として int value を持っている。
- Add メソッドに渡された値と value を足し算する。
- Sub メソッドに渡された値と value を引き算する。
- 足し引きしないで値を設定・取得する
という簡単なクラスにします。
以下実装。
class __declspec(dllexport) は、関数を公開するのと同じく、DLL 内のクラスを外部に公開するために必要な定義です。これを忘れると外部から読んでもエラーになりますので、注意が必要です。
TestClass.h
#pragma once
class __declspec(dllexport) TestClass
{
public:
int value;
TestClass(void);
~TestClass(void);
void Set(int value);
int Get();
int Add(int value);
int Sub(int value);
};
TestClass.cpp
#include "StdAfx.h"
#include "TestClass.h"
TestClass::TestClass(void)
{
this->value = 0;
}
TestClass::~TestClass(void)
{
}
void TestClass::Set(int value)
{
this->value = value;
}
int TestClass::Get()
{
return this->value;
}
int TestClass::Add(int value)
{
this->value += value;
return this->value;
}
int TestClass::Sub(int value)
{
this->value -= value;
return this->value;
}
クラスのインターフェイスを実装する
クラスが出来たら、LabVIEW からクラスを呼ぶためのインターフェイス関数を作成します。
Visual Studio で、cpp ファイル "LVIF_TestClass.cpp" という名前で追加します。
コードは以下の通り。
#include "StdAfx.h"
#include "TestClass.h"
_declspec(dllexport) TestClass* LVIF_TestClass_GetInstance()
{
TestClass *param = new TestClass();
return param;
}
_declspec(dllexport) void LVIF_TestClass_Delete(TestClass *arg)
{
delete arg;
}
_declspec(dllexport) void LVIF_TestClass_Set(TestClass *arg, int value)
{
return arg->Set(value);
}
_declspec(dllexport) int LVIF_TestClass_Get(TestClass *arg)
{
return arg->Get();
}
_declspec(dllexport) int LVIF_TestClass_Add(TestClass *arg, int value)
{
return arg->Add(value);
}
_declspec(dllexport) int LVIF_TestClass_Sub(TestClass *arg, int value)
{
return arg->Sub(value);
}
- インスタンスを作成しポインタを返す LVIF_TestClass_GetInstance 関数と、
- 値を設定・取得する LVIF_TestClass_Get, LVIF_TestClass_Set 関数、
- Add, Sub メソッドに対応した LVIF_TestClass_Add, LVIF_TestClass_Sub 関数、
- インスタンスを削除する LVIF_TestClass_Delete 関数
を用意しました。
それぞれ _declspec(dllexport) をつけておきます。
クラスを LabVIEW から呼ぶ
インスタンスの生成
DLL が出来たら、次に LabVIEW からクラスを呼んでみます。まずはインスタンスの生成から。
VI を作成し「ライブラリ関数の呼び出しノード」をブロックダイアグラム上に配置します。右クリック→構成ダイアログで、作成した DLL を選択。
関数名を見ると、先ほどのインターフェイス関数が見えてますね。
まずは GetInstance を選択します。
返り値で、符号付きポインタサイズ整数を選択。
これを実行してみると、何か値が返ってきました。
これが TestClass のポインタですね。
メソッドを呼ぶ
では次に Get, Set をして値を初期化します。
新しい「ライブラリ関数の呼び出しノード」ので、Set 関数を選択。
Set 関数は void のため返り値はデフォルト(void) のまま。
最初の引数でクラスのポインタを渡します。「パス」は必ず「値」を選択します。
2番目の引数で設定する int32 値にしておきます。
Get 関数はこちらのように、int32 を受け取ります。arg1 は Set 関数と同じくポインタを指定しておきます。
実行するとこのように、値を 1 で初期化できました。また生成したポインタと、Set/Get 関数で使用したポインタが同じ事も確認できました。
では次に Add/Sub 関数も足してみたら結果はこの通り、0 で初期化→1を100回加算→1を100回減算→結果 0 という一連の流れをクラスで実行させることが出来ました。
デバッグ方法
このクラスライブラリ呼び出し時に DLL にブレークポイントをしたい場合は、Visual Studio でプロセスにアタッチをすれば可能です。
まずデバッグビルドで DLL を作成し、LabVIEW 側で VI を起動します。
そうしたら Visual Studio のメニュー→デバッグ→プロセスにアタッチ→ LabVIEW.exe を選択し、アタッチボタンを押します。
これでソースコードにブレイクポイントをつけておけば、DLL 実行時にそこで実行が停止しステップ実行など出来ます。
はまり所
c側からの戻り値が bool の場合、LabVIEW で「符号付き8ビット整数」を選択します。32ビットだと戻り値がおかしくなります。
まとめ
- クラスのコンストラクタ、メソッドを呼ぶ関数を別途作成する。
- クラスのインスタンスポインタを LabVIEW 側で保持することで、クラスの生成・実行は可能
- インスタンスの削除を忘れないように
- 戻り値の bool は注意。
以上、ドルフィンシステム福島でした。
コメント
コメントを投稿