- PR -

DLL内の関数の戻り値を構造体で受け取るには…。

投稿者投稿内容
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-16 18:14
お世話になっております。
優希です。

開発環境は、Visual Studio .NET 2002(VC++)、
Windowsフォームを使って行います。
本体のソースは、マネージコードで記述しています。


今回は、VC++5.0で作成したDLLとの
データ通信を行なっております。

呼び出したDLL内の関数の戻り値を構造体で受け取りたいのですが、
引用:

DllImport カスタム属性を持つ関数は、クラスのインスタンスを返せません。


と、コンパイルエラーになってしまいます。


逆に、
呼び出すDLL内の関数の引数に構造体を設定すると、
きちんと設定することができます。


呼び出したDLL内の関数の戻り値を構造体で受け取るには、
どのようにしたら良いのでしょうか?


以下がサンプルコードです。


まずは、DLL内(Sample.dll)の関数、
および戻り値となる構造体を記述しています。
コード:
///
/// 構造体
///
struct TestTbl{
    unsigned short Value1;
    unsigned short Value2;
};



コード:
///
/// 構造体を返す関数
///
NOMANGLE struct TestTbl CCONV  GetStructData()
{
	struct TestTbl tbl;
	tbl.Value1 = 123;
	tbl.Value2 = 456;
	
	return tbl;
}




次に、呼び出す側のサンプルコードです。

コード:
///
/// 構造体
///
[StructLayout(LayoutKind::Sequential)]
typedef public __value struct _Struct1
{
    UInt16 Value1;
    UInt16 Value2;
}Struct1;



コード:
///
/// DLLインポート
///
public __gc class SampleClass
{
public:
	[DllImport("Sample.dll")]
	static Struct1 GetStructData(); // ←エラーになる個所
}



コード:
///
/// データ取得関数
///
public __gc class GetData
{
	// 構造体の取得
	Struct1 tbl = SampleClass::GetStructData();
}



お気づきの点がありましたら、
宜しくお願い致します。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-17 08:56
コンパイルエラーになったところのヘルプを見ると、
以下のようになっています。

引用:

'class::function' : DllImport カスタム属性を持つ関数は、クラスのインスタンスを返せません。

DllImport 属性で指定された .dll ファイル内にある関数として定義されている関数は、クラスのインスタンスを返すことができません。

次のサンプルは C3385 を生成します。

// C3385.cpp
// compile with: /clr
#using <mscorlib.dll>

using namespace System;
using namespace System::Runtime::InteropServices;

struct SomeStruct1 {
};

public __gc struct Wrap {
[ DllImport("somedll.dll", CharSet=CharSet::Unicode) ]
static SomeStruct1 f1([In, Out] SomeStruct1 *pS); // C3385
};

int main()
{
}



やはり、構造体では無理なんでしょうか?
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-02-17 21:25
meiです。

引用:

優希さんの書き込み (2004-02-17 08:56) より:

やはり、構造体では無理なんでしょうか?


エラーメッセージからすると無理そうですね。
ただ、例え可能であっても、C++でDllImportを使うのはちょっと・・・と思います。

なぜなら、DllImportは遅いです。
例えば、DllImport経由で呼び出す関数に参照型(String等)を含んでいる場合は、
CILで31命令+マーシャリングコストがかかります。
ちなみに値型の場合は、8命令だそうです。

で、C++ネイティブ呼び出しはDllImportより速いはずなので、
少なく見積もっても5倍以上遅い方法を選択していることになります。
折角C++で最速な呼び出しが出来るのに勿体ないです。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-17 22:03
こんばんわ。
優希です。

引用:

なぜなら、DllImportは遅いです。
例えば、DllImport経由で呼び出す関数に参照型(String等)を含んでいる場合は、
CILで31命令+マーシャリングコストがかかります。
ちなみに値型の場合は、8命令だそうです。

で、C++ネイティブ呼び出しはDllImportより速いはずなので、
少なく見積もっても5倍以上遅い方法を選択していることになります。
折角C++で最速な呼び出しが出来るのに勿体ないです。



そうだったんですか。
アドバイス、ありがとうございます。
どおりで遅いはずでした。。。
分からず使っていた自分が情けない(−−;)


で、この間、meiさんがおっしゃっていた
引用:

#pragma comment(lib, "Sample.lib")
 :
 :



っていうやつですね?

xxxx.libを参照(?)ってことは、
このLIBファイルが必要になるんですね?
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-02-17 22:43
meiです。

引用:

優希さんの書き込み (2004-02-17 22:03) より:

xxxx.libを参照(?)ってことは、
このLIBファイルが必要になるんですね?


はい、そうです。
ライブラリパスが通っているところに置いてください。
LoadLibraryでDLL読み込むことも出来ますが、
LIBファイルがあるのなら、そっちの方が楽なので。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-17 23:48
こんばんわ。

引用:

ライブラリパスが通っているところに置いてください。
LoadLibraryでDLL読み込むことも出来ますが、
LIBファイルがあるのなら、そっちの方が楽なので。



・・・ってことは、DLLは使わないのですか?
一応、「DLLを使って」の作りになるので、
それはマズイかも。。。

LoadLibrary()関数を使う場合は、
LIBを参照する記述は、要らなくなるのでしょうね???(^^;)
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-02-18 00:08
引用:

優希さんの書き込み (2004-02-17 23:48) より:
・・・ってことは、DLLは使わないのですか?
一応、「DLLを使って」の作りになるので、
それはマズイかも。。。


いえいえ、実行時にDLLは使いますよ。
ビルド時にLIBを使って参照解決するか、
LoadLibraryで動的に関数ポインタ引っ張ってくるかという話です。
普通は何も考えずにLIBでリンクしてください。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-18 09:05
おはようございます。

あ、そうなんですか。(^^;)
LIBもDLLも必要ってことですね。

【参照】ってことは、
こんな感じ↓で宜しいのでしょうか?

------------------------------------------------
ライブラリ(xxx.lib)とインクルードファイル(xxx.h)を
それぞれ"Lib"、"include"フォルダに格納する。

VC++のメニュー[ツール]→[オプション]の
[プロジェクト]-[VC++ ディレクトリ]の
「ディレクトリを表示するプロジェクト:ライブラリ」で、
先ほどの「Lib」フォルダを追加。
同様に、「include」も追加する。
------------------------------------------------

もうちょっと詳しく調べてみます。
ありがとうございます。

スキルアップ/キャリアアップ(JOB@IT)