Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
最近在论坛上经常看到一些基本的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,根据实际需求作相应的具体改动。
Comments
Anonymous
August 25, 2009
请问在SL3里面,针对图片处理是否可以启用GPU加速功能, 根据网上搜索到的资料,设置启用GPU后,对流媒体有加速, 但对图片处理没什么效果,请问具体怎么设置图片的GPU加速 因为用SL做webgame时候,这个功能很重要,否则性能提不上去的Anonymous
October 09, 2010
怎么样发表blog呀在msdn上