现在的位置: 首页 > 综合 > 正文

.NET(C#)平台调用:DllImportAttribute.CharSet和字符串封送编码

2013年01月14日 ⁄ 综合 ⁄ 共 2937字 ⁄ 字号 评论关闭

首先如果您看下面代码有些费解的话,推荐先阅读以下MSDN上关于平台调用的指定字符集文章:http://msdn.microsoft.com/zh-cn/library/7b93s42f.aspx

 

学习.NET(C#)的平台调用和对象封送,你会发现其实同样的系统API函数的平台调用定义可以有多种形式的,本文就拿WinAPI的MessageBox开涮。

首先通过DllImportAttribute.CharSet来自动指定名称探索(根据DllImportAttribute.ExactSpelling)和字符串封送,比如,这三个函数的平台调用最常用定义(来自上面MSDN的页面)

 

第一个是MessageBox的ANSI函数(MessageBoxA),而DllImportAttribute得CharSet字段默认值就是CharSet.Ansi枚举值。

第二个是MessageBox的Unicode函数(MessageBoxW)。

最后一个MessageBox使用自动觉察字符集编码,NT系统会调用MessageBoxW(Unicode),而98会调用MessageBoxA(ANSI)。

[DllImport("user32.dll")]

public static extern int MessageBoxA(int hWnd, String text, String caption, uint type);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]

public static extern int MessageBoxW(int hWnd, String text, String caption, uint type);

[DllImport("user32.dll", CharSet = CharSet.Auto)]

public static extern int MessageBox(int hWnd, String text, String caption, uint type);

//98调用MessageBoxA, NT调用MessageBoxW

 

接下来把CharSet全部去掉(值默认是CharSet.Ansi)。

然后为了使Unicode的MessageBox工作,手动加入MarshalAs特性把字符串封送成UnmanagedType.LPWStr(Unicode字符串)。

而最后的MessageBox实际上只会调用MessageBoxA(ANSI的MessageBox函数),因为DllImportAttribute.ExactSpelling会根据CharSet去搜索,而这里CharSet是Ansi(后面的Unicode也类似)。

//默认都是CharSet.Ansi

 

[DllImport("user32.dll")]

public static extern int MessageBoxA(int hWnd, String text, String caption, uint type);

 

//手动通过MarshalAs特性把字符串以Unicode形式封送

[DllImport("user32.dll")]

public static extern int MessageBoxW(int hWnd,

    [MarshalAs(UnmanagedType.LPWStr)] String text,

    [MarshalAs(UnmanagedType.LPWStr)]String caption,

    uint type);

 

[DllImport("user32.dll")]

public static extern int MessageBox(int hWnd, String text, String caption, uint type);

//调用MessageBoxA

 

如果把CharSet全部改成Unicode,结果则是和上面相反。需要用MarshalAs特性特殊照顾一下MessageBoxA,而最后的MessageBox也只会调用MessageBoxW函数的。

//手动通过MarshalAs特性把字符串以ANSI形式封送

[DllImport("user32.dll", CharSet = CharSet.Unicode)]

public static extern int MessageBoxA(int hWnd,

    [MarshalAs(UnmanagedType.LPStr)]String text,

    [MarshalAs(UnmanagedType.LPStr)]String caption,

    uint type);

 

[DllImport("user32.dll", CharSet = CharSet.Unicode)]

public static extern int MessageBoxW(int hWnd, String text, String caption, uint type);

 

[DllImport("user32.dll", CharSet = CharSet.Unicode)]

public static extern int MessageBox(int hWnd, String text, String caption, uint type);

//调用MessageBoxW

 

最后如果CharSet全部是Auto,那么为了确保所有函数能正常工作,必须为MessageBox的ANSI和Unicode编码都添加MarshalAs,因为此时字符串的封送形式是不定的,当然如果你确定程序会在某个特定的编码环境中运行,那么其对应的定义可以省略。最后MessageBox的TCHAR定义和最上面的一样,即98调用MessageBoxA, NT调用MessageBoxW。

//MarshalAs可以省略如果是98系统

[DllImport("user32.dll", CharSet = CharSet.Auto)]

public static extern int MessageBoxA(int hWnd,

    [MarshalAs(UnmanagedType.LPStr)]String text,

    [MarshalAs(UnmanagedType.LPStr)]String caption,

    uint type);

 

//MarshalAs可以省略如果是NT系统

[DllImport("user32.dll", CharSet = CharSet.Auto)]

public static extern int MessageBoxW(int hWnd,

    [MarshalAs(UnmanagedType.LPWStr)]String text,

    [MarshalAs(UnmanagedType.LPWStr)]String caption, uint type);

 

[DllImport("user32.dll", CharSet = CharSet.Auto)]

public static extern int MessageBox(int hWnd, String text, String caption, uint type);

//98调用MessageBoxA, NT调用MessageBoxW

抱歉!评论已关闭.