ZT: .NET Interop入门-P/Invoke和Reverse P/Invoke 

文章内容

最近在论坛上经常看到一些基本的interop的问题,给我动力写完之前的.net interop入门系列,给刚刚涉足.NET interop的朋友们一个大体上的概念。

每每谈及.NET interop,我的脑中总是出现下面一幅图:



该图代表了.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 <stdio.h>
#include <wtypes.h>

extern "C" {
    __declspec(dllexport) void NativeMethod(void (__stdcall *pShowMsgBox)(WCHAR *wChar))
    {
        (*pShowMsgBox)(L"hello reverse interop");
    }
}


注意到托管代码中的委托到了本地代码中,就是一个函数指针,本地代码可以像一个普通的函数指针一般调用托管代码。

大家可能注意到dll的声明用了extern “C”,它指明了调用规范是cdecl,在之前的托过代码的DllImport中,也相应的注明了调用约定,关于调用约定的详细介绍,可以参见我的另一篇博客。

今天的介绍就到这里,大家可以把这些示例代码当作一个template,根据实际需求作相应的具体改动。

Published Sunday, March 29, 2009 12:24 AM by SilverlightShanghai
Filed under: CLR Interop, .NET小贴士
QR Code
请用微信 扫一扫 扫描上面的二维码,然后点击页面右上角的 ... 图标,然后点击 发送给朋友分享到朋友圈,谢谢!
分享:
分享到微信

文章评论

Castro
无题
DING!

2009-04-05 23:19:17 | 引用
无题
不错。直接到他们的团队blog上看了看,东西不多不过他们自己开发的一个tool - TlmImp2挺不错的。可以直接调用COM库,然后生成Interop Assembly。

2009-06-07 09:54:10 | 引用
nessus
飞舞的音符
Re: ZT: .NET Interop入门-P/Invoke和Reverse P/Invoke
学习中。。。

2009-06-16 23:03:49 | 引用

发表评论

个人简介

webdriver
『人生游戏,游戏人生』


日志分类
最新日志
此功能已被空间主人关闭
博客搜索
 
快速导航
友情链接
此功能已被空间主人关闭
博客统计
点击: 700966
帖子数量: 691
开辟个人空间: 2008-10-15
最后更新: 2018-05-11
左邻右舍
还没有任何会员到访.
 
 
 
 
 
The images, logos, trademarks used on this site and all forwarded content are the property of their respective owners.
We are not responsible for comments posted by our visitors, as they are the property of the poster.
All other content of this website is copyrighted by 加西网

Private Policy | moonlake oblog skin

加西网为北美中文网传媒集团旗下网站