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を呼び出します.
    //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です.