一:入门,直接从 C# 调用 DLL 导出
 
其实我们的议题应该叫做C#如何直接调用非托管代码,通常有2种方法:
1.  直接调用从 DLL 导出的函数。
2.  调用 COM 对象上的接口方法
我主要讨论从dll中导出函数,基本步骤如下:
1.使用 C# 关键字 static 和 extern 声明方法。
2.将 DllImport 属性附加到该方法。DllImport 属性允许您指定包含该方法的 DLL 的名称。
3.如果需要,为方法的参数和返回值指定自定义封送处理信息,这将重写 .NET Framework 的默认封送处理。
好,我们开始
1.首先我们查询MSDN找到GetShortPathName的定义
The GetShortPathName function retrieves the short path form of the specified path.
DWORD GetShortPathName(
  LPCTSTR lpszLongPath,
  LPTSTR lpszShortPath,
  DWORD cchBuffer
);
2.查找对照表进行数据类型的转换(出处:[url]http://msdn.microsoft.com/msdnmag/issues/03/07/NET/default.aspx?fig=true[/url]  Data Types
 
Win32 Types
Specification
CLR Type
char, INT8, SBYTE, CHAR†
8-bit signed integer
System.SByte
short, short int, INT16, SHORT
16-bit signed integer
System.Int16
int, long, long int, INT32, LONG32, BOOL†, INT
32-bit signed integer
System.Int32
__int64, INT64, LONGLONG
64-bit signed integer
System.Int64
unsigned char, UINT8, UCHAR†, BYTE
8-bit unsigned integer
System.Byte
unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR†, __wchar_t
16-bit unsigned integer
System.UInt16
unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT
32-bit unsigned integer
System.UInt32
unsigned __int64, UINT64, DWORDLONG, ULONGLONG
64-bit unsigned integer
System.UInt64
float, FLOAT
Single-precision floating point
System.Single
double, long double, DOUBLE
Double-precision floating point
System.Double
†In Win32 this type is an integer with a specially assigned meaning; in contrast, the CLR provides a specific type devoted to this meaning.
 
3.调用GetShortPathName这个API,简单的写法如下(编译通过的话),
using System;
using System.Runtime.InteropServices;
public class MSSQL_ServerHandler
{
[DllImport("kernel32.dll")]
public static extern int GetShortPathName
(
string path,
StringBuilder shortPath,
int shortPathLength
)
}
而我们之前的例子:
using System;
using System.Runtime.InteropServices;
public class MSSQL_ServerHandler
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetShortPathName
(
[MarshalAs(UnmanagedType.LPTStr)] string path,
[MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath,
int shortPathLength
)
}
对比可知,其中DllImport ,static,extern基本上是必须有的,其他CharSet,MarshalAs(…)是可选项,在这里即使没有,程序也是可以调用此API了。
说明:
1.MSSQL_ServerHandler. GetShortPathName 方法用 static 和 extern 修饰符声明并且具有 DllImport 属性,该属性使用默认名称GetShortPathName 通知编译器此实现来自kernel32.dll。若要对 C# 方法使用不同的名称(如getShort),则必须在 DllImport 属性中使用 EntryPoint 选项,如下所示:
[DllImport("kernel32.dll", EntryPoint="getShort")]
2使用MarshalAs(UnmanagedType.LPTStr)保证了在任何平台上都会得到LPTStr,否则默认的方式会把从C#中的字符串作为BStr传递。
 
现在如果是仅含有简单参数和返回值的WIN32 API,就都可以利用这种方法进行对照,简单的改写和调用了。
 
二.背后的原理 ―― 知其所以然,相关的知识
 1.平台调用详原理
平台调用依赖于元数据在运行时查找导出的函数并封送其参数。下图显示了这一过程。
对非托管 DLL 函数的“平台调用”调用
 
当“平台调用”调用非托管函数时,它将依次执行以下操作:
查找包含该函数的 DLL。
将该 DLL 加载到内存中。
查找函数在内存中的地址并将其参数推到堆栈上,以封送所需的数据。
注意   只在第一次调用函数时,才会查找和加载 DLL 并查找函数在内存中的地址。
将控制权转移给非托管函数。
平台调用会向托管调用方引发由非托管函数生成的异常。
 2.关于Attribute(属性,注意蓝色字)
属性可以放置在几乎所有声明中(但特定的属性可能限制它在其上有效的声明类型)。在语法上,属性的指定方法为:将括在方括号中的属性名置于其适用的实体声明之前。例如,具有 DllImport 属性的类将声明如下:
[DllImport] public class MyDllimportClass { ... }
有关更多信息,请参见 DllImportAttribute 类
许多属性都带参数,而这些参数可以是定位(未命名)参数也可以是命名参数。任何定位参数都必须按特定顺序指定并且不能省略,而命名参数是可选的且可以按任意顺序指定。首先指定定位参数。例如,这三个属性是等效的:
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
[DllImport("user32.dll")]
第一个参数(DLL 名称)是定位参数并且总是第一个出现,其他参数为命名参数。在此例中,两个命名参数都默认为假,因此它们可以省略(有关默认参数值的信息,请参见各个属性的文档)。
在一个声明中可以放置多个属性,可分开放置,也可放在同一组括号中:
bool AMethod([In][Out]ref double x);
bool AMethod([Out][In]ref double x);
bool AMethod([In,Out]ref double x);
某些属性对于给定实体可以指定多次。此类可多次使用的属性的一个示例是 Conditional
[Conditional("DEBUG"), Conditional("TEST1")] void TraceMethod() {...}
注意   根据约定,所有属性名称都以单词“Attribute”结束,以便将它们与 .NET Framework 中的其他项区分。但是,在代码中使用属性时不需要指定属性后缀。例如,[DllImport] 虽等效于 [DllImportAttribute],但 DllImportAttribute 才是该属性在 .NET Framework 中的实际名称。
3MarshalAsAttribute 
指示如何在托管代码和非托管代码之间封送数据。可将该属性应用于参数、字段或返回值。
该属性为可选属性,因为每个数据类型都有默认的封送处理行为。
大多数情况下,该属性只是使用 UnmanagedType 枚举标识非托管数据的格式。
例如,默认情况下,公共语言运行库将字符串参数作为 BStr 封送到 COM 方法,但是可以通过制定MarshalAs属性,将字符串作为 LPStrLPWStrLPTStr 或 BStr 封送到非托管代码。某些 UnmanagedType 枚举成员需要附加信息。
 
 
三:进阶,如何处理含有复杂的参数和返回值类型的API的调用(To Be Continue…)

使用c#调用API入门的更多相关文章

  1. 阿里云API网关(3)快速入门(调用 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  2. Web API 入门指南 - 闲话安全

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  3. 转载-Web API 入门

    An Introduction to ASP.NET Web API 目前感觉最好的Web API入门教程 HTTP状态码 Web API 强势入门指南 Install Mongodb Getting ...

  4. Hadoop MapReduce编程 API入门系列之压缩和计数器(三十)

    不多说,直接上代码. Hadoop MapReduce编程 API入门系列之小文件合并(二十九) 生成的结果,作为输入源. 代码 package zhouls.bigdata.myMapReduce. ...

  5. Web API入门指南(安全)转

    安全检测的工具站点:https://www.owasp.org/index.php/Category:Vulnerability_Scanning_Tools Web API入门指南有些朋友回复问了些 ...

  6. C#区域截图——调用API截图

    原文:C#区域截图——调用API截图 前言:截图对于一个C++开发者来说无非是小菜一碟,也有朋友使用C#的 Graphics.CopyFromScreen 方法屏幕操作,作为一名整天想着用 C++ 开 ...

  7. Web API 入门指南

    Web API 入门指南 - 闲话安全2013-09-21 18:56 by 微软互联网开发支持, 231 阅读, 3 评论, 收藏, 编辑 Web API入门指南有些朋友回复问了些安全方面的问题,安 ...

  8. 阿里云API网关(5)用户指南(调用 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  9. Web API 入门 二 媒体类型

    还是拿上面 那篇 Web API 入门 一  的那个来讲 在product类中加一个时间属性

随机推荐

  1. C++文件写入,读出函数ofstream,ifstream的使用方法

    ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间. 1.插入器(<<)  向流输出数据.比如说系统有一个默认的标准输出流(cout),一般情况下 ...

  2. mongodb 用户指引

    维护人:陈权 一.mongodb install on linuxcurl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.6 ...

  3. 【笔记6-支付及订单模块】从0开始 独立完成企业级Java电商网站开发(服务端)

    支付模块 实际开发工作中经常会遇见如下场景,一个支付模块,一个订单模块,有一定依赖,一个同事负责支付模块,另一个同事负责订单模块,但是开发支付模块的时候要依赖订单模块的相关类 ,方法,或者工具类,这些 ...

  4. 攻防世界 web 新手练习 刷题记录

    1.view_source 既然让看源码,那就F12直接就能看到. 2.robots 先百度去简单了解一下robots协议 robots协议(robots.txt),robots.txt文件在网站根目 ...

  5. buuctf——facebook1

    分为注册和登陆两个页面 据大佬wp登陆页面又盲注,但我没测试 直接注册后登陆 注册后发现,会显示输入的url 根据目录扫描,发现robots.txt和flag.php robots.txt有源码备份 ...

  6. cemtos安装python

    mkdir python3cd python3/yum -y install gcc*yum install zlib-devel bzip2-devel openssl-devel ncurses- ...

  7. JavaScript 深度遍历对象的两种方式,递归与非递归

    递归遍历: 基本问题: 当前属性值不为对象时,打印键和值 递归过程:当前属性值为对象时,打印键,继续递归 var o = { a: { b: { c: { d: { e: { f: 1, g:{ h: ...

  8. JMS消息传递的类型

    对于消息的传递有两种类型: 一种是点对点的,即一个生产者和一个消费者一一对应: 另一种是发布/ 订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进 行接收.

  9. 【Android多线程】异步信息处理机制

    https://www.bilibili.com/video/av65170691?p=3 (本文为此视频听课笔记) 一.线程和线程之间为什么要进行通讯 各线程之间要传递数据 二.线程和线程之间如何通 ...

  10. Java直通车——类与对象篇

    一.面向对象 教师节来临,一群小学生应召出黑板报,该怎样完成呢?对于一个小孩子来说,你告诉他:“我们要确定黑板报主题.明确内容要旨.搜寻具体内容.构思版面布局.画图和写字.安排人员后勤辅助.”他可能会 ...