.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