一:入门,直接从 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#调用windows API入门的更多相关文章

  1. C#调用windows API的一些方法

    使用C#调用windows API(从其它地方总结来的,以备查询) C#调用windows API也可以叫做C#如何直接调用非托管代码,通常有2种方法: 1.  直接调用从 DLL 导出的函数. 2. ...

  2. C#调用Windows API函数截图

    界面如下: 下面放了一个PictureBox 首先是声明函数: //这里是调用 Windows API函数来进行截图 //首先导入库文件 [System.Runtime.InteropServices ...

  3. 【转】用C#调用Windows API向指定窗口发送

    一.调用Windows API. C#下调用Windows API方法如下: 1.引入命名空间:using System.Runtime.InteropServices; 2.引用需要使用的方法,格式 ...

  4. C#中调用Windows API的要点 .

    介绍 API(Application Programming Interface),我想大家不会陌生,它是我们Windows编程的常客,虽然基于.Net平台的C#有了强大的类库,但是,我们还是不能否认 ...

  5. c# 判断窗体是否永在最前(TopMost),调用windows API

    许多程序都可以把自身的窗体设为最前显示状态,这个可以参考博客c#让窗体永在最前 调用windows api 将窗体设为topmost.那么如何判断桌面上的一个窗体是否为最前显示状态呢,不光是自己的程序 ...

  6. c#让窗体永在最前 调用windows api 将窗体设为topmost

    有时候应用程序需要将一个窗体始终位于屏幕的最前面,即使切换到其它窗体也能看到该窗体,这样的窗体就叫做TopMost窗体. 用C#制作TopMost窗体之前,首先要了解如何声明SetWindowPos函 ...

  7. 善于 调用Windows API

    前一段时间看见别人做的一个自动填写信息并且点击登录的程序,觉得很有意思. 其实就是在程序中调用Windows的API,那么如何调用,下面就做个简单的介绍. 写的简单粗暴, 不喜轻喷. 0.首先引入名称 ...

  8. C#中调用Windows API时的数据类型对应关系

    原文 C#中调用Windows API时的数据类型对应关系 BOOL=System.Int32 BOOLEAN=System.Int32 BYTE=System.UInt16 CHAR=System. ...

  9. 用C#调用Windows API向指定窗口发送按键消息 z

    用C#调用Windows API向指定窗口发送 一.调用Windows API. C#下调用Windows API方法如下: 1.引入命名空间:using System.Runtime.Interop ...

随机推荐

  1. android学习笔记30——AndroidMainfest.xml

    Manifest.xml文件的职责:指定APP的包名.声明四大组件, 以及启动方式.指定APP运行的进程名称.指定APP权限.指定最小API版本.指定需要连接的库. Manifest.xml的格式:& ...

  2. Expecting "jsp:param" standard action with "name" and "value" attributes错误

    错误信息如下: Servlet.service() for servlet [jsp] in context with path [/20161017] threw exception [/tag/s ...

  3. 关于mysql数据库在输入密码后,滴的一声直接退出界面的解决办法

    转自:http://www.2cto.com/database/201412/361751.html 网上搜索到的解决办法: 1.找到mysql安装目录下的bin目录路径.2.打开cmd,进入到bin ...

  4. gcc中动态库和静态库的链接顺序

    so文件:动态库a文件: 静态库exe文件:可执行程序(linux下以文件属性来标示是否是可执行文件,与后缀名无关) 经过自己写的一些测试程序,大致了解了下gcc中链接顺序问题,总结出以下几点:1,动 ...

  5. Linux大文件传输(转)

    我们经常需要在机器之间传输文件.比如备份,复制数据等等.这个是很常见,也是很简单的.用scp或者rsync就能很好的完成任务.但是如果文件很大,需要占用一些传输时间的时候,怎样又快又好地完成任务就很重 ...

  6. Unix commands in Mac OS X

    参考:http://www.renfei.org/blog/mac-os-x-terminal-101.html One command line includes 4 parts: Command ...

  7. bug_ _ 常见的bug1

    =====  3   java.lang.reflect.InvocationTargetException 异常解决方法 在做djunit测试的时候,发生下面异常: java.lang.reflec ...

  8. MySQL 绿色版安装方法图文教程

    一.下载,这里使用绿色解压缩版 http://mirror.services.wisc.edu/mysql/Downloads/MySQL-5.1/mysql-noinstall-5.1.32-win ...

  9. linux 好玩的命令

    发现一个linux好玩的命令,随机显示名言警句和诗词:fortune 和 fortune-zh (中文) cowsay: 小动物说话- ________________________________ ...

  10. windows service自动启动相关设置

    http://blog.csdn.net/thebesttome/article/details/7590025   原帖:http://www.cnblogs.com/junior/archive/ ...