P/Invoke之路2--c#调用 WindowsAPI

C#调用WindowsAPI

1.一个简单示例
2.数据类型对应关系
3.数据封送处理规则
4.DllImportAttribute说明
5.MarshalAsAttribute说明
6.UnmanagedType枚举说明

 

1.一个简单示例

User32.dll中非托管API之MessageBeep:

BOOL MessageBeep( UINT uType // beep type);

调用:

public class Test
{
[DllImport("User32.dll")]
static extern Boolean MessageBeep(UInt32 beepType);

static void Beep()
{
      MessageBeep(0);
}
}

2.c#托管数据类型与非托管API类型对应表:

API与C#的数据类型对应关系表
API数据类型 类型描述 C#类型 API数据类型 类型描述 C#类型
WORD 16位无符号整数 ushort CHAR 字符 char
LONG 32位无符号整数 int DWORDLONG 64位长整数 long
DWORD 32位无符号整数 uint HDC 设备描述表句柄 int
HANDLE 句柄,32位整数 int HGDIOBJ GDI对象句柄 int
UINT 32位无符号整数 uint HINSTANCE 实例句柄 int
BOOL 32位布尔型整数 bool HWM 窗口句柄 int
LPSTR 指向字符的32位指针 string HPARAM 32位消息参数 int
LPCSTR 指向常字符的32位指针 String LPARAM 32位消息参数 int
BYTE 字节 byte WPARAM 32位消息参数 int
LPDWORD 指向32位无符号的整数指针 out uint PVOID 或 LPVOID 不确定类型指针 IntPtr

 

 

 

 

 

 

 

 

 

 

 

3.数据封送:

1.值类型指针按out,ref方式封送

2.引用类型指针按类型直接封送

3.不透明指针和句柄按System.IntPtr封送

4.文本只有做输入按System.String,用作输入和输出按System.StringBuilder

5.两种方式可以知道处理字符串时信息的传递方向,第一个也是最可靠的一个方法就是首先理解参数的用途,第二种查找 API 参数类型中的字母“C”。
6.数组封送,
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] Phone;
7.字符串封送
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DevName;
等同于
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] devName;

4.函数调用-DllImportAttribute:

#region 程序集 mscorlib.dll, v4.0.0.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll
#endregion

using System;
using System.Reflection;
using System.Security;

namespace System.Runtime.InteropServices
{
    // 摘要:
    //     指示该特性化方法由非托管动态链接库 (DLL) 作为静态入口点公开。
    [AttributeUsage(AttributeTargets.Method, Inherited = false)]
    [ComVisible(true)]
    public sealed class DllImportAttribute : Attribute
    {
        // 摘要:
        //     将 Unicode 字符转换为 ANSI 字符时,启用或禁用最佳映射行为。
        public bool BestFitMapping;
        //
        // 摘要:
        //     指示入口点的调用约定。
        public CallingConvention CallingConvention;
        //
        // 摘要:
        //     指示如何向方法封送字符串参数,并控制名称重整。
        public CharSet CharSet;
        //
        // 摘要:
        //     指示要调用的 DLL 入口点的名称或序号。
        public string EntryPoint;
        //
        // 摘要:
        //     控制 System.Runtime.InteropServices.DllImportAttribute.CharSet 字段是否使公共语言运行时在非托管
        //     DLL 中搜索入口点名称,而不使用指定的入口点名称。
        public bool ExactSpelling;
        //
        // 摘要:
        //     指示是否直接转换具有 HRESULT 或 retval 返回值的非托管方法,或是否自动将 HRESULT 或 retval 返回值转换为异常。
        public bool PreserveSig;
        //
        // 摘要:
        //     指示被调用方在从特性化方法返回之前是否调用 SetLastError Win32 API 函数。
        public bool SetLastError;
        //
        // 摘要:
        //     启用或禁止在遇到被转换为 ANSI“?”字符的无法映射的 Unicode 字符时引发异常。字符。
        public bool ThrowOnUnmappableChar;

        // 摘要:
        //     使用包含要导入的方法的 DLL 的名称初始化 System.Runtime.InteropServices.DllImportAttribute
        //     类的新实例。
        //
        // 参数:
        //   dllName:
        //     包含非托管方法的 DLL 的名称。如果 DLL 包含在某个程序集中,则可以包含程序集显示名称。
        public DllImportAttribute(string dllName);

        // 摘要:
        //     获取包含入口点的 DLL 文件的名称。
        //
        // 返回结果:
        //     包含入口点的 DLL 文件的名称。
        public string Value { get; }
    }
}

5.数据封送-MarshalAsAttribute:

#region 程序集 mscorlib.dll, v4.0.0.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll
#endregion

using System;
using System.Reflection;
using System.Security;

