使用 C++ Interop(隐式 PInvoke)

更新:2007 年 11 月

与其他 .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++ COM 互操作

在与 COM 组件进行交互操作方面,Visual C++ 支持的互操作性功能与其他 .NET 语言相比具有特别的优势。C++ Interop 不受限于 .NET Framework 类型库导入程序 (Tlbimp.exe) 限制(如对数据类型的有限支持和强制公开每个 COM 接口的每个成员),而是允许随意访问 COM 组件,而且不需要单独的互操作程序集。有关更多信息,请参见使用 .NET 中的本机 COM 服务器

可直接复制到本机结构中的类型

对于使用简单内部类型(请参见 可直接复制到本机结构中的类型和非直接复制到本机结构中的类型)的非托管 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");
}

Begin beep
Done

本节内容

有关在互操作方案中使用委托的信息,请参见 delegate

请参见

概念

从托管代码调用本机函数