.Net中C#的DllImport的用法_.net dllimport用法-程序员宅基地

技术标签: MFC/VS2010  

说明:
  1、DllImport只能放置在方法声明上。
  2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。
  3、DllImport具有五个命名参数:
   a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。
   b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。
   c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。
   d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。
   e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。
   f、SetLastError 参数指示方法是否保留 Win32"上一错误"。如果未指定 SetLastError,则使用默认值 false。
  4、它是一次性属性类。

  5、此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。


其中CallingConvention.就有五种方式:

CallingConvention = CallingConvention.StdCall
CallingConvention = CallingConvention.Cdecl
CallingConvention = CallingConvention.FastCall
CallingConvention = CallingConvention.ThisCall
CallingConvention = CallingConvention.Winapi

"By default, C and C++ use cdecl - but marshalling uses stdcall to match the Windows API."

翻译:默认情况下,C和C++使用的Cdecl调用 ,但编组使用StdCall调用匹配的Windows
API

对于FastCall、ThisCall、Winapi这三种调用方式尚不清楚。

引用:百度文库  http://wenku.baidu.com/view/70f06e48cf84b9d528ea7ae9.html

#define   CALLBACK         __stdcall    
#define   WINAPI           __stdcall    
#define   WINAPIV          __cdecl    
#define   APIENTRY          WINAPI    
#define   APIPRIVATE       __stdcall    
#define   PASCAL           __stdcall

      调用约定(Calling   convention):决定函数参数传送时入栈和出栈的顺序,由调用者还是被调用者把参数弹出栈,以及编译器用来识别函数名字的修饰约定 .

 
函数调用约定有多种,这里简单说一下:   
  1、__stdcall调用约定相当于16位动态库中经常使用的PASCAL调用约定。
在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义
为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代
之的是__stdcall调用 约定。两者实质上是一致的,即函数的参数自右向
左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同
的是函数名的修饰部分(关于函数名的修饰 部分在后面将详细说明)。   
  _stdcall是Pascal程序的缺省调用方式,通常用于Win32   Api中,函数采
用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在
函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。

   
  2、C调用约定(即用__cdecl关键字说明)按从右至左的顺序压参数入
栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护
的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,
在函数名修饰约定方面也有所不同。   
  _cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清
空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函
数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线
前缀。是MFC缺省调用约定。

   
  3、__fastcall调用约定是“人”如其名,它的主要特点就是快,因为它是通
