C# 调用Windows API

一:入门, 直接从 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属性,将字符串作为 LPStrLPWStrLPTStrBStr 封送到非托管代码。某些 UnmanagedType枚举成员需要附加信息。
 
 
三:进阶,如何处理含有复杂的参数和返回值类型的API的调用(To Be Continue…)
 
 
参考文章
1.  Eric Gunnerson的《 使用 Win32 和其他库》(非常好!!!)
3.  《在 C# 中通过 P/Invoke 调用Win32 DLL》Jason Clark
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值