.Net與動态連結庫、COM元件的關系大緻如下:
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