使用 C++ 互操作(隐式 PInvoke)
与其他 .NET 语言不同,Visual C++ 支持互操作性,允许托管代码和非托管代码存在于同一个应用程序中,甚至存在于同一个文件中(使用 managed, unmanaged 杂注)。 Visual C++ 开发人员可以通过此功能将 .NET 功能集成到现有 Visual C++ 应用程序中,而不会干扰该应用程序的其余部分。
还可以使用 dllexport, dllimport 从托管模块中调用非托管函数。
如果不需要指定封送函数参数的方式或显式调用 DllImportAttribute 时指定的任何其他详细信息,则隐式 PInvoke 非常有用。
Visual C++ 为托管函数和非托管函数提供了两种交互操作方式:
显式 PInvoke 受 .NET Framework 支持并且可用于大多数 .NET 语言。 但是顾名思义,C++ Interop 特定于 Visual C++。
C++ Interop
推荐使用 C++ Interop 而不是显式 PInvoke,因为 C++ Interop 提供更好的类型安全性,通常实现起来比较有趣,更为常用(如果修改非托管 API),并且可能会实现显式 PInvoke 不可能实现的性能增强。 但是,如果非托管源代码不可用或使用 /clr:safe 进行编译,则不可能使用 C++ Interop(有关更多信息,请参见 纯代码和可验证代码 (C++/CLI))。
C++ COM 互操作
在与 COM 组件进行交互操作方面,Visual C++ 支持的互操作性功能与其他 .NET 语言相比具有特别的优势。 C++ Interop 不受限于 .NET Framework Tlbimp.exe(类型库导入程序) 限制(如对数据类型的有限支持和强制公开每个 COM 接口的每个成员),而是允许随意访问 COM 组件,而且不需要单独的互操作程序集。 有关更多信息,请参见 Using COM from .NET。
可直接复制到本机结构中的类型
对于使用简单内部类型(请参见 可直接复制到本机结构中的类型和非直接复制到本机结构中的类型)的非托管 API 而言,无需特殊编码,因为这些数据类型在内存中具有相同的表示形式,但是更复杂的数据类型需要显式数据封送处理。 有关示例,请参见如何:使用 PInvoke 从托管代码调用本机 DLL。
示例
// vcmcppv2_impl_dllimp.cpp
// compile with: /clr:pure user32.lib
using namespace System::Runtime::InteropServices;
// Implicit DLLImport specifying calling convention
extern "C" int __stdcall MessageBeep(int);
// explicit DLLImport needed here to use P/Invoke marshalling because
// System::String ^ is not the type of the first parameter to printf
[DllImport("msvcrt.dll", EntryPoint = "printf", CallingConvention = CallingConvention::Cdecl, CharSet = CharSet::Ansi)]
// or just
// [DllImport("msvcrt.dll")]
int printf(System::String ^, ...);
int main() {
// (string literals are System::String by default)
printf("Begin beep\n");
MessageBeep(100000);
printf("Done\n");
}
本节内容
有关在互操作方案中使用委托的信息,请参见 委托(C++ 组件扩展)。