namespace System.Runtime.InteropServices
{
    // 摘要:
    //     指示如何在托管代码和非托管代码之间封送数据。
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
    [ComVisible(true)]
    public sealed class MarshalAsAttribute : Attribute
    {
        // 摘要:
        //     指定非托管 System.Runtime.InteropServices.UnmanagedType.LPArray 或 System.Runtime.InteropServices.UnmanagedType.ByValArray
        //     的元素类型。
        public UnmanagedType ArraySubType;
        //
        // 摘要:
        //     指定 COM 使用的非托管 iid_is 特性的参数索引。
        public int IidParameterIndex;
        //
        // 摘要:
        //     向自定义封送拆收器提供附加信息。
        public string MarshalCookie;
        //
        // 摘要:
        //     指定自定义封送拆收器的完全限定名。
        [ComVisible(true)]
        public string MarshalType;
        //
        // 摘要:
        //     将 System.Runtime.InteropServices.MarshalAsAttribute.MarshalType 作为类型实现。
        [ComVisible(true)]
        public Type MarshalTypeRef;
        //
        // 摘要:
        //     指示 System.Runtime.InteropServices.UnmanagedType.SafeArray 的元素类型。
        public VarEnum SafeArraySubType;
        //
        // 摘要:
        //     指示用户定义的 System.Runtime.InteropServices.UnmanagedType.SafeArray 元素类型。
        public Type SafeArrayUserDefinedSubType;
        //
        // 摘要:
        //     指示固定长度数组中的元素数,或要导入的字符串中的字符(不是字节)数。
        public int SizeConst;
        //
        // 摘要:
        //     指示从零开始的参数,该参数包含数组元素的计数,与 COM 中的 size_is 类似。
        public short SizeParamIndex;

        // 摘要:
        //     使用指定的 System.Runtime.InteropServices.UnmanagedType 值初始化 System.Runtime.InteropServices.MarshalAsAttribute
        //     类的新实例。
        //
        // 参数:
        //   unmanagedType:
        //     数据将以其形式封送的值。
        public MarshalAsAttribute(short unmanagedType);
        //
        // 摘要:
        //     使用指定的 System.Runtime.InteropServices.UnmanagedType 枚举成员初始化 System.Runtime.InteropServices.MarshalAsAttribute
        //     类的新实例。
        //
        // 参数:
        //   unmanagedType:
        //     数据将以其形式封送的值。
        public MarshalAsAttribute(UnmanagedType unmanagedType);

        // 摘要:
        //     获取 System.Runtime.InteropServices.UnmanagedType 值,数据将被作为该值封送。
        //
        // 返回结果:
        //     System.Runtime.InteropServices.UnmanagedType 值,数据将被作为该值封送。
        public UnmanagedType Value { get; }
    }
}

6. 指定如何将参数或字段封送到非托管代码

#region 程序集 mscorlib.dll, v2.0.0.0
// C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll
#endregion

using System;

