COMと.NETのブリッジ(二)COMサーバーを接続するP/Invoke方式
5458 ワード
転載:VC知識庫
http://www.vckbase.com/document/viewdoc/?id=1622
COMと.NETをつなぐブリッジ(二)COMサーバーのP/Invoke方式の作者:caeser 2 ソースコードをダウンロード、COMサーバー->COMクライアントは伝統的なCOM知識です.この部分がよく分からないなら、楊先生の個人欄を見に行きます.そこに素晴らしい教えがあります.ここで無駄話をしません.詳しくは言いませんが、この部分が重要ではないということです.逆に、読者がこの部分に詳しいと、後のすべての内容は形式的に伝統的なCOM呼び出しを模倣していることが分かります.二、COMサーバー-->.netクライアントはうん、これがポイントです.下図はこの部分の原理です.各COMオブジェクトはいずれもありますが、どれだけの引用があってもパッケージ(RCW)エージェントを呼び出すことができます.公開インターフェースがない(あるいは全くない)場合に使う操作はP/Invokeです.私たちは少なくとも次の二つの内容を知っています. DLLファイルの名前 は、呼び出す関数の名前または番号を指定します.次に次の2つのステップを行う必要があります. .netプログラムでそれを識別するには、静的で外部的な でなければならない. C++このようにします:extern“C”;普通の関数を呼び出すように呼び出します. パラメータに注意してください.構造またはクラスであれば、内部メンバはpublicと定義しなければならないことに注意して、公開することができない. はいくつかの属性を適用して「個性化」を実現できます.詳細は以下の「個性化」属性コードを参照してください. 呼び出したい関数がたくさんある場合、またはこの関数を委託管理クラスのメンバーにしたい場合は、包装類を使うことができます.は、DLL関数を直接既存のクラスで宣言する. は、関数を相互に分離し、検索しやすくし、それぞれのDLL関数のクラスを作成することができる. は、論理グループを形成し、システムオーバーヘッドを低減するために、関連するDLL関数のセットを1つのクラスに書き込むことができる. サンプルコードを見に来ました.まず簡単な呼び出しステップのデモンストレーションを行い、Win 32 APIから提供されたMessageBoxを呼び出します.
http://www.vckbase.com/document/viewdoc/?id=1622
COMと.NETをつなぐブリッジ(二)COMサーバーのP/Invoke方式の作者:caeser 2 ソースコードをダウンロード、COMサーバー->COMクライアントは伝統的なCOM知識です.この部分がよく分からないなら、楊先生の個人欄を見に行きます.そこに素晴らしい教えがあります.ここで無駄話をしません.詳しくは言いませんが、この部分が重要ではないということです.逆に、読者がこの部分に詳しいと、後のすべての内容は形式的に伝統的なCOM呼び出しを模倣していることが分かります.二、COMサーバー-->.netクライアントはうん、これがポイントです.下図はこの部分の原理です.各COMオブジェクトはいずれもありますが、どれだけの引用があってもパッケージ(RCW)エージェントを呼び出すことができます.公開インターフェースがない(あるいは全くない)場合に使う操作はP/Invokeです.私たちは少なくとも次の二つの内容を知っています.
//1.
using namespace System::Runtime::InteropServices;
typedef IntPtr HWND; // void * ,win32 4 , int
//2. DllImport ( DllImportAttribute )"#import" DLL ,
[DllImport("user32", EntryPoint="MessageBoxA")]
//3. ,
extern "C" int MsgBox(HWND hWnd,String* pText,String* pCaption,unsigned int uType);
//4.
MsgBox(this->Handle,"hello","hi",0);
//5. , , ^_^
public __gc class SDKMsgBox: {
public:
[DllImport("user32", EntryPoint="MessageBoxA")]
extern "C" int MsgBox(HWND hWnd,String* pText,String* pCaption,unsigned int uType);
.......
}
は、伝達された値が配列、構造またはクラスであれば、そんなに簡単ではありません.カスタムパッケージ(Marsharl、カスタムタイプ変換)// , ,
extern "C" void SendArray(
[MarshalAs(UnmanagedType::LPArray)]Array<int> list,
int length
);
/*
, ,User32.dll
BOOL PtInRect(const RECT *lprc, POINT pt);
RECT Point
, Point __value __gc, .net v1.1 ( ,
.net v1.1 Bug), ( __box
), (String *) 。
*/
//StructLayout StructLayoutAttribute ,
//Sequential
[StructLayout(LayoutKind::Sequential)]
public __value struct Point {
public:
int x;
int y;
};
//Explicit FieldOffset( FieldOffsetAttribute )
[StructLayout(LayoutKind::Explicit)]
public __gc struct Rect {
public:
[FieldOffset(0)] int left; //FieldOffset() ,
[FieldOffset(4)] int top; // , int, +4
[FieldOffset(8)] int right;
[FieldOffset(12)] int bottom;
};
[DllImport("User32.dll")]
extern "C" bool PtInRect(const Rect& r, Point p);// 1 1
/*
COM char *text,
[StructLayout(LayoutKind::Sequential,CharSet=CharSet::Ansi)]
... ( ... , String *text);
*/
}
のような伝達方法が必要です.自然は構造の伝達方法と同じである.ただし、クラスを伝達する際には通常、少なくとも1つのレベルが間接的にアドレス指定されます.つまり、ポインタ(上記の例のRectと同じ)が必要です./*
,Kernel32.dll
void GetSystemTime(SYSTEMTIME* SystemTime);
SYSTEMTIME , “ ” ^_^
*/
[StructLayout(LayoutKind::Sequential)]
public __gc class MySystemTime {
public:
unsigned short wYear;
unsigned short wMonth;
unsigned short wDayOfWeek;
unsigned short wDay;
unsigned short wHour;
unsigned short wMinute;
unsigned short wSecond;
unsigned short wMilliseconds;
};
[DllImport("Kernel32.dll")]
extern "C" void GetSystemTime(MySystemTime& st);
は、コールバック関数を使用したいなら、さらに面倒であり、依頼/イベント機構を用いてメッセージを受信する必要がある.using namespace System::Runtime::InteropServices;
//
__delegate bool CallBack(int hwnd, int lParam);
[DllImport("user32")]
extern "C" int EnumWindows(CallBack* x, int y); // CallBack ,
// ,
bool Report(int hwnd, int lParam) {
System::Diagnostics::Trace::WriteLine(hwnd.ToString(),"Window handle is:");
return true;
};
//
// myCallBack
CallBack* myCallBack = new CallBack(this, &EnumReport::Report);
EnumWindows(myCallBack, 0); // ( ) COM ,COM
バックインターフェースや接続点を使いたいなら、本節のタイトルをよく見てください.インタフェースがないです.どうすればいいですか?へへはい、P/Invokeはそろそろできるのはこれだけです.役に立つ表を並べました.いくつかのよく使われているWin 32 API DLLの利用可能な属性は、通常はDllImport Attribute(DllImport)を使用して値を設定しています.この節の多くの内容はMSDN 2003以上のバージョンの「非委託DLL関数を使用して」で見つけることができます.「個性」化された封送処理(COMサーバーのみ->.netクライアント)は、「プラットフォームで封送データを呼び出す」を参照してください.プラットフォームの呼び出しはP/Invokeです.