C#調用windows API也能夠叫作C#如何直接調用非託管代碼,一般有2種方法:html
1. 直接調用從 DLL 導出的函數。編程
2. 調用 COM 對象上的接口方法小程序
我主要討論從dll中導出函數,基本步驟以下:windows
1.使用 C# 關鍵字 static 和 extern 聲明方法。api
2.將 DllImport 屬性附加到該方法。DllImport 屬性容許您指定包含該方法的 DLL 的名稱。數組
3.若是須要,爲方法的參數和返回值指定自定義封送處理信息,這將重寫 .NET Framework 的默認封送處理。安全
1.首先咱們查詢MSDN找到GetShortPathName的原型定義ide
DWORD GetShortPathName(函數
LPCTSTR lpszLongPath,佈局
LPTSTR lpszShortPath,
DWORD cchBuffer
);
2.查找對照表進行數據類型的轉換(出處:http://msdn.microsoft.com/msdnmag/issues/03/07/NET/default.aspx?fig=true )Data
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 中的實際名稱。
3.MarshalAsAttribute 類
指示如何在託管代碼和非託管代碼之間封送數據。可將該屬性應用於參數、字段或返回值。
該屬性爲可選屬性,由於每一個數據類型都有默認的封送處理行爲。
大多數狀況下,該屬性只是使用 UnmanagedType 枚舉標識非託管數據的格式。
例如,默認狀況下,公共語言運行庫將字符串參數做爲 BStr 封送到 COM 方法,可是能夠經過制定MarshalAs屬性,將字符串做爲 LPStr、LPWStr、LPTStr 或 BStr 封送到非託管代碼。某些 UnmanagedType 枚舉成員須要附加信息。
下面,就讓咱們寫一個小程序,試一試如何用C#語言和DllImport特性來調用Win32 API。
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
static int Main()
{
MessageBox(0, "Hello Win32 API", "水之真諦", 4);
Console.ReadLine();
return 0;
}
}
1. 要使用DllImport這個特性(特性也是一種類),必須使用這一句
using System.Runtime.InteropServices;
2. 而後咱們就能夠製造一個DllImport類的實例,並把這個實例綁定在咱們要使用的函數上了。「特性類」這種類很是怪——製造類實例的時候不使用MyClass mc = new MyClass();這種形式,而是使用[特性類(參數列表)]這種形式;特性類不能獨立存在,必定要用做修飾其它目標上(本例是修飾後面的一個函數),不一樣的特性能夠用來修飾類、函數、變量等等;特性類實例在被編譯的時候也不產生可執行代碼,而是被放進metadata裏以備檢索。總之,你記住特性類很怪就是了,想了解更多就查查MSDN,懶得查就先這麼記——不懂慣性定律不影響你學騎自行車。[DllImport("User32.dll")]是說咱們要使用的Win32 API函數在User32.dll這個文件裏。問題又來了:我怎麼知道那麼多API函數都在哪一個dll文件裏呢?這個你能夠在MSDN裏查到,位置是Root->Win32 and COM Development->Development Guides->Windows API->Windows API->Windows API Reference->Functions by Category。打開這頁,你會看到有不少API的分類,API全在這裏了。打開一個分類,好比Dialog Box,在Functions段,你會看到不少具體的函數,其中就有上面用到的MessageBox函數,點擊進入。你將打開MessageBox的詳細解釋和具體用法。它的名字、返回值、參數類型一覽無餘、盡收眼底!並且很練英文哦~~~~在這一頁的底部,你能夠看到一個小表格,裏面有一項「Minimum DLL Version user32.dll」就是說這個函數在user32.dll裏。
3. 接下來就是咱們的函數了。在C#裏調用Win32函數有這麼幾個要點。
第一:名字要與Win32 API的徹底同樣。
第二:函數除了要有相應的DllImport類修飾外,還要聲明成public static extern類型的。
第三:也是最變態的一點,函數的返回值和參數類型要與Win32 API徹底一致!
經常使用Win32數據類型與.NET平臺數據類型的對應表:
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. |
以MessageBox函數爲例(看剛纔給出的函數表),它的Win32原形以下:
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );
函數名:MessageBox將保持不變。
返回值:int 將保持不變(不管是Win32仍是C#,int都是32位整數)
參數表:H開頭意味着是Handle,通常狀況下Handld都是指針類型,Win32平臺的指針類型是用32位來存儲的,因此在C#里正好對應一個int整型。不過,既然是指針,就沒有什麼正負之分,32位都應該用來保存數值——這樣一來,用uint(無符號32位整型)來對應Win32的H類型更合理。不過提醒你們一點,int是受C#和.NET CLR雙重支持的,而uint只受C#支持而不受.NET CLR支持,因此,本例仍是老老實實地使用了int型。(肚子餓了……再堅持堅持……)
至於LPCTSTR是Long Pointer to Constant String的縮寫,說白了就是——字符串。因此,用C#裏的string類型就對了。
修飾符:要求有相應的DllImport和public static extern
通過上面一番折騰,Win32的MessageBox函數就包裝成C#能夠調用的函數了:
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
第一個:彈出的MessageBox的父窗口是誰。本例中沒有,因此是0,也就是「空指針」。
第二個:MessageBox的內容。本例中是「Hello Win32 API」。
第三個:MessageBox的標題。本例中用的是本人Blog的名字——水之真諦——請你們不要忘記。
第四個:MessageBox上的按鈕是什麼,若是是0,那就只有一個OK,MessageBox過短了,你將看不全「水之真諦」四個字,因而偶改爲了4,這樣就有兩個按鈕了。這些在MSDN的函數用法裏都有。不過,我仍是很是推薦您閱讀一下本人的另外一篇拙做《一個Win32程序的進化》 。
三. 真的有必要嗎?
.NET Framework是對Win32 API的良好封裝,大部分Win32 API函數都已經封裝在了.NET Framework類庫的各個類裏了。
下面是個例子
那是在好久好久之前,我給一個公司寫程序用來控制用戶登陸,在登陸以前,用戶不能把鼠標移出登陸窗體,由於要控制鼠標,因此我首先想起了調用Win32 API中與Cursor相關的函數來——因而無論三七二11、花了九牛二虎之力調用了Win32 API中的ClipCursor()這個函數,效果還不錯。
結果前兩天翻.NET Framework類庫的時候,發現System.Windows.Forms.Cursor類的Clip屬性就是專門作這個用的!差點沒把鼻子氣歪了……請你們本身動手建立一個C#的Windows程序,把下面的核心代碼貼到主窗體的雙擊事件裏,試一試。作這個例子的目的就是要告訴你們:1.對類庫的瞭解程序直接決定了你編程的效率和質量——用類庫裏的組件比咱們「從輪子造起」要快得多、安全得多。2.不到萬不得已,不要去直接調Win32 API函數——那是不安全的。
Rectangle r = new Rectangle(this.Left, this.Top, this.Width, this.Height);
System.Windows.Forms.Cursor.Clip = r;
最後,你們必定很是想知道,.NET Framework都爲咱們封裝好了哪些Win32 API,OK,MSDN裏有一篇文章,專門列出了這些。文章的名字是《Microsoft Win32 to Microsoft .NET Framework API Map》
下面以C#爲例簡單介紹調用API的基本過程:
動態連接庫函數聲明部分通常由下列兩部分組成,一是函數名或索引號,二是動態連接庫的文件名。
譬如,你想調用User32.DLL中的MessageBox函數,咱們必須指明函數的名字MessageBoxA或MessageBoxW,以及庫名字User32.dll,咱們知道Win32 API對每個涉及字符串和字符的函數通常都存在兩個版本,單字節字符的ANSI版本和雙字節字符的UNICODE版本。
下面是一個調用API函數的例子:
[DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern bool MoveFile(String src, String dst);
其中入口點EntryPoint標識函數在動態連接庫的入口位置,在一個受管轄的工程中,目標函數的原始名字和序號入口點不只標識一個跨越互操做界限的函數。並且,你還能夠把這個入口點映射爲一個不一樣的名字,也就是對函數進行重命名。重命名能夠給調用函數帶來種種便利,經過重命名,一方面咱們不用爲函數的大小寫傷透腦筋,同時它也能夠保證與已有的命名規則保持一致,容許帶有不一樣參數類型的函數共存,更重要的是它簡化了對ANSI和Unicode版本的調用。CharSet用於標識函數調用所採用的是Unicode或是ANSI版本,ExactSpelling=false將告訴編譯器,讓編譯器決定使用Unicode或者是Ansi版本。其它的參數請參考MSDN在線幫助.
在C#中,你能夠在EntryPoint域經過名字和序號聲明一個動態連接庫函數,若是在方法定義中使用的函數名與DLL入口點相同,你不須要在EntryPoint域顯示聲明函數。不然,你必須使用下列屬性格式指示一個名字和序號。
[DllImport("dllname", EntryPoint="Functionname")]
[DllImport("dllname", EntryPoint="#123")]
值得注意的是,你必須在數字序號前加「#」
下面是一個用MsgBox替換MessageBox名字的例子:
using System.Runtime.InteropServices;
[DllImport("user32.dll", EntryPoint="MessageBox")]
public static extern int MsgBox(int hWnd, String text, String caption, uint type);
許多受管轄的動態連接庫函數指望你可以傳遞一個複雜的參數類型給函數,譬如一個用戶定義的結構類型成員或者受管轄代碼定義的一個類成員,這時你必須提供額外的信息格式化這個類型,以保持參數原有的佈局和對齊。
C#提供了一個StructLayoutAttribute類,經過它你能夠定義本身的格式化類型,在受管轄代碼中,格式化類型是一個用StructLayoutAttribute說明的結構或類成員,經過它可以保證其內部成員預期的佈局信息。佈局的選項共有三種:
佈局選項
描述
LayoutKind.Automatic
爲了提升效率容許運行態對類型成員從新排序。
注意:永遠不要使用這個選項來調用不受管轄的動態連接庫函數。
LayoutKind.Explicit
對每一個域按照FieldOffset屬性對類型成員排序
LayoutKind.Sequential
對出如今受管轄類型定義地方的不受管轄內存中的類型成員進行排序。
傳遞結構成員
下面的例子說明如何在受管轄代碼中定義一個點和矩形類型,並做爲一個參數傳遞給User32.dll庫中的PtInRect函數,
函數的不受管轄原型聲明以下:
BOOL PtInRect(const RECT *lprc, POINT pt);
注意你必須經過引用傳遞Rect結構參數,由於函數須要一個Rect的結構指針。
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}
[StructLayout(LayoutKind.Explicit]
public struct Rect {
[FieldOffset(0)] public int left;
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right;
[FieldOffset(12)] public int bottom;
}
[DllImport("User32.dll")]
public static extern Bool PtInRect(ref Rect r, Point p);
相似你能夠調用GetSystemInfo函數得到系統信息:
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO {
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
[DllImport("kernel32")]
static extern void GetSystemInfo(ref SYSTEM_INFO pSI);
SYSTEM_INFO pSI = new SYSTEM_INFO();
GetSystemInfo(ref pSI);
類成員的傳遞
一樣只要類具備一個固定的類成員佈局,你也能夠傳遞一個類成員給一個不受管轄的動態連接庫函數,下面的例子主要說明如何傳遞一個sequential順序定義的MySystemTime類給User32.dll的GetSystemTime函數, 函數用C/C++調用規範以下:
void GetSystemTime(SYSTEMTIME* SystemTime);
不像傳值類型,類老是經過引用傳遞參數.
[StructLayout(LayoutKind.Sequential)]
public class MySystemTime {
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
[DllImport("User32.dll")]
public static extern void GetSystemTime(MySystemTime st);
回調函數的傳遞:
從受管轄的代碼中調用大多數動態連接庫函數,你只需建立一個受管轄的函數定義,而後調用它便可,這個過程很是直接。
若是一個動態連接庫函數須要一個函數指針做爲參數,你還須要作如下幾步:
首先,你必須參考有關這個函數的文檔,肯定這個函數是否須要一個回調;第二,你必須在受管轄代碼中建立一個回調函數;最後,你能夠把指向這個函數的指針做爲一個參數創遞給DLL函數,.
回調函數及其實現:
回調函數常常用在任務須要重複執行的場合,譬如用於枚舉函數,譬如Win32 API 中的EnumFontFamilies(字體枚舉), EnumPrinters(打印機), EnumWindows (窗口枚舉)函數. 下面以窗口枚舉爲例,談談如何經過調用EnumWindow 函數遍歷系統中存在的全部窗口
分下面幾個步驟:
1. 在實現調用前先參考函數的聲明
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)
顯然這個函數須要一個回調函數地址做爲參數.
2. 建立一個受管轄的回調函數,這個例子聲明爲表明類型(delegate),也就是咱們所說的回調,它帶有兩個參數hwnd和lparam,第一個參數是一個窗口句柄,第二個參數由應用程序定義,兩個參數均爲整形。
當這個回調函數返回一個非零值時,標示執行成功,零則暗示失敗,這個例子老是返回True值,以便持續枚舉。
3. 最後建立以表明對象(delegate),並把它做爲一個參數傳遞給EnumWindows 函數,平臺會自動地 把表明轉化成函數可以識別的回調格式。
using System;
using System.Runtime.InteropServices;
public delegate bool CallBack(int hwnd, int lParam);
public class EnumReportApp {
[DllImport("user32")]
public static extern int EnumWindows(CallBack x, int y);
public static void Main()
{
CallBack myCallBack = new CallBack(EnumReportApp.Report);
EnumWindows(myCallBack, 0);
}
public static bool Report(int hwnd, int lParam) {
Console.Write("窗口句柄爲");
Console.WriteLine(hwnd);
return true;
}
}
指針類型參數傳遞:
在Windows API函數調用時,大部分函數採用指針傳遞參數,對一個結構變量指針,咱們除了使用上面的類和結構方法傳遞參數以外,咱們有時還能夠採用數組傳遞參數。
下面這個函數經過調用GetUserName得到用戶名
BOOL GetUserName(
LPTSTR lpBuffer, // 用戶名緩衝區
LPDWORD nSize // 存放緩衝區大小的地址指針
);
[DllImport("Advapi32.dll", EntryPoint="GetComputerName", ExactSpelling=false,
SetLastError=true)]
static extern bool GetComputerName ( [MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer, [MarshalAs(UnmanagedType.LPArray)] Int32[] nSize );
這個函數接受兩個參數,char * 和int *,由於你必須分配一個字符串緩衝區以接受字符串指針,你可使用String類代替這個參數類型,固然你還能夠聲明一個字節數組傳遞ANSI字符串,一樣你也能夠聲明一個只有一個元素的長整型數組,使用數組名做爲第二個參數。上面的函數能夠調用以下:
byte[] str=new byte[20];
Int32[] len=new Int32[1];
len[0]=20;
GetComputerName (str,len);
MessageBox.Show(System.Text.Encoding.ASCII.GetString(str));
Windows Data Type |
.NET Data Type |
BOOL, BOOLEAN |
Boolean or Int32 |
BSTR |
String |
BYTE |
Byte |
CHAR |
Char |
DOUBLE |
Double |
DWORD |
Int32 or UInt32 |
FLOAT |
Single |
HANDLE (and all other handle types, such as HFONT and HMENU) |
IntPtr, UintPtr or HandleRef |
HRESULT |
Int32 or UInt32 |
INT |
Int32 |
LANGID |
Int16 or UInt16 |
LCID |
Int32 or UInt32 |
LONG |
Int32 |
LPARAM |
IntPtr, UintPtr or Object |
LPCSTR |
String |
LPCTSTR |
String |
LPCWSTR |
String |
LPSTR |
String or StringBuilder* |
LPTSTR |
String or StringBuilder |
LPWSTR |
String or StringBuilder |
LPVOID |
IntPtr, UintPtr or Object |
LRESULT |
IntPtr |
SAFEARRAY |
.NET array type |
SHORT |
Int16 |
TCHAR |
Char |
UCHAR |
SByte |
UINT |
Int32 or UInt32 |
ULONG |
Int32 or UInt32 |
VARIANT |
Object |
VARIANT_BOOL |
Boolean |
WCHAR |
Char |
WORD |
Int16 or UInt16 |
WPARAM |
IntPtr, UintPtr or Object |
|
|
另: 在進行string轉換時,須要加入前綴[MarshalAs(UnmanagedType.LPStr)]
LPDWORD 對應於 ref int
C/C++ |
C# |
HANDLE, LPDWORD, LPVOID, void* |
IntPtr |
LPCTSTR, LPCTSTR, LPSTR, char*, const char*, Wchar_t*, LPWSTR |
String [in], StringBuilder [in, out] |
DWORD, unsigned long, Ulong |
UInt32, [MarshalAs(UnmanagedType.U4)] |
bool |
bool |
LP<struct> |
[In] ref <struct> |
SIZE_T |
uint |
LPDWORD |
out uint |
LPTSTR |
[Out] StringBuilder |
PULARGE_INTEGER |
out ulong |
WORD |
uInt16 |
Byte, unsigned char |
byte |
Short |
Int16 |
Long, int |
Int32 |
float |
single |
double |
double |
NULL pointer |
IntPtr.Zero |
Uint |
Uint32 |
Wtypes.h 中的非託管類型 |
非託管 C 語言類型 |
託管類名 |
說明 |
HANDLE |
void* |
System.IntPtr |
在 32 位 Windows 操做系統上爲 32 位,在 64 位 Windows 操做系統上爲 64 位。 |
BYTE |
unsigned char |
System.Byte |
8 位 |
SHORT |
short |
System.Int16 |
16 位 |
WORD |
unsigned short |
System.UInt16 |
16 位 |
INT |
int |
System.Int32 |
32 位 |
UINT |
unsigned int |
System.UInt32 |
32 位 |
LONG |
long |
System.Int32 |
32 位 |
BOOL |
long |
System.Int32 |
32 位 |
DWORD |
unsigned long |
System.UInt32 |
32 位 |
ULONG |
unsigned long |
System.UInt32 |
32 位 |
CHAR |
char |
System.Char |
用 ANSI 修飾。 |
LPSTR |
char* |
System.String 或 System.Text.StringBuilder |
用 ANSI 修飾。 |
LPCSTR |
Const char* |
System.String 或 System.Text.StringBuilder |
用 ANSI 修飾。 |
LPWSTR |
wchar_t* |
System.String 或 System.Text.StringBuilder |
用 Unicode 修飾。 |
LPCWSTR |
Const wchar_t* |
System.String 或 System.Text.StringBuilder |
用 Unicode 修飾。 |
FLOAT |
Float |
System.Single |
32 位 |
DOUBLE |
Double |
System.Double |
64 位 |
BOOL=System.Int32 BOOLEAN=System.Int32 BYTE=System.UInt16 CHAR=System.Int16 COLORREF=System.UInt32 DWORD=System.UInt32 DWORD32=System.UInt32 DWORD64=System.UInt64 FLOAT=System.Float HACCEL=System.IntPtr HANDLE=System.IntPtr HBITMAP=System.IntPtr HBRUSH=System.IntPtr HCONV=System.IntPtr HCONVLIST=System.IntPtr HCURSOR=System.IntPtr HDC=System.IntPtr HDDEDATA=System.IntPtr HDESK=System.IntPtr HDROP=System.IntPtr HDWP=System.IntPtr HENHMETAFILE=System.IntPtr HFILE=System.IntPtr HFONT=System.IntPtr HGDIOBJ=System.IntPtr HGLOBAL=System.IntPtr HHOOK=System.IntPtr HICON=System.IntPtr HIMAGELIST=System.IntPtr HIMC=System.IntPtr HINSTANCE=System.IntPtr HKEY=System.IntPtr HLOCAL=System.IntPtr HMENU=System.IntPtr HMETAFILE=System.IntPtr HMODULE=System.IntPtr HMONITOR=System.IntPtr HPALETTE=System.IntPtr HPEN=System.IntPtr HRGN=System.IntPtr HRSRC=System.IntPtr HSZ=System.IntPtr HWINSTA=System.IntPtr HWND=System.IntPtr INT=System.Int32 INT32=System.Int32 INT64=System.Int64 LONG=System.Int32 LONG32=System.Int32 LONG64=System.Int64 LONGLONG=System.Int64 LPARAM=System.IntPtr LPBOOL=System.Int16[] LPBYTE=System.UInt16[] LPCOLORREF=System.UInt32[] LPCSTR=System.String LPCTSTR=System.String LPCVOID=System.UInt32 LPCWSTR=System.String LPDWORD=System.UInt32[] LPHANDLE=System.UInt32 LPINT=System.Int32[] LPLONG=System.Int32[] LPSTR=System.String LPTSTR=System.String LPVOID=System.UInt32 LPWORD=System.Int32[] LPWSTR=System.String LRESULT=System.IntPtr PBOOL=System.Int16[] PBOOLEAN=System.Int16[] PBYTE=System.UInt16[] PCHAR=System.Char[] PCSTR=System.String PCTSTR=System.String PCWCH=System.UInt32 PCWSTR=System.UInt32 PDWORD=System.Int32[] PFLOAT=System.Float[] PHANDLE=System.UInt32 PHKEY=System.UInt32 PINT=System.Int32[] PLCID=System.UInt32 PLONG=System.Int32[] PLUID=System.UInt32 PSHORT=System.Int16[] PSTR=System.String PTBYTE=System.Char[] PTCHAR=System.Char[] PTSTR=System.String PUCHAR=System.Char[] PUINT=System.UInt32[] PULONG=System.UInt32[] PUSHORT=System.UInt16[] PVOID=System.UInt32 PWCHAR=System.Char[] PWORD=System.Int16[] PWSTR=System.String REGSAM=System.UInt32 SC_HANDLE=System.IntPtr SC_LOCK=System.IntPtr SHORT=System.Int16 SIZE_T=System.UInt32 SSIZE_=System.UInt32 TBYTE=System.Char TCHAR=System.Char UCHAR=System.