You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# How to: Marshal embedded pointers using P/Invoke
10
10
11
-
Functions that are implemented in unmanaged DLLs can be called from managed code using Platform Invoke (P/Invoke) functionality. If the source code for the DLL is not available, P/Invoke is the only option for interoperating. However, unlike other .NET languages, Visual C++ provides an alternative to P/Invoke. For more information, see [Using C++ Interop (Implicit PInvoke)](../dotnet/using-cpp-interop-implicit-pinvoke.md) and [How to: Marshal Embedded Pointers Using C++ Interop](../dotnet/how-to-marshal-embedded-pointers-using-cpp-interop.md).
11
+
Functions that are implemented in unmanaged DLLs can be called from managed code using Platform Invoke (P/Invoke) functionality. If the source code for the DLL isn't available, P/Invoke is the only option for interoperating. However, unlike other .NET languages, Visual C++ provides an alternative to P/Invoke. For more information, see [Using C++ Interop (Implicit P/Invoke)](../dotnet/using-cpp-interop-implicit-pinvoke.md) and [How to: Marshal embedded pointers using C++ Interop](../dotnet/how-to-marshal-embedded-pointers-using-cpp-interop.md).
12
12
13
13
## Example
14
14
15
15
Passing structures to native code requires that a managed structure that is equivalent in terms of data layout to the native structure is created. However, structures that contain pointers require special handling. For each embedded pointer in the native structure, the managed version of the structure should contain an instance of the <xref:System.IntPtr> type. Also, memory for these instances must be explicitly allocated, initialized, and released using the <xref:System.Runtime.InteropServices.Marshal.AllocCoTaskMem%2A>, <xref:System.Runtime.InteropServices.Marshal.StructureToPtr%2A>, and <xref:System.Runtime.InteropServices.Marshal.FreeCoTaskMem%2A> methods.
16
16
17
-
The following code consists of an unmanaged and a managed module. The unmanaged module is a DLL that defines a function that accepts a structure called ListString that contains a pointer, and a function called TakesListStruct. The managed module is a command-line application that imports the TakesListStruct function and defines a structure called MListStruct that is equivalent to the native ListStruct except that the double* is represented with an <xref:System.IntPtr> instance. Before calling TakesListStruct, the main function allocates and initializes the memory that this field references.
17
+
The following code consists of an unmanaged and a managed module. The unmanaged module is a DLL that defines a function that accepts a structure called `ListString` that contains a pointer, and a function called `TakesListStruct`.
The managed module is a command-line application that imports the `TakesListStruct` function and defines a structure called `MListStruct` that is equivalent to the native `ListStruct` except that the `double*` is represented with an <xref:System.IntPtr> instance. Before it calls `TakesListStruct`, the `main` function allocates and initializes the memory that this field references.
50
+
49
51
```cpp
50
52
// EmbeddedPointerMarshalling.cpp
51
53
// compile with: /clr
@@ -88,8 +90,8 @@ int main() {
88
90
}
89
91
```
90
92
91
-
Note that no portion of the DLL is exposed to the managed code using the traditional #include directive. In fact, the DLL is accessed at run time only, so problems with functions imported with <xref:System.Runtime.InteropServices.DllImportAttribute>will not be detected at compile time.
93
+
No portion of the DLL is exposed to the managed code using the traditional `#include` directive. In fact, the DLL is accessed at runtime only, so problems in functions imported by using <xref:System.Runtime.InteropServices.DllImportAttribute>can't be detected at compile time.
92
94
93
95
## See also
94
96
95
-
[Using Explicit PInvoke in C++ (DllImport Attribute)](../dotnet/using-explicit-pinvoke-in-cpp-dllimport-attribute.md)
97
+
[Using explicit P/Invoke in C++ (`DllImport` attribute)](../dotnet/using-explicit-pinvoke-in-cpp-dllimport-attribute.md)
Copy file name to clipboardExpand all lines: docs/dotnet/how-to-marshal-function-pointers-using-pinvoke.md
+15-15Lines changed: 15 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,28 +1,24 @@
1
1
---
2
-
description: "Learn more about: How to: Marshal Function Pointers Using PInvoke"
3
-
title: "How to: Marshal Function Pointers Using PInvoke"
2
+
description: "Learn more about: How to: Marshal function pointers using P/Invoke"
3
+
title: "How to: Marshal function pointers using P/Invoke"
4
4
ms.custom: "get-started-article"
5
-
ms.date: "11/04/2016"
5
+
ms.date: 06/29/2022
6
6
helpviewer_keywords: ["data marshaling [C++], callbacks and delegates", "interop [C++], callbacks and delegates", "platform invoke [C++], callbacks and delegates", "marshaling [C++], callbacks and delegates"]
7
7
ms.assetid: dcf396fd-a91d-49c0-ab0b-1ea160668a89
8
8
---
9
-
# How to: Marshal Function Pointers Using PInvoke
9
+
# How to: Marshal function pointers using P/Invoke
10
10
11
-
This topic explains how managed delegates can be used in place of function pointers when interoperating with unmanaged functions using .NET Framework P/Invoke features. However, Visual C++ programmers are encouraged to use the C++ Interop features instead (when possible) because P/Invoke provides little compile-time error reporting, is not type-safe, and can be tedious to implement. If the unmanaged API is packaged as a DLL and the source code is not available, P/Invoke is the only option. Otherwise, see the following topics:
11
+
Managed delegates can be used in place of function pointers when interoperating with unmanaged functions by using .NET Framework P/Invoke features. However, we encourage you to use the C++ Interop features instead, when possible. P/Invoke provides little compile-time error reporting, isn't type-safe, and can be tedious to implement. If the unmanaged API is packaged as a DLL and the source code isn't available, P/Invoke is the only option. Otherwise, see these articles:
12
12
13
-
-[Using C++ Interop (Implicit PInvoke)](../dotnet/using-cpp-interop-implicit-pinvoke.md)
13
+
-[Using C++ Interop (Implicit P/Invoke)](../dotnet/using-cpp-interop-implicit-pinvoke.md)
14
14
15
-
-[How to: Marshal Callbacks and Delegates By Using C++ Interop](../dotnet/how-to-marshal-callbacks-and-delegates-by-using-cpp-interop.md)
15
+
-[How to: Marshal callbacks and delegates by using C++ Interop](../dotnet/how-to-marshal-callbacks-and-delegates-by-using-cpp-interop.md)
16
16
17
-
Unmanaged APIs that take functions pointers as arguments can be called from managed code with a managed delegate in place of the native function pointer. The compiler automatically marshals the delegate to unmanaged functions as a function pointer and inserts the necessary managed/unmanaged transition code.
17
+
Unmanaged APIs that take functions pointers as arguments can be called from managed code by using a managed delegate in place of the native function pointer. The compiler automatically marshals the delegate to unmanaged functions as a function pointer. It inserts the necessary managed/unmanaged transition code.
18
18
19
19
## Example
20
20
21
-
The following code consists of an unmanaged and a managed module. The unmanaged module is a DLL that defines a function called TakesCallback that accepts a function pointer. This address is used to execute the function.
22
-
23
-
The managed module defines a delegate that is marshaled to the native code as a function pointer and uses the <xref:System.Runtime.InteropServices.DllImportAttribute> attribute to expose the native TakesCallback function to the managed code. In the main function, an instance of the delegate is created and passed to the TakesCallback function. The program output demonstrates that this function gets executed by the native TakesCallback function.
24
-
25
-
The managed function suppresses garbage collection for the managed delegate to prevent .NET Framework garbage collection from relocating the delegate while the native function executes.
21
+
The following code consists of an unmanaged and a managed module. The unmanaged module is a DLL that defines a function called `TakesCallback` that accepts a function pointer. This address is used to execute the function.
26
22
27
23
```cpp
28
24
// TraditionalDll5.cpp
@@ -48,6 +44,10 @@ int TakesCallback(CALLBACK fp, int n) {
48
44
}
49
45
```
50
46
47
+
The managed module defines a delegate that's marshaled to the native code as a function pointer. It uses the <xref:System.Runtime.InteropServices.DllImportAttribute> attribute to expose the native `TakesCallback` function to the managed code. In the `main` function, an instance of the delegate is created and passed to the `TakesCallback` function. The program output demonstrates that this function gets executed by the native `TakesCallback` function.
48
+
49
+
The managed function suppresses garbage collection for the managed delegate to prevent .NET Framework garbage collection from relocating the delegate while the native function executes.
50
+
51
51
```cpp
52
52
// MarshalDelegate.cpp
53
53
// compile with: /clr
@@ -76,8 +76,8 @@ int main() {
76
76
}
77
77
```
78
78
79
-
Note that no portion of the DLL is exposed to the managed code using the traditional #include directive. In fact, the DLL is accessed at run time only, so problems with functions imported with <xref:System.Runtime.InteropServices.DllImportAttribute>will not be detected at compile time.
79
+
No portion of the DLL is exposed to the managed code using the traditional `#include` directive. In fact, the DLL is accessed at runtime only, so problems with functions imported by using <xref:System.Runtime.InteropServices.DllImportAttribute>can't be detected at compile time.
80
80
81
81
## See also
82
82
83
-
[Using Explicit PInvoke in C++ (DllImport Attribute)](../dotnet/using-explicit-pinvoke-in-cpp-dllimport-attribute.md)
83
+
[Using explicit P/Invoke in C++ (`DllImport` attribute)](../dotnet/using-explicit-pinvoke-in-cpp-dllimport-attribute.md)
This topic explains how native functions that accept C-style strings can be called using the CLR string type System::Stringusing .NET Framework Platform Invoke support. Visual C++ programmers are encouraged to use the C++ Interop features instead (when possible) because P/Invoke provides little compile-time error reporting, is not type-safe, and can be tedious to implement. If the unmanaged API is packaged as a DLL, and the source code is not available, then P/Invoke is the only option, but otherwise see [Using C++ Interop (Implicit PInvoke)](../dotnet/using-cpp-interop-implicit-pinvoke.md).
11
+
Native functions that accept C-style strings can be called using the CLR string type `System::String` by using .NET Framework Platform Invoke (P/Invoke) support. We encourage you to use the C++ Interop features instead of P/Invoke when possible. because P/Invoke provides little compile-time error reporting, isn't type-safe, and can be tedious to implement. If the unmanaged API is packaged as a DLL, and the source code isn't available, then P/Invoke is the only option. Otherwise, see [Using C++ Interop (Implicit P/Invoke)](../dotnet/using-cpp-interop-implicit-pinvoke.md).
12
12
13
13
Managed and unmanaged strings are laid out differently in memory, so passing strings from managed to unmanaged functions requires the <xref:System.Runtime.InteropServices.MarshalAsAttribute> attribute to instruct the compiler to insert the required conversion mechanisms for marshaling the string data correctly and safely.
14
14
15
-
As with functions that use only intrinsic data types, <xref:System.Runtime.InteropServices.DllImportAttribute> is used to declare managed entry points into the native functions, but--for passing strings--instead of defining these entry points as taking C-style strings, a handle to the <xref:System.String> type can be used instead. This prompts the compiler to insert code that performs the required conversion. For each function argument in an unmanaged function that takes a string, the <xref:System.Runtime.InteropServices.MarshalAsAttribute> attribute should be used to indicate that the String object should be marshaled to the native function as a C-style string.
15
+
As with functions that use only intrinsic data types, <xref:System.Runtime.InteropServices.DllImportAttribute> is used to declare managed entry points into the native functions. Functions that pass strings can use a handle to the <xref:System.String> type instead of defining these entry points as taking C-style strings. Using this type prompts the compiler to insert code that performs the required conversion. For each function argument in an unmanaged function that takes a string, use the <xref:System.Runtime.InteropServices.MarshalAsAttribute> attribute to indicate that the `String` object should be marshaled to the native function as a C-style string.
16
16
17
-
The marshaler wraps the call to the unmanaged function in a hidden wrapper routine that pins and copies the managed string into a locally allocated string in the unmanaged context, which then is passed to the unmanaged function. When the unmanaged function returns, the wrapper either deletes the resource, or if it was on the stack, it is reclaimed when the wrapper goes out of scope. The unmanaged function is not responsible for this memory. The unmanaged code only creates and deletes memory in the heap set up by its own CRT, so there is never an issue with the marshaller using a different CRT version.
17
+
The marshaler wraps the call to the unmanaged function in a hidden wrapper routine. The wrapper routine pins and copies the managed string into a locally allocated string in the unmanaged context. The local copy is then passed to the unmanaged function. When the unmanaged function returns, the wrapper deletes the resource. Or, if it was on the stack, it's reclaimed when the wrapper goes out of scope. The unmanaged function isn't responsible for this memory. The unmanaged code only creates and deletes memory in the heap set up by its own CRT, so there's never an issue with the marshaller using a different CRT version.
18
18
19
19
If your unmanaged function returns a string, either as a return value or an out parameter, the marshaler copies it into a new managed string, and then releases the memory. For more information, see [Default Marshaling Behavior](/dotnet/framework/interop/default-marshaling-behavior) and [Marshaling Data with Platform Invoke](/dotnet/framework/interop/marshaling-data-with-platform-invoke).
20
20
21
21
## Example
22
22
23
-
The following code consists of a unmanaged and a managed module. The unmanaged module is a DLL that defines a function called TakesAString that accepts a C-style ANSI string in the form of a char*. The managed module is a command-line application that imports the TakesAString function, but defines it as taking a managed System.String instead of a char\*. The <xref:System.Runtime.InteropServices.MarshalAsAttribute> attribute is used to indicate how the managed string should be marshaled when TakesAString is called.
23
+
The following code consists of an unmanaged module and a managed module. The unmanaged module is a DLL that defines a function called `TakesAString`. `TakesAString` accepts a C-style narrow string in the form of a `char*`.
24
24
25
25
```cpp
26
26
// TraditionalDll2.cpp
@@ -47,6 +47,8 @@ void TakesAString(char* p) {
47
47
}
48
48
```
49
49
50
+
The managed module is a command-line application that imports the `TakesAString` function, but defines it as taking a managed `System.String` instead of a `char*`. The <xref:System.Runtime.InteropServices.MarshalAsAttribute> attribute is used to indicate how the managed string should be marshaled when `TakesAString` is called.
51
+
50
52
```cpp
51
53
// MarshalString.cpp
52
54
// compile with: /clr
@@ -62,16 +64,16 @@ value struct TraditionalDLL
62
64
63
65
int main() {
64
66
String^ s = gcnew String("sample string");
65
-
Console::WriteLine("[managed] passing managed string to unmanaged function...");
67
+
Console::WriteLine("[managed] passing managed string to unmanaged function...");
66
68
TraditionalDLL::TakesAString(s);
67
69
Console::WriteLine("[managed] {0}", s);
68
70
}
69
71
```
70
72
71
-
This technique causes a copy of the string to be constructed on the unmanaged heap, so changes made to the string by the native function will not be reflected in the managed copy of the string.
73
+
This technique constructs a copy of the string on the unmanaged heap, so changes made to the string by the native function won't be reflected in the managed copy of the string.
72
74
73
-
Note that no portion of the DLL is exposed to the managed code via the traditional #include directive. In fact, the DLL is accessed at runtime only, so problems with functions imported with `DllImport`will not be detected at compile time.
75
+
No portion of the DLL is exposed to the managed code by the traditional `#include` directive. In fact, the DLL is accessed at runtime only, so problems in functions imported by using `DllImport`aren't detected at compile time.
74
76
75
77
## See also
76
78
77
-
[Using Explicit PInvoke in C++ (DllImport Attribute)](../dotnet/using-explicit-pinvoke-in-cpp-dllimport-attribute.md)
79
+
[Using explicit P/Invoke in C++ (`DllImport` attribute)](../dotnet/using-explicit-pinvoke-in-cpp-dllimport-attribute.md)
0 commit comments