Platform Invoke Tutorial
来源:互联网 发布:神雕群芳谱txt下载知轩 编辑:程序博客网 时间:2024/06/02 02:29
Platform Invocation Services (PInvoke) allows managed code to call unmanaged functions that are implemented in a DLL.
This tutorial shows you what you need to do to be able to call unmanaged DLL functions from C#. The attributes discussed in the tutorial allow you to call these functions and have data types be marshaled correctly.
Sample Files
See Platform Invoke Sample to download and build the sample files discussed in this tutorial.
Platform Invoke
Further Reading
- A Closer Look at Platform Invoke
- Using Attributes
- DllImportAttribute Class
- MarshalAsAttribute Class
- StructLayoutAttribute Class
- InAttribute Class
- OutAttribute Class
Tutorial
There are two ways that C# code can directly call unmanaged code:
- Directly call a function exported from a DLL.
- Call an interface method on a COM object (for more information, see COM Interop Part 1: C# Client Tutorial).
For both techniques, you must provide the C# compiler with a declaration of the unmanaged function, and you may also need to provide the C# compiler with a description of how to marshal the parameters and return value to and from the unmanaged code.
The tutorial consists of the following topics:
- Calling a DLL Export Directly from C#
- Default Marshaling and Specifying Custom Marshaling for Parameters to Unmanaged Methods
- Specifying Custom Marshaling for User-Defined Structs
- Registering Callback Methods
The tutorial includes the following examples:
- Example 1 Using DllImport
- Example 2 Overriding Default Marshaling
- Example 3 Specifying Custom Marshaling
Calling a DLL Export Directly from C#
To declare a method as having an implementation from a DLL export, do the following:
- Declare the method with the static and extern C# keywords.
- Attach the DllImport attribute to the method. The DllImport attribute allows you to specify the name of the DLL that contains the method. The common practice is to name the C# method the same as the exported method, but you can also use a different name for the C# method.
- Optionally, specify custom marshaling information for the method's parameters and return value, which will override the .NET Framework default marshaling.
Example 1
This example shows you how to use the DllImport attribute to output a message by calling puts
from msvcrt.dll
.
// PInvokeTest.csusing System;using System.Runtime.InteropServices;class PlatformInvokeTest{ [DllImport("msvcrt.dll")] public static extern int puts(string c); [DllImport("msvcrt.dll")] internal static extern int _flushall(); public static void Main() { puts("Test"); _flushall(); }}
Output
Test
Code Discussion
The preceding example shows the minimum requirements for declaring a C# method that is implemented in an unmanaged DLL. The methodPlatformInvokeTest.puts
is declared with the static and extern modifiers and has the DllImport attribute which tells the compiler that the implementation comes from msvcrt.dll
, using the default name of puts
. To use a different name for the C# method such as putstring
, you must use the EntryPoint option in the DllImport attribute, that is:
[DllImport("msvcrt.dll", EntryPoint="puts")]
For more information on the syntax of the DllImport attribute, see DllImportAttribute Class.
Default Marshaling and Specifying Custom Marshaling for Parameters to Unmanaged Methods
When calling an unmanaged function from C# code, the common language runtime must marshal the parameters and return values.
For every .NET Framework type there is a default unmanaged type, which the common language runtime will use to marshal data across a managed to unmanaged function call. For example, the default marshaling for C# string values is to the type LPTSTR (pointer to TCHAR char buffer). You can override the default marshaling using the MarshalAs attribute in the C# declaration of the unmanaged function.
Example 2
This example uses the DllImport attribute to output a string. It also shows you how to override the default marshaling of the function parameters by using theMarshalAs attribute.
// Marshal.csusing System;using System.Runtime.InteropServices;class PlatformInvokeTest{ [DllImport("msvcrt.dll")] public static extern int puts( [MarshalAs(UnmanagedType.LPStr)] string m); [DllImport("msvcrt.dll")] internal static extern int _flushall(); public static void Main() { puts("Hello World!"); _flushall(); }}
Output
When you run this example, the string,
Hello World!
will display at the console.
Code Discussion
In the preceding example, the default marshaling for the parameter to the puts
function has been overridden from the default of LPTSTR to LPSTR.
The MarshalAs attribute can be placed on method parameters, method return values, and fields of structs and classes. To set the marshaling of a method return value, place the MarshalAs attribute in an attribute block on the method with the return attribute location override. For example, to explicitly set the marshaling for the return value of the puts
method:
...[DllImport("msvcrt.dll")] [return : MarshalAs(UnmanagedType.I4)]public static extern int puts( ...
For more information on the syntax of the MarshalAs attribute, see MarshalAsAttribute Class.
Note The In and Out attributes can be used to annotate parameters to unmanaged methods. They behave in a similar manner to the in and outmodifiers in MIDL source files. Note that the Out attribute is different from the C# parameter modifier, out. For more information on the In and Outattributes, see InAttribute Class and OutAttribute Class.
Specifying Custom Marshaling for User-Defined Structs
You can specify custom marshaling attributes for fields of structs and classes passed to or from unmanaged functions. You do this by adding MarshalAsattributes to the fields of the struct or class. You must also use the StructLayout attribute to set the layout of the struct, optionally to control the default marshaling of string members, and to set the default packing size.
Example 3
This example demonstrates how to specify custom marshaling attributes for a struct.
Consider the following C structure:
typedef struct tagLOGFONT { LONG lfHeight; LONG lfWidth; LONG lfEscapement; LONG lfOrientation; LONG lfWeight; BYTE lfItalic; BYTE lfUnderline; BYTE lfStrikeOut; BYTE lfCharSet; BYTE lfOutPrecision; BYTE lfClipPrecision; BYTE lfQuality; BYTE lfPitchAndFamily; TCHAR lfFaceName[LF_FACESIZE]; } LOGFONT;
In C#, you can describe the preceding struct by using the StructLayout and MarshalAs attributes as follows:
// logfont.cs// compile with: /target:moduleusing System;using System.Runtime.InteropServices;[StructLayout(LayoutKind.Sequential)]public class LOGFONT { public const int LF_FACESIZE = 32; public int lfHeight; public int lfWidth; public int lfEscapement; public int lfOrientation; public int lfWeight; public byte lfItalic; public byte lfUnderline; public byte lfStrikeOut; public byte lfCharSet; public byte lfOutPrecision; public byte lfClipPrecision; public byte lfQuality; public byte lfPitchAndFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=LF_FACESIZE)] public string lfFaceName; }
For more information on the syntax of the StructLayout attribute, see StructLayoutAttribute Class.
The structure can then be used in C# code as shown below:
// pinvoke.cs// compile with: /addmodule:logfont.netmoduleusing System;using System.Runtime.InteropServices; class PlatformInvokeTest{ [DllImport("gdi32.dll", CharSet=CharSet.Auto)] public static extern IntPtr CreateFontIndirect( [In, MarshalAs(UnmanagedType.LPStruct)] LOGFONT lplf // characteristics ); [DllImport("gdi32.dll")] public static extern bool DeleteObject( IntPtr handle ); public static void Main() { LOGFONT lf = new LOGFONT(); lf.lfHeight = 9; lf.lfFaceName = "Arial"; IntPtr handle = CreateFontIndirect(lf); if (IntPtr.Zero == handle) { Console.WriteLine("Can't creates a logical font."); } else { if (IntPtr.Size == 4) Console.WriteLine("{0:X}", handle.ToInt32()); else Console.WriteLine("{0:X}", handle.ToInt64()); // Delete the logical font created. if (!DeleteObject(handle)) Console.WriteLine("Can't delete the logical font"); } }}
Sample Run
C30A0AE5
Code Discussion
In the preceding example, the CreateFontIndirect
method is using a parameter of the type LOGFONT. The MarshalAs and In attributes are used to qualify the parameter. The program displays the numeric value returned by the method as a hexadecimal uppercase string.
Registering Callback Methods
To register a managed callback that calls an unmanaged function, declare a delegate with the same argument list and pass an instance of it via PInvoke. On the unmanaged side it will appear as a function pointer. For more information about PInvoke and callback, see A Closer Look at Platform Invoke.
For example, consider the following unmanaged function, MyFunction
, which requires callback as one of the arguments:
typedef void (__stdcall *PFN_MYCALLBACK)();int __stdcall MyFunction(PFN_ MYCALLBACK callback);
To call MyFunction
from managed code, declare the delegate, attach DllImport to the function declaration, and optionally marshal any parameters or the return value:
public delegate void MyCallback();[DllImport("MYDLL.DLL")]public static extern void MyFunction(MyCallback callback);
Also, make sure the lifetime of the delegate instance covers the lifetime of the unmanaged code; otherwise, the delegate will not be available after it is garbage-collected.
- Platform Invoke Tutorial
- PlatForm Invoke Technology Sample
- Platform invoke 乱码
- c#.NET Framework 关机代码 Platform Invoke
- C#调用C++代码(CSharp Platform Invoke)
- Unity3D Platform Tutorial 中文教程翻译-第一章
- /LGC图形渲染/Pure GPU Computing Platform : NVIDIA CUDA Tutorial
- 《Eclipse.Rich.Client.Platform》3章 Tutorial Introduction
- Invoke
- Invoke
- invoke
- Invoke
- Invoke()
- Delphi2005学习笔记2——Using Platform Invoke with Delphi 2005
- platform
- platform
- platform
- platform
- HDU-3790-最短路径问题
- Datagridview控件常用设置
- 用command模拟多线程
- golang 创建守护进程
- 编程之美3.4
- Platform Invoke Tutorial
- cocos2d学习记录(六)-切片动画
- poj 2349 Arctic Network
- poj 3376 Finding Palindromes
- s:if中% #
- C++类别转换之char*与string的互转换
- CPPNIUT使用过程常见问题FAQ
- delete与delete [] 真正区别
- android学习-DDMS使用