![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
現在、Visual Studio 2005の、Visual C#、C++/CLI、MFCを使ったシステムを構築しています。
具体的には、MFCで書かれたライブラリ(DLL)をC++/CLIでラップし、C#から呼び出して使うというものです。
現在は、http://www.atmarkit.co.jp/fdotnet/special/vcppin …
http://msdn2.microsoft.com/ja-jp/library/ac7ay12 …
これらのサイトを参考にしながら、一部のMFCで書かれたメソッドを、C#から呼び出すことに成功しました。しかし、int型やHANDLE型などの、上記サイトに記述されているデータ型を用いたメソッドのラッピングや呼び出しはできたのですが、HDCやLPRECTなどの特殊な型の場合のやり方がよく分かりません。
具体的に現在分からないのは、次の通りです。
HDC(デバイスコンテキスト)、HWND(ウィンドウのハンドル)、CIRCLE,RECT等の構造体、LPRECTなどの構造体のアドレス、POINT*などの構造体のポインタ
これらが、C#やCLIでどのような型になるのか、メソッドに渡す時にどのように記述するのかが分かりません。
以上、どなたか分かる方いらっしゃいましたら、ご回答をお願いします。
No.3ベストアンサー
- 回答日時:
> DLLのリンクはIJW機構というものを使用して
そのようですね、勉強不足で申し訳ありません。
>> RECT lprcDC, lprcDib;
>
>> return dllfunction(hDC, lprcDC, hDib, lprcDib);
> --------------------------------------------------------------
> この記述ですと、lprcDCとlprcDibがポインタに変換されていないと思う
> のですが、これは記述ミスでしょうか?
DllImport でマネージドとアンマネージドに変換されるので構造体を含め
C++/CLI のマネージドコードで記述してます。
# 他のと同じように lp- というプリフィクスにしたのが誤解を招いたかも
# 知れないです。
念のために拙いコードなのですが、 C# の GUI でコードを書いて動作
確認をしてみました。
TestDll.dll 側の関数実装には TextDraw と Bitblt を記述して任意の
文字列を bmp1(C#) の HDC に描画して bmp2(C#) の HDC には Bitblt で
bmp1(C#) の HDC を反転したものを転送するようにしました。
TextDraw と BitBlt のどちらかで失敗した場合はその時点で FALSE を
返すようになっています。
HANDLE は void* の typdef なので HDC にキャストしました。
TestDll.dll にポインタが確実に渡っているか調べるのだけならそれで
問題ないのではないかと思いましたので。
------------- 呼出用プログラム(C#) --------------
// PictureBox サイズの Bitmap を作成
Bitmap bmp1 = new Bitmap(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height);
Bitmap bmp2 = new Bitmap(pictureBox2.ClientSize.Width,
pictureBox2.ClientSize.Height);
// Bitmap から Graphics を得る
Graphics g1 = Graphics.FromImage(bmp1);
Graphics g2 = Graphics.FromImage(bmp2);
// Graphics から HDC を得る
IntPtr hDC = g1.GetHdc();
IntPtr hDBI = g2.GetHdc();
// DLL 呼び出し
if (!wrapper.function(hDC, pictureBox1.ClientRectangle,
hDBI, pictureBox2.ClientRectangle)
)
MessageBox.Show("失敗");
// PictureBox へ描画
pictureBox1.Image = bmp1;
pictureBox2.Image = bmp2;
g1.ReleaseHdc();
g2.ReleaseHdc();
その他の部分は ANo.2 に記述したものと同じです。
----------------------------------------------------
それと、一点お尋ねしたいのですが
> BOOL result = Mvc10_PaintDIB( (HDC)hDC.ToPointer(), LPrcDC , (HANDLE)hDib.ToInt32(), LPrcDib );
HANDLE は typedef void* かと思うのですが hDib.ToInt32() として
hDib.ToPointer() としてないのは何か理由があってのことでしょうか?
# こちらで試したところ ToPointer() でも ToInt32() でも動作する
# ようですし、立ち入ったことであれば申し訳ないですので、流して
# ください。
> 実際に使用してみての結果は後日報告させていただきたいと思います。
無事に動作されることをお祈りいたします。
自己解決されておられるようで、お役に立てなくて申し訳ありませんでした。
ご回答ありがとうございます。
>DllImport でマネージドとアンマネージドに変換されるので構造体を含めC++/CLI のマネージドコードで記述してます。
[DllImport("TestDll.dll")]
bool dllfunction(IntPtr hDC, RECT %lprcDC, IntPtr hDib, RECT %lprcDib);
ここでアドレスを渡していたのですね。見落としていました。
>HANDLE は typedef void* かと思うのですが hDib.ToInt32() として
>hDib.ToPointer() としてないのは何か理由があってのことでしょうか?
すいません。これは記述ミスですね。他のメソッドでは.ToPointer()としていました。HWND型の場合は.ToInt32()とするらしい(どこかのサイトに書いてありました)ので、それと混同していたのだと思います。
>自己解決されておられるようで、お役に立てなくて申し訳ありませんでした。
いえいえ、大変参考になりました。さらに、動作確認までしていただいてありがとうございます。
No.2
- 回答日時:
どうもすみません、MFC DLL を C++ でラップしたかったのでしたね?
C# から DllImport で直接呼び出せば手間が省けてよろしいかと思いましたで。
> 渡されたRECT構造体をLPRECT型に変換
LP は long pointer (32 ビットポインタ)の略なので「RECT *rc」として
も可能です。
マイクロソフトの流儀にするなら「#define LPRECT RECT* 」でしょうけど
windef.h の定義だと RECTtag をポインタにしているだけかと思います。
> これで合っているのでしょうか?
DllImport の記載を省略されているのであれば、よろしいかと思います。
あまり参考にはならないかもしれないですが、コード書いてみました。
ちゃんと動作確認はしてないです、すみません。
もっと良い方法があると思いますが、一般人ですのでご容赦ください。
こんな感じにすれば、C# からラッパー用 DLL を参照するだけで使えるかと
思うのですが? いかがでしょうか?
※ インデントに全角文字が使ってあります。
------------- TestDll.dll DLL(MFC) --------------
// TestDll.h プロトタイプ
public:
static BOLL dllfunction(HDC hDC, LPRECT lprcDC, HANDLE hDib, LPRECT lprcDib);
// TestDll.def に エクスポート関数名追加
EXPORTS
dllfunction
------------- DllWrapper.dll ラッパー用 DLL(CLI+C++) --------------
// using namespace 部分に追記
using namespace System::Drawing; // 参照で System.Drawing 追加
using namespace System::Runtime::InteropServices;
struct RECT
{
int left;
int top;
int right;
int bottom;
};
[DllImport("TestDll.dll")]
bool dllfunction(IntPtr hDC, RECT %lprcDC, IntPtr hDib, RECT %lprcDib);
namespace DllWrapper {
public ref class WrapperClass
{
public:
static bool func(IntPtr hDC, Rectangle ^rcDC, IntPtr hDib, Rectangle ^rcDib) {
RECT lprcDC, lprcDib;
lprcDC.top = rcDC->Top;
lprcDC.left = rcDC->Left;
lprcDC.bottom = rcDC->Bottom;
lprcDC.right = rcDC->Right;
lprcDib.top = rcDib->Top;
lprcDib.left = rcDib->Left;
lprcDib.bottom = rcDib->Bottom;
lprcDib.right = rcDib->Right;
return dllfunction(hDC, lprcDC, hDib, lprcDib);
}
};
}
------------- 呼出用プログラム(C#) --------------
using DllWrapper; // 参照に DllWrapper.dll 追加
// IntPtr hDC, hDIB
// Rectangle rcDC, rcDib
WrapperClass.function(hDC, rcDC, hDIB, rcDib);
-------------------------------------------------
また、既知かも知れませんが DllImport せずに C++/CLI にネイティブ
コードを取り込む方法もあるようです。
@IT:特集:Visual C++ 2005 いままたC++が熱い!「C++/CLI」として大進化したVisual C++ 2005
http://www.atmarkit.co.jp/fdotnet/special/cppcli …
この回答への補足
ハードウェアの環境が整い、動作確認を行ったので、結果を報告させていただきます。
すべてのメソッドの動作を確認したわけではないのですが、構造体やハンドルを引数に持つメソッドを呼び出して確認したところ、きちんと動作していることが確認されました。
これで、開発が進められそうです。色々とアドバイスいただき、ありがとうございました。
ご回答ありがとうございます。
>DllImport の記載を省略されているのであれば、よろしいかと思います。
DLLのリンクはIJW機構というものを使用して、ヘッダのインクルードと、ライブラリファイルのリンクをするだけでOKなようです。
http://msdn2.microsoft.com/ja-jp/library/ms23528 …
また、MFCのRECT構造体やなども、 #include <afxwin.h> をStdafx.hに記述することで使用可能なようです。
------------------------------------------------------------
> RECT lprcDC, lprcDib;
> return dllfunction(hDC, lprcDC, hDib, lprcDib);
--------------------------------------------------------------
この記述ですと、lprcDCとlprcDibがポインタに変換されていないと思うのですが、これは記述ミスでしょうか?
あと、以前記述したものだと、lprcDCやlprcDibに別の値などが代入された場合に、呼び出しもとの変数が変更されないと思われるので、以下のような記述を追加しました。
--------------------------------------------------------------
//関数を呼び出し、結果を格納
BOOL result = Mvc10_PaintDIB( (HDC)hDC.ToPointer(), LPrcDC , (HANDLE)hDib.ToInt32(), LPrcDib );
//渡した構造体の値が変更された場合を考えて、渡された引数に値を格納しなおす
lprcDC.top = rcDC.top;
lprcDC.bottom = rcDC.bottom;
lprcDC.left= rcDC.left;
lprcDC.right = rcDC.right;
lprcDC.top = rcDC.top;
lprcDC.bottom = rcDC.bottom;
lprcDC.left= rcDC.left;
lprcDC.right = rcDC.right;
//結果を返す
if(result == FALSE){ return false; }
else{ return true; }
--------------------------------------------------------------
一応これで、エラー、警告無くコンパイルが通ったので、これで試してみようと思います。まだ、実際に試せない(訳あってハードウェアなどの環境が整っていない)ので、実際に使用してみての結果は後日報告させていただきたいと思います。
No.1
- 回答日時:
> これらのサイトを参考にしながら
と仰せられるのなら、以下の記述は的外れで無礼かも知れませんので
その節はご容赦ください。
> HDC(デバイスコンテキスト)、HWND(ウィンドウのハンドル)、
C# から HDC, HWND を使う場合 IntPtr を用います。
> CIRCLE,RECT等の構造体、LPRECTなどの構造体のアドレス、
> POINT*などの構造体のポインタ
> これらが、C#やCLIでどのような型になるのか
Windows API の RECT 構造体を例として話をすすめますが
RECT 構造体は「[StructLayout(LayoutKind.Sequential)]」を
書いてから自前で定義する必要があります。
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
LPRECT などは ref RECT として渡します。
参考になりそうな URL
http://www.atmarkit.co.jp/fdotnet/dotnettips/026 …
C#, VB.NET で API を使用する構造体や関数呼出等の定義
(C# との型の変換について参考になれば宜しいかと)
http://www.pinvoke.net/
ご回答ありがとうございます。教えていただいた内容を元にコードをかいてみました。
C++/CLIの実装部分で、渡されたRECT構造体をLPRECT型に変換する方法が分からなかったので、一度MFCのRECT型変数を作成してから、LPRECT型の変数にアドレスを渡してみました。これで合っているのでしょうか?
----MFCで書かれたメソッド----------------------------------
BOOL function( HDC hDC, LPRECT lprcDC, HANDLE hDib, LPRECT lprcDib );
-----------------------------------------------------------
----C#インタフェイス部分-----------------------------------
bool Function(IntPtr hDC, ref SoccerStruct.RECT lprcDC, IntPtr hDib, ref SoccerStruct.RECT lprcDib );
-----------------------------------------------------------
----C++/CLI宣言部分----------------------------------------
virtual bool Function( IntPtr hDC, SoccerStruct::RECT% lprcDC, IntPtr hDib, SoccerStruct::RECT% lprcDib );
-----------------------------------------------------------
----C++/CLI実装部分----------------------------------------
bool DocumentClass::Function(IntPtr hDC, SoccerStruct::RECT% lprcDC, IntPtr hDib, SoccerStruct::RECT% lprcDib )
{
RECT rcDC;
rcDC.top=lprcDC.top;
rcDC.bottom = lprcDC.bottom;
rcDC.left= lprcDC.left;
rcDC.right = lprcDC.right;
RECT rcDib;
rcDib.top = lprcDib.top;
rcDib.bottom = lprcDib.bottom;
rcDib.left = lprcDib.left;
rcDib.right = lprcDib.right;
LPRECT LPrcDC = &rcDC;
LPRECT LPrcDib = &rcDib;
if( function( (HDC)hDC.ToPointer(), LPrcDC, (HANDLE)hDib.ToInt32(), LPrcDib ) == FALSE )
{
return false;
}
else
{
return true;
}
}
-----------------------------------------------------------
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
セグメントエラー
-
fopne で失敗する原因
-
init関数の意味
-
戻り値で構造体を返すことは可...
-
LPSTR型の初期化について
-
C++ vectorのbeginについて
-
【C言語】戻り値が構造体の関数
-
ExcelVBAでのkernel32(64bit)
-
CopyMemory()をmemcpy()に書き...
-
VC++6.0 MFC ダイアログバーを...
-
Run-Time Check Failure #3とい...
-
C言語の文字列?処理 strcpyやl...
-
ハンドル、アドレス、ポインタ...
-
参照型で受け取った引数をポイ...
-
どうしてエラーになるかわかり...
-
ダイアログから、ドキュメント...
-
C言語のポインタの価値
-
単方向リストの解釈
-
構造体内のポインタのポインタ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語のポインタに直接アドレス...
-
init関数の意味
-
セグメントエラー
-
fopne で失敗する原因
-
戻り値で構造体を返すことは可...
-
Run-Time Check Failure #3とい...
-
ExcelVBAでのkernel32(64bit)
-
LPSTR型の初期化について
-
C言語でのconstを返す関数
-
ハンドルはポインタか
-
【C言語】戻り値が構造体の関数
-
nullポインタを逆参照とは?
-
基本アルゴリズムの『返す』の...
-
参照型で受け取った引数をポイ...
-
#define NULL ((void *)0) の弊害
-
アプリを32bitから64bit移行
-
ハンドル、アドレス、ポインタ...
-
デバイスハンドルとは?
-
C++で関数ポインタから関数名を...
-
Cで作成したDLL関数をVBから呼...
おすすめ情報