namespace System.Runtime.InteropServices
{
    // 摘要:
    //     指定如何将参数或字段封送到非托管代码。
    [Serializable]
    [ComVisible(true)]
    public enum UnmanagedType
    {
        // 摘要:
        //     4 字节布尔值(true != 0、false = 0)。这是 Win32 BOOL 类型。
        Bool = 2,
        //
        // 摘要:
        //     1 字节有符号整数。可使用此成员将布尔值转换为 1 字节、C 样式的 bool(true = 1、false = 0)。
        I1 = 3,
        //
        // 摘要:
        //     1 字节无符号整数。
        U1 = 4,
        //
        // 摘要:
        //     2 字节有符号整数。
        I2 = 5,
        //
        // 摘要:
        //     2 字节无符号整数。
        U2 = 6,
        //
        // 摘要:
        //     4 字节有符号整数。
        I4 = 7,
        //
        // 摘要:
        //     4 字节无符号整数。
        U4 = 8,
        //
        // 摘要:
        //     8 字节有符号整数。
        I8 = 9,
        //
        // 摘要:
        //     8 字节无符号整数。
        U8 = 10,
        //
        // 摘要:
        //     4 字节浮点数。
        R4 = 11,
        //
        // 摘要:
        //     8 字节浮点数。
        R8 = 12,
        //
        // 摘要:
        //     在 System.Decimal 上使用,以将十进制数值作为 COM 货币类型而不是 Decimal 封送。
        Currency = 15,
        //
        // 摘要:
        //     长度前缀为双字节的 Unicode 字符串。可以在 System.String 数据类型上使用此成员(它是 COM 中的默认字符串)。
        BStr = 19,
        //
        // 摘要:
        //     单字节、空终止的 ANSI 字符串。可在 System.String 或 System.Text.StringBuilder 数据类型上使用此成员。
        LPStr = 20,
        //
        // 摘要:
        //     一个 2 字节、空终止的 Unicode 字符串。
        LPWStr = 21,
        //
        // 摘要:
        //     与平台相关的字符串:在 Windows 98 上为 ANSI,在 Windows NT 和 Windows XP 上为 Unicode。该值仅对平台调用受支持,而对
        //     COM Interop 则不受支持,原因是不支持导出 LPTStr 类型的字符串。
        LPTStr = 22,
        //
        // 摘要:
        //     用于在结构中出现的内联定长字符数组。与 System.Runtime.InteropServices.UnmanagedType.ByValTStr
        //     一起使用的字符类型由应用于包含结构的 System.Runtime.InteropServices.StructLayoutAttribute 的
        //     System.Runtime.InteropServices.CharSet 参数确定。应始终使用 System.Runtime.InteropServices.MarshalAsAttribute.SizeConst
        //     字段来指示数组的大小。
        ByValTStr = 23,
        //
        // 摘要:
        //     COMIUnknown 指针。可以在 System.Object 数据类型上使用此成员。
        IUnknown = 25,
        //
        // 摘要:
        //     一个 COM IDispatch 指针(在 Microsoft Visual Basic 6.0 中为 Object)。
        IDispatch = 26,
        //
        // 摘要:
        //     一个用于封送托管格式化类和值类型的 VARIANT。
        Struct = 27,
        //
        // 摘要:
        //     COM 接口指针。从类元数据获得接口的 System.Guid。如果将此成员应用于类,则可以使用该成员指定确切的接口类型或默认的接口类型。当应用于
        //     System.Object 数据类型时,此成员将产生 System.Runtime.InteropServices.UnmanagedType.IUnknown
        //     行为。
        Interface = 28,
        //
        // 摘要:
        //     SafeArray 是自我描述的数组,它带有关联数组数据的类型、秩和界限。可将此成员与 System.Runtime.InteropServices.MarshalAsAttribute.SafeArraySubType
        //     字段一起使用,以重写默认元素类型。
        SafeArray = 29,
        //
        // 摘要:
        //     当 System.Runtime.InteropServices.MarshalAsAttribute.Value 设置为 ByValArray
        //     时,必须设置 System.Runtime.InteropServices.MarshalAsAttribute.SizeConst 以指示数组中的元素数。当需要区分字符串类型时,System.Runtime.InteropServices.MarshalAsAttribute.ArraySubType
        //     字段可以选择包含数组元素的 System.Runtime.InteropServices.UnmanagedType。此 System.Runtime.InteropServices.UnmanagedType
        //     只可用于作为结构中的字段的数组。
        ByValArray = 30,
        //
        // 摘要:
        //     与平台相关的有符号整数。在 32 位 Windows 上为 4 字节,在 64 位 Windows 上为 8 字节。
        SysInt = 31,
        //
        // 摘要:
        //     与平台相关的无符号整数。在 32 位 Windows 上为 4 字节,在 64 位 Windows 上为 8 字节。
        SysUInt = 32,
        //
        // 摘要:
        //     允许 Visual Basic 2005 在非托管代码中更改字符串,并将结果在托管代码中反映出来。该值仅对平台调用受支持。
        VBByRefStr = 34,
        //
        // 摘要:
        //     长度前缀为单字节的 ANSI 字符串。可以在 System.String 数据类型上使用此成员。
        AnsiBStr = 35,
        //
        // 摘要:
        //     一个有长度前缀的与平台相关的 char 字符串。在 Windows 98 上为 ANSI,在 Windows NT 上为 Unicode。很少用到这个类似于
        //     BSTR 的成员。
        TBStr = 36,
        //
        // 摘要:
        //     2 字节、OLE 定义的 VARIANT_BOOL 类型(true = -1、false = 0)。
        VariantBool = 37,
        //
        // 摘要:
        //     一个可用作 C 样式函数指针的整数。可将此成员用于 System.Delegate 数据类型或从 System.Delegate 继承的类型。
        FunctionPtr = 38,
        //
        // 摘要:
        //     一个动态类型,将在运行时确定对象的类型,并将该对象作为所确定的类型进行封送处理。仅对平台调用方法有效。
        AsAny = 40,
        //
        // 摘要:
        //     指向 C 样式数组的第一个元素的指针。当从托管到非托管进行封送处理时,该数组的长度由托管数组的长度确定。当从非托管到托管进行封送处理时,将根据 System.Runtime.InteropServices.MarshalAsAttribute.SizeConst
        //     和 System.Runtime.InteropServices.MarshalAsAttribute.SizeParamIndex 字段确定该数组的长度,当需要区分字符串类型时,还可以后跟数组中元素的非托管类型。
        LPArray = 42,
        //
        // 摘要:
        //     一个指针,它指向用于封送托管格式化类的 C 样式结构。仅对平台调用方法有效。
        LPStruct = 43,
        //
        // 摘要:
        //     当与 System.Runtime.InteropServices.MarshalAsAttribute.MarshalType 或 System.Runtime.InteropServices.MarshalAsAttribute.MarshalTypeRef
        //     一起使用时,指定自定义封送拆收器类。System.Runtime.InteropServices.MarshalAsAttribute.MarshalCookie
        //     字段可用于将附加信息传递给自定义封送拆收器。可以在任何引用类型上使用此成员。
        CustomMarshaler = 44,
        //
        // 摘要:
        //     此与 System.Runtime.InteropServices.UnmanagedType.I4 或 System.Runtime.InteropServices.UnmanagedType.U4
        //     关联的本机类型将导致参数作为导出类型库中的 HRESULT 导出。
        Error = 45,
    }
}

 

posted @ 2013-11-20 12:16  Roader  阅读(472)  评论(0编辑  收藏  举报