Platform Invoke
Finally ,找到工具来参考转换。
Source: https://github.com/jaredpar/pinvoke
Tool: https://archive.codeplex.com/?p=clrinterop
书籍 参考:
NET and COM: The Complete Interoperability Guide
https://docs.microsoft.com/en-us/cpp/dotnet/calling-native-functions-from-managed-code
这篇新文章里面有详细的解释,包括数据类型的转换。
还可以参考这个文档:
file:///C:/Users/wiyan/AppData/Local/Microsoft/Windows/INetCache/IE/Q0DGUWJP/traks_computerscience_2016.pdf
Marshaling Arguments
With PInvoke
, no marshaling is needed between managed and C++ native primitive types with the same form. For example, no marshaling is required between Int32 and int, or between Double and double.
However, you must marshal types that do not have the same form. This includes char, string, and struct types. The following table shows the mappings used by the marshaler for various types:
wtypes.h | Visual C++ | Visual C++ with /clr | Common language runtime |
---|---|---|---|
HANDLE | void * | void * | IntPtr, UIntPtr |
BYTE | unsigned char | unsigned char | Byte |
SHORT | short | short | Int16 |
WORD | unsigned short | unsigned short | UInt16 |
INT | int | int | Int32 |
UINT | unsigned int | unsigned int | UInt32 |
LONG | long | long | Int32 |
BOOL | long | bool | Boolean |
DWORD | unsigned long | unsigned long | UInt32 |
ULONG | unsigned long | unsigned long | UInt32 |
CHAR | char | char | Char |
LPCSTR | char * | String ^ [in], StringBuilder ^ [in, out] | String ^ [in], StringBuilder ^ [in, out] |
LPCSTR | const char * | String ^ | String |
LPWSTR | wchar_t * | String ^ [in], StringBuilder ^ [in, out] | String ^ [in], StringBuilder ^ [in, out] |
LPCWSTR | const wchar_t * | String ^ | String |
FLOAT | float | float | Single |
DOUBLE | double | double | Double |
PInvoke 允许managed code 来调用在DLL中实施的unmanged function。
Platform invoke relies on metadata to locate exported functions and marshal their arguments at run time. The following illustration shows this process.
A platform invoke call to an unmanaged DLL function
When platform invoke calls an unmanaged function, it performs the following sequence of actions:
- Locates the DLL containing the function.
- Loads the DLL into memory.
- Locates the address of the function in memory and pushes its arguments onto the stack, marshaling data as required.
Note Locating and loading the DLL, and locating the address of the function in memory occur only on the first call to the function.
- Transfers control to the unmanaged function.
Platform invoke throws exceptions generated by the unmanaged function to the managed caller.
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.
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.cs
using 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 method PlatformInvokeTest.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 theMarshalAs 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 the MarshalAsattribute.
// Marshal.cs
using 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 theputs
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 out modifiers in MIDL source files. Note that the Out attribute is different from the C# parameter modifier, out. For more information on the In and Out attributes, 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 MarshalAs attributes 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:module
using 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.netmodule
using 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.
参考:http://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx
Platform Invoke的更多相关文章
- P/Invoke:C#调用C++
P/Invoke的全称是Platform Invoke (平台调用) 它实际上是一种函数调用机制通 过P/Invoke我们就可以调用非托管DLL中的函数. P/Invoke依次执行以下操作: 1. 查 ...
- P/Invoke .NET调用win32API
项目:无线无源测温软件系统 项目中,用到使用P/Invoke在.NET调用win32API,实现对ini配置文件的读写功能!因为有一些配置信息需要保存下来,以便在下一次启动程序完成初始化,这实际上是一 ...
- 使用平台调用(P/Invoke)
使用平台调用 P/Invoke.它的全名叫平台调用(platform invoke).用于调用dll 中实现的非托管的单调(flat)编程接口.被称为使用C或C++ 调用约定(calling conv ...
- 关于P/Invoke的闲话
P/Invoke,Platform Invoke,平台调用,是.NET打通托管与非托管两个世界的通路,10来年前曾经研究过这方面的技术,还曾发表过相关文章在<程序员>上,呵呵. 昨天有需求 ...
- Thread.Sleep(0) vs Sleep(1) vs Yeild
本文将要提到的线程及其相关内容,均是指 Windows 操作系统中的线程,不涉及其它操作系统. 文章索引 核心概念 Thread.Yeild Thread.Sleep(0) Thread. ...
- C++如何调用C#开发的dll
序言 本文介绍一个C++如何调用C#开发的dll实例. 前言 C++编写的程序为非托管代码,C#编写的程序为托管代码.托管代码虽然提供了其他开发平台没有的许多优势,但由于前期系统及历史版本很多使用的是 ...
- Effective C#中文版
我看的书是<Effective C#中文版——改善C#程序的50种方法>,Bill Wagner著,李建忠译.书比较老了,04年写的,主要针对C#1.0,但我相信其中的观点现在仍有价值.( ...
- Windbg使用简明指南
第一章 准备 1.1. 环境配置 _NT_DEBUGGER_EXTENSION_PATH=C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 _NT_SY ...
- Java基础常见英语词汇
Java基础常见英语词汇(共70个) ['ɔbdʒekt] ['ɔ:rientid]导向的 ['prəʊɡræmɪŋ]编程 OO: object ...
随机推荐
- Ubuntu12.04安装中文字体(转)
1.在/usr/share/fonts/下,新建文件夹winFonts,如果没有fonts目录,就安装fontconfig软件(系统字体管理),再将win7字体msyh.ttf和msyhbd.ttf复 ...
- zboot/xtract.c
/* * linux/zBoot/xtract.c * * Copyright (C) 1993 Hannu Savolainen * * Extracts the system imag ...
- 第一课 T语言关键字(版本TC5.0)
关键字 TC综合开发工具的语法里包含了大量的关键字,而且对TC综合开发工具支持的关键字都做了亮色处理,以便大家在写脚本的时候容易区分. 关键字在使用的时候,都有特定的作用,不能作为变量名.函数名等等使 ...
- js部分---for循环练习题
1有一张0.0001米的纸,对折多少次可以达到珠穆朗玛峰的高度8848: <script> /*var h=0.0001; var biao=0; for(;;) { h=h*2; if( ...
- activiti工作流数据库表详细介绍 (23张表)
Activiti的后台是有数据库的支持,所有的表的表名都以ACT_开头,表名的第二部分是用来表示表的用途的两个字母标识. 用途也和服务的API对应. ACT_RE_*: 'RE'表示repositor ...
- yum命令
1)查询 yum list #查询所有可用软件包列表 yum search 关键字 #搜索服务器上和关键字相关的包 #对比rpm的查询:rpm -qa | grep xxx 2)安装 yum ...
- POJ-2991 Crane(区间更新+向量旋转)
题目大意:n个向量首尾相连,每次操作使某个区间中的所有向量都旋转同样的角度.每次操作后都回答最后一个向量的坐标. 题目分析:区间维护向量信息.向量旋转:x1=x0*cos(t)-y0*sin(t),y ...
- Python 基本语法1
Python 基础语法(一) Python的特点 1. 简单 Python是一种代表简单思想的语言. 2. 易学 Python有极其简单的语法. 3. 免费.开源 Python是FLOSS(自由/开放 ...
- Too many authentic authentication failures for root
连接SSH服务器时报 Too many authentic authentication failures for root. 方法一:删除目标服务器 /root/.ssh/目录下的 known_ho ...
- [译] AlphaGo 的确是一个大事件
[译] AlphaGo 的确是一个大事件 转自:http://www.jianshu.com/p/157a15de47df 字数3797 阅读696 评论0 喜欢4 作者:Michael Nielse ...