在编程世界中,简洁与效率往往被视为至高无上的追求。,作为一个崇尚简洁的程序员,自然对那些复杂且不自然的事物抱有反感。P/Invoke就是这样一种让感到不悦的技术。它不仅丑陋,而且使用起来极其复杂。然而,当读到Nick Hodapp的话时,想法开始发生了转变。
Nick Hodapp,一位来自微软的专家,曾这样评价Managed C++中的IJW技术:“在C++中使用IJW比P/Invoke语法更简单,而且,如所说,性能稍微更好。” 这句话立刻引起了注意。首先,意识到“performant”这个词虽然在英语字典中找不到,但却能清楚地理解Nick Hodapp所要表达的意思。其次,发现自己并不知道IJW的含义。直到后来才明白,IJW实际上就是“It just works”的缩写。在试用了IJW之后,不禁大声赞叹:“它确实有效!”因为它真的有效,而且不像P/Invoke那样丑陋和不自然。正如Nick Hodapp所说,它在性能上略胜一筹。
使用IJW非常简单,只需要包含所需的C++头文件即可。当然,这样做可能会遇到头文件中定义的名称与.NET框架类及其成员函数之间的名称冲突。就是在遇到成百上千的编译错误后,才痛苦地意识到这一点。所有的错误信息都指向了同一个问题:“error C2872: 'blahblahblah' : ambiguous symbol”。这对来说是一个相当令人烦恼的情况。经过几分钟的思考,终于明白了,需要在所有的using namespace指令之前包含头文件。
与P/Invoke不同,P/Invoke中.NET类型和本地类型之间的所有数据封送都是由编译器完成的,而在这里必须自己来做。一旦查看了框架中的System.Runtime.InteropServices.Marshal类,会发现这并不是一个复杂的问题。这个类非常出色,提供了许多有用的函数。
让直接来看一些示例代码。在下面列出的小程序中,将展示如何创建一个托管类,该类可以从托管代码块中实例化,并且使用IJW调用本地API调用。将看到,与P/Invoke代码相比,这看起来要优雅得多。
以下是使用Managed C++创建的一个简单示例,展示了如何使用IJW技术调用本地API。
#include "stdafx.h"
#using <mscorlib.dll>
#include <tchar.h>
#include <windows.h>
using namespace System;
using namespace System::Runtime::InteropServices;
public __gc class MsgBox
{
public:
MsgBox(String *str)
{
IntPtr ptrtxt = Marshal::StringToCoTaskMemUni(str);
MessageBoxW(0, (LPCWSTR)ptrtxt.ToPointer(), L"IJW is cool", 0);
Marshal::FreeCoTaskMem(ptrtxt);
}
};
int _tmain(void)
{
String *str;
str = "Nish was here";
MsgBox *m_msgbox = new MsgBox(str);
return 0;
}