Skip to content

Commit edca2fd

Browse files
author
Zlatko Knezevic
committed
Respond to PR feedback
Add comments to code samples in documents. Add subsection heading for marshalling structs/classes.
1 parent 1822a0b commit edca2fd

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed

docs/concepts/native-interop.rst

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,13 @@ in your managed code. Let's show a message box from a command-line application:
5050
5151
public class Program {
5252
53+
// Import user32.dll (containing the function we need) and define
54+
// the method corresponding to the native function.
5355
[DllImport("user32.dll")]
5456
public static extrn int MessageBox(IntPtr hWnd, String text, String caption, int options);
5557
5658
public static void Main(string[] args) {
59+
// Invoke the function as a regular managed method.
5760
MessageBox(IntPtr.Zero, "Command-line message box", "Attention!", 0);
5861
}
5962
}
@@ -148,17 +151,22 @@ else.
148151
149152
class Program {
150153
154+
// Define a delegate that corresponds to the unmanaged function.
151155
delegate bool EnumWC(IntPtr hwnd, IntPtr lParam);
152156
157+
// Import user32.dll (containing the function we need) and define
158+
// the method corresponding to the native function.
153159
[DllImport("user32.dll")]
154160
static extern int EnumWindows(EnumWC hWnd, IntPtr lParam);
155161
162+
// Define the implementation of the delegate; here, we simply output the window handle.
156163
static bool OutputWindow(IntPtr hwnd, IntPtr lParam) {
157164
Console.WriteLine(hwnd.ToInt64());
158165
return true;
159166
}
160167
161168
static void Main(string[] args) {
169+
// Invoke the method; note the delegate as a first parameter.
162170
EnumWindows(OutputWindow, IntPtr.Zero);
163171
}
164172
}
@@ -197,46 +205,48 @@ The said function has the following signature:
197205
using System.Runtime.InteropServices;
198206
199207
namespace PInvokeSamples {
200-
public static class Program {
201-
202-
// Define a delegate that has the same signature as the native function.
203-
delegate int DirClbk(string fName, StatClass stat, int typeFlag);
204-
205-
// Import the libc and define the method to represent the native function.
206-
[DllImport("libc.so.6")]
207-
static extern int ftw(string dirpath, DirClbk cl, int descriptors);
208-
209-
// Implement the above DirClbk delegate; this one just prints out the filename that is passed to it.
210-
static int DisplayEntry(string fName, StatClass stat, int typeFlag) {
211-
Console.WriteLine(fName);
212-
return 0;
213-
}
214-
215-
public static void Main(string[] args){
216-
// Call the native function. Note the second parameter which represents the delegate (callback).
217-
ftw(".", DisplayEntry, 10);
218-
}
219-
}
220-
221-
// The native callback takes a pointer to a struct. The below class
222-
// represents that struct in managed code. You can find more information
223-
// about this in the section on marshalling below.
224-
[StructLayout(LayoutKind.Sequential)]
225-
public class StatClass {
226-
public uint DeviceID;
227-
public uint InodeNumber;
228-
public uint Mode;
229-
public uint HardLinks;
230-
public uint UserID;
231-
public uint GroupID;
232-
public uint SpecialDeviceID;
233-
public ulong Size;
234-
public ulong BlockSize;
235-
public uint Blocks;
236-
public long TimeLastAccess;
237-
public long TimeLastModification;
238-
public long TimeLastStatusChange;
239-
}
208+
public static class Program {
209+
210+
// Define a delegate that has the same signature as the native function.
211+
delegate int DirClbk(string fName, StatClass stat, int typeFlag);
212+
213+
// Import the libc and define the method to represent the native function.
214+
[DllImport("libc.so.6")]
215+
static extern int ftw(string dirpath, DirClbk cl, int descriptors);
216+
217+
// Implement the above DirClbk delegate;
218+
// this one just prints out the filename that is passed to it.
219+
static int DisplayEntry(string fName, StatClass stat, int typeFlag) {
220+
Console.WriteLine(fName);
221+
return 0;
222+
}
223+
224+
public static void Main(string[] args){
225+
// Call the native function.
226+
// Note the second parameter which represents the delegate (callback).
227+
ftw(".", DisplayEntry, 10);
228+
}
229+
}
230+
231+
// The native callback takes a pointer to a struct. The below class
232+
// represents that struct in managed code. You can find more information
233+
// about this in the section on marshalling below.
234+
[StructLayout(LayoutKind.Sequential)]
235+
public class StatClass {
236+
public uint DeviceID;
237+
public uint InodeNumber;
238+
public uint Mode;
239+
public uint HardLinks;
240+
public uint UserID;
241+
public uint GroupID;
242+
public uint SpecialDeviceID;
243+
public ulong Size;
244+
public ulong BlockSize;
245+
public uint Blocks;
246+
public long TimeLastAccess;
247+
public long TimeLastModification;
248+
public long TimeLastStatusChange;
249+
}
240250
}
241251
242252
@@ -259,14 +269,16 @@ to the ``DllImport`` attribute, as OS X keeps ``libc`` in a different place.
259269
[DllImport("libSystem.dylib")]
260270
static extern int ftw(string dirpath, DirClbk cl, int descriptors);
261271
262-
// Implement the above DirClbk delegate; this one just prints out the filename that is passed to it.
272+
// Implement the above DirClbk delegate;
273+
// this one just prints out the filename that is passed to it.
263274
static int DisplayEntry(string fName, StatClass stat, int typeFlag) {
264275
Console.WriteLine(fName);
265276
return 0;
266277
}
267278
268279
public static void Main(string[] args){
269-
// Call the native function. Note the second parameter which represents the delegate (callback).
280+
// Call the native function.
281+
// Note the second parameter which represents the delegate (callback).
270282
ftw(".", DisplayEntry, 10);
271283
}
272284
}
@@ -299,7 +311,7 @@ to writing quality native interop code, let's take a look at what happens when
299311
the runtime *marshals* the types.
300312

301313
Type marshalling
302-
^^^^^^^^^^^^^^^^
314+
----------------
303315
**Marshalling** is the process of transforming types when they need to cross the
304316
managed boundary into native and vice versa.
305317

@@ -318,6 +330,9 @@ ANSI string, we could do it like this:
318330
[DllImport("somenativelibrary.dll"]
319331
static extern int MethodA([MarshalAs(UnmanagedType.LPStr) string parameter);
320332
333+
334+
Marshalling classes and structs
335+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
321336
Another aspect of type marshalling is how to pass in a struct to an unmanaged method.
322337
For instance, some of the unmanaged methods require a struct as a parameter.
323338
In these cases, we need to create a corresponding struct or a class in managed

0 commit comments

Comments
 (0)