Using C++ Interop (Implicit PInvoke) (original) (raw)
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 provides better type safety, and it is typically less tedious to implement. However, C++ Interop is not an option if the unmanaged source code is not available, or for cross-platform projects.
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. Unlike Visual Basic and C#, Visual C++ can use COM objects directly using the usual COM mechanisms (such as CoCreateInstance and QueryInterface). This is possible due to C++ Interop features that cause the compiler to automatically insert the transition code to move from managed to unmanaged functions and back again.
Using C++ Interop, COM components can be used as they are normally used or they can be wrapped inside C++ classes. These wrapper classes are called custom runtime callable wrappers, or CRCWs, and they have two advantages over using COM directly in application code:
- The resulting class can be used from languages other than Visual C++.
- The details of the COM interface can be hidden from the managed client code. .NET data types can be used in place of native types, and the details of data marshaling can be performed transparently inside the CRCW.
Regardless of whether COM is used directly or through a CRCW, argument types other than simple, blittable types must be marshaled.
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
- How to: Marshal ANSI Strings Using C++ Interop
- How to: Marshal Unicode Strings Using C++ Interop
- How to: Marshal COM Strings Using C++ Interop
- How to: Marshal Structures Using C++ Interop
- How to: Marshal Arrays Using C++ Interop
- How to: Marshal Callbacks and Delegates By Using C++ Interop
- How to: Marshal Embedded Pointers Using C++ Interop
- How to: Access Characters in a System::String
- How to: Convert char * String to System::Byte Array
- How to: Convert System::String to wchar_t* or char*
- How to: Convert System::String to Standard String
- How to: Convert Standard String to System::String
- How to: Obtain a Pointer to Byte Array
- How to: Load Unmanaged Resources into a Byte Array
- How to: Modify Reference Class in a Native Function
- How to: Determine if an Image is Native or CLR
- How to: Add Native DLL to Global Assembly Cache
- How to: Hold Reference to Value Type in Native Type
- How to: Hold Object Reference in Unmanaged Memory
- How to: Detect /clr Compilation
- How to: Convert Between System::Guid and _GUID
- How to: Specify an out Parameter
- How to: Use a Native Type in a /clr Compilation
- How to: Declare Handles in Native Types
- How to: Wrap Native Class for Use by C#
For information on using delegates in an interop scenario, see delegate (C++ Component Extensions).