过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字
(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用
的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和
前两者均不同。_fastcall方式的函数采用寄存器传递参数,VC将函数
编译后会在函数名前面加上"@"前缀,在函数名后加上"@"和参数的字节数。

           
  4、thiscall仅仅应用于“C++”成员函数。this指针存放于CX寄存器,参数从右
到左压。thiscall不是关键词,因此不能被程序员指定。

   
  5、naked   call采用1-4的调用约定时,如果必要的话,进入函数时编译器
会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢
复这些寄存器的内容。naked   call不产生这样的代码。naked   call不是类型
修饰符,故必须和_declspec共同使用。

   
  关键字   __stdcall、__cdecl和__fastcall可以直接加在要输出的函数前,
也可以在编译环境的Setting.../C/C++   /Code   Generation项选择。当加在输
出函数前的关键字与编译环境中的选择不同时,直接加在输出函数前的关键
字有效。它们对应的命令行参数分别为/Gz、 /Gd和/Gr。缺省状态为/Gd,即__cdecl。

   
       要完全模仿PASCAL调用约定首先必须使用__stdcall调用约定,至于函数名修饰约定,可以通过其它方法模仿。还有一个值得一提的是WINAPI 宏,
Windows.h支持该宏,它可以将出函数翻译成适当的调用约定,在WIN32中,
它被定义为__stdcall。使用WINAPI宏可以创建自己 的APIs。
 
总结一点常用的:     
关于PASCAL这种调用约定的函数都是由它本身来清栈,而__cdecl的函数都是
由调用者来清栈. 实际用的时候,个人觉得两者最大的差别在 于:__cdecl的函
数参数个数可以声明为不确定,比如printf,scanf之类,而PASCAL的函数是不
可以这样做的,如果这样的话它不知道实参有多少个。     
VC里面:PASCAL==CALLBACK==WINAPI==__stdcall

DllImport特性

         首先我们来了解一下DllImport代码特性,在进行互操作的时候,我们需要用DllImport来标识该方法是非托管的代码方法,在编译器编译的时候它能够正确的认识出被该特性标记的是外来代码段,所以能顺利的通过编译,当到达程序运行的时候,也能够正确的认识出该代码是引用非托管的代码,这样就让我们的CLR去加载非托管DLL文件,然后查找到入口点进行调用;

[DllImport("Win32DLL.dll", EntryPoint = "add", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 public static extern int AddNumber(int x, int y);

这段代码申明了一个非托管代码AddNumber方法,我们来看DllImport特性的这几个属性具体什么意思;在DllImport构造函数里面有一个dllname的参数

我们可以看到注释,这个构造函数的参数是非托管dll的名称,也就是我们所要用到的导入方法的具体位置;上图中的参数是 "Win32DLL.dll"字符串,也就是我们上篇文章中创建的非托管C++生成文件,在后面有几个相关属性,我们也逐一来解释;

EntryPoint属性是用来确定非托管方法的入口点是什么,我的非托管代码的入口点名称是add,也就是说明一个问题,系统在识别非托管代码名称是靠Entrypoint属性来的,而不是我们在C#编辑器中申明的托管代码的名称AddNumber,系统只用Entrypoint来确定非托管入口点,而我们可以用随意的名称来定义非托管的调用名称,这往往是个好方法,由于我们托管代码经常要讲究一些对象化的编程方法,所以在命名方面也是至关重要的,不能随意起一个没有任何对象意义的名称,这样我们就可以定义自己的,复合当前上下文的,很形象的名称;

DllImport特性中的CharSet可选属性;

             CharSet属性是用来确定在托管与非托管调用的过程中用什么字符编码来封送数据,因为我们的.NET平台是采用的Unicode编码,而标准C++是采用的Ansi编码,在我们了解了非托管代码的编码方式之后,我们就很确定用什么编码,那么如果我们不清楚非托管代码是用什么语言编写的或者不清楚它的编码方式时,我们可以使用CharSet枚举中的auto值,让CLR自动为我们处理相关细节;

DllImport特性中的CallingConvention可选属性;

CallingConvention属性也是一个比较重要的属性,在平台调用的过程中起到查找入口点的作用,在托管代码进行非托管代码入口点查找时,会通过CallingConvention中的值进行确认非托管入口点的调用约定,

extern "C" _declspec(dllexport) int _stdcall add(int x,int y)
{
 return x+y;
}

这段是非托管C++代码,在这个方法前面有一个_stdcall的关键字,这个关键字的意思是说方法的调用约定,我们来看_stdcall调用的相关概念说明:函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈;意思是说,有被调用方来清理调用堆栈;

还有_declspec(dllexport)关键代码,这段意思是说将该方法导出为可调用方法,也就是说外来者是可以调用的方法,由于DLL文件不是每一个方法都可以调用的,只有编写者愿意才能使用。

extern "C"关键代码,是名称修饰的意思,在编译期间采用C编译选项来编译这个函数,由于C和C++是不同的语言,具体的语法也不相同,所以在C++中提供了选择的余地,让我们可以选择用什么编译方式来编译方法,如果我们用"C"代码修饰了之后,编译器会通过区分不同的调用约定来重新命名方法的名称;

__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个"@"符号和其参数的字节数,格式为_functionname@number,例如:function(int a, int b),其修饰名为:_function@8
__cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_functionname。
__fastcall调用约定在输出函数名前加上一个"@"符号,后面也是一个"@"符号和其参数的字节数,格式为@functionname@number。



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/bingqingsuimeng/article/details/75007044

智能推荐

java写的麻将小游戏_打牌游戏源代码-程序员宅基地

文章浏览阅读1.9w次,点赞24次,收藏102次。过年回家在家打麻将,觉得蛮有趣的,就用java写了一个麻将小游戏(没有界面,只能在控制台玩)。 说明:使用语言:java(jdk1.7)开发工具:eclipse项目集成:maven1 麻将说明1.1 方位说明(请注意“人”这个玩家的位置)1.2 规则说明可以碰牌、杠牌不能吃牌有东西南北中发白有癞子可以自摸,可以放炮其余的麻将知识请自行百度..._打牌游戏源代码

Flume之——org/apache/flume/tools/GetJavaProperty : Unsupported major.minor version 52.0-程序员宅基地

文章浏览阅读2.7k次。转载请注明出处:http://blog.csdn.net/l1028386804/article/details/79193639ng脚本问题,解决办法:增加如下红色字体add_HBASE_paths() { local HBASE_IN_PATH=$(PATH="${HBASE_HOME}/bin:$PATH" \ which hbase 2>/dev/null)...

自动设置纹理资源属性(一)_onpostprocesstexture 纹理路径-程序员宅基地

文章浏览阅读529次。实际项目中,我们会对指定的纹理设置不同平台不同属性。手动去设置操作量相对较大特别是资源持续性迭代的情况下,所以为了目标需求,我们需要去制作一个工具来设置我们导入的纹理资源。目标1:获取导入的纹理资源,并修改纹理资源属性。可用接口:AssetPostprocessor;TextureImporter。目标2:制作编辑器。 目标1实现:熟悉AssetPostprocessor接口..._onpostprocesstexture 纹理路径

Qt5学习之路01:直接使用QWidget类创建一个空的窗口_c++qt5如何创建一个无标题的窗口-程序员宅基地

文章浏览阅读5.7k次。main.cpp#include <QApplication>#include <QWidget>int main(int argc, char** argv){ QApplication app(argc, argv); QWidget w; w.resize(640, 320); w.move(400, 200); w..._c++qt5如何创建一个无标题的窗口

Kali之——OpenVAS 8.0 Vulnerability Scanning_openvas vulnerability scanner-程序员宅基地

文章浏览阅读1.4k次。Vulnerability scanning is a crucial phase of a penetration test and having an updated vulnerability scanner in your security toolkit can often make a real difference by helping you discover overlooked..._openvas vulnerability scanner

SAP ABAP 数据字典中的数量单位维护_abap 在zh下维护单位怎么维护-程序员宅基地

文章浏览阅读663次。SAP ABAP 数据字典中的数量单位维护在数据字典中创建构造时,出现如下错误。如图切换到 [通货/ 数量项目]页,对于该构造,其中的MENGE和NETRP字段需要进行维护。维护方法如下:去该字段所在系统表搜索该字段,并参照该字段的参照项目进行维护,以MENGE例。到系统表EKKO里使用快捷键Ctrl + F搜索”MENGE“字段。切换到 [通货/数量项目] 页,参照 [参照..._abap 在zh下维护单位怎么维护

随便推点

计算机经典书籍【转】-程序员宅基地

文章浏览阅读353次。【动机】就计算机这个专业来说吧,因为我是非科班出身的学生,要重新开始补相应的知识,目前定下来要学习的基础理论知识有:离散数学,数据结构与算法, 组成原理,汇编,操作系统,网络等等,有的时候觉得这里每一个知识点要学的深入的话都是无底洞,不过我又是那种喜欢追根究底的人,比如学习a知识的时候要 用到b知识,我会停下来学学b知识,然后一直这样下去.....有时候也会觉得很累,觉得没有一个尽头。最近也看..._计算机最严谨的书号称找到错够多就能致富

Android两种实现跳转网页的方式_andriod如何实现页面跳转-程序员宅基地

文章浏览阅读9.9k次。@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //方式一,Webview控件跳转网页 WebV_andriod如何实现页面跳转

DeepLabV3+(tensorflow)工程应用系列(一)—— 自己制作语义分割数据集_windows deeplabv3+ 安装-程序员宅基地

文章浏览阅读659次。一、概述  在实际的工程应用中,我们通常要制作自己的数据集,进而完成实际场景下的任务。关于语义分割任务数据集的基本介绍以及规范,请参考我总结的官网博客,PASCAL VOC 2012 数据集解析。在该系列博客中,将详细介绍【DeepLabV3+】的整个应用过程:数据制作,数据生成,代码解析,网络结构解析,论文翻译以及解析。二、软件安装(Labelme)  本次数据制作,选择普遍使用的标注软件,Labelme。该软件是一个图形界面的图像标注软件,来自于 http://labelme.csail.mit._windows deeplabv3+ 安装

OpenGL-立方体贴图之天空盒_天空盒贴图-程序员宅基地

文章浏览阅读8.3k次,点赞17次,收藏85次。目录天空盒天空盒简介天空盒加载天空盒显示优化举个栗子材料下载所用天空盒更多天空盒代码项目结构部分代码Cubemap.vertCubemap.fragmain.cpp结果截图资源下载参考:LearnOpenGL天空盒天空盒简介天空盒是一个包含了整个场景的(大)立方体,它包含周围环境的6个图像,让玩家以为他处在一个比实..._天空盒贴图

ALV双击事件_alv双击 rs_stable无值-程序员宅基地

文章浏览阅读1.1k次。实例一REPORT ZR_EXAMPLE_16.TABLES:MARA.TYPE-POOLS: SLIS.SELECT-OPTIONS:MATNR FOR MARA-MATNR OBLIGATORY.DATA:LT_MARA TYPE TABLE OF MARA WITH HEADER LINE, FIELDCAT TYPE SLIS_T_FIELDCAT_ALV WITH H..._alv双击 rs_stable无值

看懂XCP协议_xcp报文-程序员宅基地

文章浏览阅读3.5k次。XCP全称Universal Calibration Protocol,是由ASAM (Association for Standardization of Automation and Measuring Systems,简称 ASAM)组织在2003年提出的可在不同的通信总线上进行标定的新型标定协议,这里的X代表不同的传输层上传输(CAN、Ethernet、FlexRay、SCI、SPI、USB)。XCP的应用场景:上传ECU数据,实现对ECU内部变量进行观测;在线对ECU内部变量进行标定;ECU刷_xcp报文