Dela via


Using C++ Interop (Implicit PInvoke)

Unlike other .NET languages, Visual C++ has interoperability support that allows managed and unmanaged code to exist in the same application and even in the same file (with the managed, unmanaged pragmas). This allows Visual C++ developers to integrate .NET functionality into existing Visual C++ applications without disturbing the rest of the application.

You can also call unmanaged functions from a managed compiland using dllexport, dllimport.

Implicit PInvoke is useful when you do not need to specify how function parameters will be marshaled, or any of the other details that can be specified when explicitly calling DllImportAttribute.

Visual C++ provides two ways for managed and unmanaged functions to interoperate:

Explicit PInvoke is supported by the .NET Framework and is available in most .NET languages. But as its name implies, C++ Interop is specific to Visual C++.

C++ Interop

C++ Interop is recommended over explicit PInvoke because it provides better type safety, is typically less tedious to implement, is more forgiving if the unmanaged API is modified, and makes performance enhancements possible that are not possible with explicit PInvoke. However, C++ Interop is not possible if the unmanaged source code is not available or when compiling with /clr:safe (see Pure and Verifiable Code (C++/CLI) for more information).

C++ COM Interop

The interoperability features supported by Visual C++ offer a particular advantage over other .NET languages when it comes to interoperating with COM components. Instead of being limited to the restrictions of the .NET Framework Tlbimp.exe (Type Library Importer), such as limited support for data types and the mandatory exposure of every member of every COM interface, C++ Interop allows COM components to be accessed at will and does not require separate interop assemblies.

Blittable Types

For unmanaged APIs that use simple, intrinsic types (see Blittable and Non-Blittable Types), no special coding is required because these data types have the same representation in memory, but more complex data types require explicit data marshaling. For an example, see How to: Call Native DLLs from Managed Code Using PInvoke.

Example

// 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

In This Section

For information on using delegates in an interop scenario, see delegate.

See Also

Concepts

Calling Native Functions from Managed Code