天天看點

P/Invoke和Reverse P/Invoke

.Net與動态連結庫、COM元件的關系大緻如下:

P/Invoke和Reverse P/Invoke

1. P/Invoke

P/Invoke(platform invoke)是.NET調用本地代碼(native code)的一種比較輕便的方式。隻需要将本地代碼編寫成動态連結庫,然後在c#代碼中,聲明一個外部靜态函數,并且用DllImport屬性指明動态連接配接庫的入口。舉例如下:

using
 System;

using
 System.Runtime.InteropServices;



class
 PInvoke

{

    [DllImportAttribute("user32.dll"
, EntryPoint = "MessageBoxW"
)]

    public
 static
 extern
  int
 MessageBoxW(

        [In]System.IntPtr hWnd,

        [In][MarshalAs(UnmanagedType.LPWStr)] string
 lpText,

        [In][MarshalAs(UnmanagedType.LPWStr)] string
 lpCaption,

        uint
 uType);



    public
 static
 void
 Main()

    {

        MessageBoxW(IntPtr.Zero, "Hello"
, "Interop"
, 0);

    }

}

MessageBoxW是一個在user32.dll中已經實作了的函數,這裡隻需要聲明一下它,然後就可以調用了
           

2. Reverse P/Invoke

接着,我們來看看在本地代碼中調用.NET方法。本地代碼需要拿到一個.NET委托(delegate),然後把這個delegate當作一個函數指針使用,示例如下:

using
 System;

using
 System.Windows.Forms;

using
 System.Runtime.InteropServices;



public
 class
 Program

{

    internal
 delegate
 void
 DelegateMessageBox([MarshalAs(UnmanagedType.LPWStr)]string
 msg);



    [DllImport("Native.dll"
, CallingConvention = CallingConvention.Cdecl)]

    static
 extern
 void
 NativeMethod(DelegateMessageBox d);



    public
 static
 void
 ShowMessageBox(string
 msg)

    {

       MessageBox.Show(msg);

    }



    public
 static
 void
 Main()

    {

        NativeMethod(new
 DelegateMessageBox(ShowMessageBox));

    }

}
           

這個例子中,我們希望本地代碼能夠調用托管函數ShowMessageBox來顯示一個對話框。為了讓本地代碼可以調用這個函數,我們根據它的聲明,定了了一個delegate,并且通過P/Invoke把這個委托傳給了本地代碼。本地代碼可以如下調用托管代碼:

#include
 <stdio.h>

#include
 <wtypes.h>



extern
 "C"
 {

    __declspec
(dllexport
) void
 NativeMethod(void
 (__stdcall
 *pShowMsgBox)(WCHAR *wChar))

    {

        (*pShowMsgBox)(L"hello reverse interop"
);

    }

}

           

注意到托管代碼中的委托到了本地代碼中,就是一個函數指針,本地代碼可以像一個普通的函數指針一般調用托管代碼。

——源文引自http://blogs.msdn.com/silverlightshanghai/archive/2009/03/29/net-interop-p-invoke-reverse-p-invoke.aspx

繼續閱讀