一:入门,直接从 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. python正则表达式的学习记录

    match和findall的区别以及有括号和无括号的区别 strvar = "hello\n\nworld" find_re = re.compile("hello[.| ...

  2. 嵌入式设计模式:有限状态自动机的C语言实现

    转自:http://www.cnblogs.com/autosar/archive/2012/06/22/2558604.html 状态机模式是一种行为模式,在<设计模式>这本书中对其有详 ...

  3. activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建        (2)创建流程模型:activiti自定义流程之Spring ...

  4. 黄聪:wordpress如何使用get_avatar禁止调用gravatar头像,替换为自定义头像

    add_filter( 'get_avatar' , 'my_custom_avatar' , 1 , 5 ); function my_custom_avatar( $avatar, $id_or_ ...

  5. Skip StyleCop Warnings.

    [SuppressMessage("Microsoft.StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMust ...

  6. SCREAM:Error suppression ignored for

    wamp报错SCREAM:Error suppression ignored for 问题:SCREAM:Error suppression ignored for 解决: 在php.ini最下面加入 ...

  7. linuc c 代码示例

    fork的应用: #include "stdio.h" #include "string.h" #include <sys/types.h> #in ...

  8. Spring的AOP与代理

    spring 支持两种注入方式: setter/constructor 支持多种配置方式: xml/java5注解/java类配置 支持两种事务管理: 声明性/编程性 实际上上述方式只有一个就能保证系 ...

  9. HtmlparseUtil.java

    该类并不是一个通用的工具类,需要按自己的要求实现,这里只记录了Htmlparse.jar包的一些用法.仅此而已! 详细看这里:http://gundumw100.iteye.com/blog/7043 ...

  10. Django – query not equal

    The simpliest way to retrieve data from tables is take them all. To do this,  you can write: 1 all_e ...