[学习笔记] .NET Interop入门-P/Invoke和Reverse P/Invoke

[学习笔记] .NET Interop入门-P/Invoke和Reverse P/Invoke  


[学习笔记] .NET Interop入门-P/Invoke和Reverse P/Invoke_第1张图片

该图代表了.net interop的四个典型场景。之前我的同事和我讨论了.NET和COM互操作的应用:

在.NET中调用COM:COM Interop入门
在COM中调用.NET:在COM应用中使用.NET组件,使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法。
今天我主要讲一下P/Invoke和Reverse P/Invoke,和COM interop相比,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);
    }
}稍加解释这个代码。类PInvoke中,有个MessageBoxW的函数声明,它的实现在user32.dll(系统自带)中,入口是MessageBoxW,参数的构成是根据windows API的声明而定的,我们在Codeplex上有一个工具,专门帮助大家声称一个本地代码(c++)编写的函数在托过代码(c#)中的函数声明,之前我们团队的成员也撰文介绍了这个工具的使用。

有了这个声明以后,在Main中调用MessageBox,就和调用其他托管代码一样轻松自如了。

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
#include

extern "C" {
    __declspec(dllexport) void NativeMethod(void (__stdcall *pShowMsgBox)(WCHAR *wChar))
    {
        (*pShowMsgBox)(L"hello reverse interop");
    }
}
注意到托管代码中的委托到了本地代码中,就是一个函数指针,本地代码可以像一个普通的函数指针一般调用托管代码。


你可能感兴趣的:(.net,String,C#,user,工具,Interop)