使用C#調(diào)用windows API(從其它地方總結(jié)來的,,以備查詢) C#調(diào)用windows API也可以叫做C#如何直接調(diào)用非托管代碼,,通常有2種方法: 1. 直接調(diào)用從 DLL 導(dǎo)出的函數(shù)。 2. 調(diào)用 COM 對象上的接口方法 我主要討論從dll中導(dǎo)出函數(shù),,基本步驟如下: 1.使用 C# 關(guān)鍵字 static 和 extern 聲明方法,。 2.將 DllImport 屬性附加到該方法,。DllImport 屬性允許您指定包含該方法的 DLL 的名稱。 3.如果需要,,為方法的參數(shù)和返回值指定自定義封送處理信息,,這將重寫 .NET Framework 的默認封送處理。 1.首先我們查詢MSDN找到GetShortPathName的原型定義 DWORD GetShortPathName( LPCTSTR lpszLongPath, LPTSTR lpszShortPath, DWORD cchBuffer ); 2.查找對照表進行數(shù)據(jù)類型的轉(zhuǎn)換(出處:http://msdn.microsoft.com/msdnmag/issues/03/07/NET/default.aspx?fig=true )Data Win32 Types Specification CLR Type char, INT8, SBYTE, CHARa€ 8-bit signed integer System.SByte short, short int, INT16, SHORT 16-bit signed integer System.Int16 int, long, long int, INT32, LONG32, BOOLa€ , INT 32-bit signed integer System.Int32 __int64, INT64, LONGLONG 64-bit signed integer System.Int64 unsigned char, UINT8, UCHARa€ , BYTE 8-bit unsigned integer System.Byte unsigned short, UINT16, USHORT, WORD, ATOM, WCHARa€ , __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 a€ 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.調(diào)用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(…)是可選項,,在這里即使沒有,程序也是可以調(diào)用此API了,。 說明: 1.MSSQL_ServerHandler. GetShortPathName 方法用 static 和 extern 修飾符聲明并且具有 DllImport 屬性,,該屬性使用默認名稱GetShortPathName 通知編譯器此實現(xiàn)來自kernel32.dll。若要對 C# 方法使用不同的名稱(如 getShort),,則必須在 DllImport 屬性中使用 EntryPoint 選項,,如下所示: [DllImport("kernel32.dll", EntryPoint="getShort")] 2.使用MarshalAs(UnmanagedType.LPTStr)保證了在任何平臺上都會得到LPTStr,否則默認的方式會把從C#中的字符串作為BStr傳遞,。 現(xiàn)在如果是僅含有簡單參數(shù)和返回值的WIN32 API,,就都可以利用這種方法進行對照,簡單的改寫和調(diào)用了,。 二.背后的原理 ―― 知其所以然,,相關(guān)的知識 1.平臺調(diào)用詳原理 平臺調(diào)用依賴于元數(shù)據(jù)在運行時查找導(dǎo)出的函數(shù)并封送其參數(shù)。下圖顯示了這一過程,。 對非托管 DLL 函數(shù)的“平臺調(diào)用”調(diào)用 當“平臺調(diào)用”調(diào)用非托管函數(shù)時,,它將依次執(zhí)行以下操作: 查找包含該函數(shù)的 DLL。 將該 DLL 加載到內(nèi)存中,。 查找函數(shù)在內(nèi)存中的地址并將其參數(shù)推到堆棧上,,以封送所需的數(shù)據(jù)。 注意 只在第一次調(diào)用函數(shù)時,,才會查找和加載 DLL 并查找函數(shù)在內(nèi)存中的地址,。 將控制權(quán)轉(zhuǎn)移給非托管函數(shù)。 平臺調(diào)用會向托管調(diào)用方引發(fā)由非托管函數(shù)生成的異常,。 2.關(guān)于Attribute(屬性,,注意藍色字) 屬性可以放置在幾乎所有聲明中(但特定的屬性可能限制它在其上有效的聲明類型)。在語法上,,屬性的指定方法為:將括在方括號中的屬性名置于其適用的實體聲明之前,。例如,,具有 DllImport 屬性的類將聲明如下: [DllImport] public class MyDllimportClass { ... } 有關(guān)更多信息,請參見 DllImportAttribute 類,。 許多屬性都帶參數(shù),,而這些參數(shù)可以是定位(未命名)參數(shù)也可以是命名參數(shù)。任何定位參數(shù)都必須按特定順序指定并且不能省略,,而命名參數(shù)是可選的且可以按任意順序指定,。首先指定定位參數(shù)。例如,,這三個屬性是等效的: [DllImport("user32.dll", SetLastError=false, ExactSpelling=false)] [DllImport("user32.dll", ExactSpelling=false, SetLastError=false)] [DllImport("user32.dll")] 第一個參數(shù)(DLL 名稱)是定位參數(shù)并且總是第一個出現(xiàn),,其他參數(shù)為命名參數(shù)。在此例中,,兩個命名參數(shù)都默認為假,,因此它們可以省略(有關(guān)默認參數(shù)值的信息,請參見各個屬性的文檔),。 在一個聲明中可以放置多個屬性,,可分開放置,也可放在同一組括號中: 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() {...} 注意 根據(jù)約定,,所有屬性名稱都以單詞“Attribute”結(jié)束,以便將它們與 .NET Framework 中的其他項區(qū)分,。但是,,在代碼中使用屬性時不需要指定屬性后綴。例如,,[DllImport] 雖等效于 [DllImportAttribute],,但 DllImportAttribute 才是該屬性在 .NET Framework 中的實際名稱。 3.MarshalAsAttribute 類 指示如何在托管代碼和非托管代碼之間封送數(shù)據(jù),??蓪⒃搶傩詰?yīng)用于參數(shù)、字段或返回值,。 該屬性為可選屬性,因為每個數(shù)據(jù)類型都有默認的封送處理行為,。 大多數(shù)情況下,,該屬性只是使用 UnmanagedType 枚舉標識非托管數(shù)據(jù)的格式。 例如,,默認情況下,,公共語言運行庫將字符串參數(shù)作為 BStr 封送到 COM 方法,但是可以通過制定MarshalAs屬性,,將字符串作為 LPStr,、LPWStr,、LPTStr 或 BStr 封送到非托管代碼。某些 UnmanagedType 枚舉成員需要附加信息,。 下面,,就讓我們寫一個小程序,試一試如何用C#語言和DllImport特性來調(diào)用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類的實例,并把這個實例綁定在我們要使用的函數(shù)上了,?!疤匦灶悺边@種類非常怪——制造類實例的時候不使用MyClass mc = new MyClass();這種形式,而是使用[特性類(參數(shù)列表)]這種形式,;特性類不能獨立存在,,一定要用作修飾其它目標上(本例是修飾后面的一個函數(shù)),不同的特性可以用來修飾類,、函數(shù),、變量等等;特性類實例在被編譯的時候也不產(chǎn)生可執(zhí)行代碼,,而是被放進metadata里以備檢索,。總之,,你記住特性類很怪就是了,,想了解更多就查查MSDN,懶得查就先這么記——不懂慣性定律不影響你學(xué)騎自行車,。[DllImport("User32.dll")]是說我們要使用的Win32 API函數(shù)在User32.dll這個文件里,。問題又來了:我怎么知道那么多API函數(shù)都在哪個dll文件里呢?這個你可以在MSDN里查到,,位置是Root->Win32 and COM Development->Development Guides->Windows API->Windows API->Windows API Reference->Functions by Category,。打開這頁,你會看到有很多API的分類,,API全在這里了,。打開一個分類,比如Dialog Box,,在Functions段,,你會看到很多具體的函數(shù),其中就有上面用到的MessageBox函數(shù),,點擊進入,。你將打開MessageBox的詳細解釋和具體用法。它的名字、返回值,、參數(shù)類型盡收眼底,、一覽無余!而且很練英文哦~~~~在這一頁的底部,,你可以看到一個小表格,,里面有一項“Minimum DLL Version user32.dll”就是說這個函數(shù)在user32.dll里。 3. 接下來就是我們的函數(shù)了,。在C#里調(diào)用Win32函數(shù)有這么幾個要點,。 第一:名字要與Win32 API的完全一樣。 第二:函數(shù)除了要有相應(yīng)的DllImport類修飾外,,還要聲明成public static extern類型的,。 第三:也是最變態(tài)的一點,函數(shù)的返回值和參數(shù)類型要與Win32 API完全一致,! 常用Win32數(shù)據(jù)類型與.NET平臺數(shù)據(jù)類型的對應(yīng)表: 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函數(shù)為例(看剛才給出的函數(shù)表),,它的Win32原形如下: int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ); 函數(shù)名:MessageBox將保持不變。 返回值:int 將保持不變(無論是Win32還是C#,,int都是32位整數(shù)) 參數(shù)表:H開頭意味著是Handle,,一般情況下Handld都是指針類型,Win32平臺的指針類型是用32位來存儲的,,所以在C#里正好對應(yīng)一個int整型,。不過,既然是指針,,就沒有什么正負之分,,32位都應(yīng)該用來保存數(shù)值——這樣一來,用uint(無符號32位整型)來對應(yīng)Win32的H類型更合理,。不過提醒大家一點,,int是受C#和.NET CLR雙重支持的,而uint只受C#支持而不受.NET CLR支持,,所以,,本例還是老老實實地使用了int型。(肚子餓了……再堅持堅持……) 至于LPCTSTR是Long Pointer to Constant String的縮寫,,說白了就是——字符串,。所以,用C#里的string類型就對了,。 修飾符:要求有相應(yīng)的DllImport和public static extern 經(jīng)過上面一番折騰,,Win32的MessageBox函數(shù)就包裝成C#可以調(diào)用的函數(shù)了: [DllImport("User32.dll")] public static extern int MessageBox(int h, string m, string c, int type); 第一個:彈出的MessageBox的父窗口是誰。本例中沒有,,所以是0,也就是“空指針”,。 第二個:MessageBox的內(nèi)容,。本例中是“Hello Win32 API”,。 第三個:MessageBox的標題。本例中用的是本人Blog的名字——水之真諦——請大家不要忘記,。 第四個:MessageBox上的按鈕是什么,,如果是0,那就只有一個OK,,MessageBox太短了,,你將看不全“水之真諦”四個字,于是偶改成了4,,這樣就有兩個按鈕了,。這些在MSDN的函數(shù)用法里都有。不過,,我還是非常推薦您閱讀一下本人的另一篇拙作《一個Win32程序的進化》 ,。 三. 真的有必要嗎? .NET Framework是對Win32 API的良好封裝,,大部分Win32 API函數(shù)都已經(jīng)封裝在了.NET Framework類庫的各個類里了,。 下面是個例子 那是在很久很久以前,我給一個公司寫程序用來控制用戶登錄,,在登錄之前,,用戶不能把鼠標移出登錄窗體,因為要控制鼠標,,所以我首先想起了調(diào)用Win32 API中與Cursor相關(guān)的函數(shù)來——于是不管三七二十一,、花了九牛二虎之力調(diào)用了Win32 API中的ClipCursor()這個函數(shù),效果還不錯,。 結(jié)果前兩天翻.NET Framework類庫的時候,,發(fā)現(xiàn)System.Windows.Forms.Cursor類的Clip屬性就是專門做這個用的!差點沒把鼻子氣歪了……請大家自己動手創(chuàng)建一個C#的Windows程序,,把下面的核心代碼貼到主窗體的雙擊事件里,,試一試。做這個例子的目的就是要告訴大家:1.對類庫的了解程序直接決定了你編程的效率和質(zhì)量——用類庫里的組件比我們“從輪子造起”要快得多,、安全得多,。2.不到萬不得已,不要去直接調(diào)Win32 API函數(shù)——那是不安全的,。 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#為例簡單介紹調(diào)用API的基本過程: 動態(tài)鏈接庫函數(shù)聲明部分一般由下列兩部分組成,,一是函數(shù)名或索引號,,二是動態(tài)鏈接庫的文件名。 譬如,,你想調(diào)用User32.DLL中的MessageBox函數(shù),,我們必須指明函數(shù)的名字MessageBoxA或MessageBoxW,以及庫名字User32.dll,我們知道Win32 API對每一個涉及字符串和字符的函數(shù)一般都存在兩個版本,,單字節(jié)字符的ANSI版本和雙字節(jié)字符的UNICODE版本,。 下面是一個調(diào)用API函數(shù)的例子: [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標識函數(shù)在動態(tài)鏈接庫的入口位置,在一個受管轄的工程中,,目標函數(shù)的原始名字和序號入口點不僅標識一個跨越互操作界限的函數(shù),。而且,你還可以把這個入口點映射為一個不同的名字,,也就是對函數(shù)進行重命名,。重命名可以給調(diào)用函數(shù)帶來種種便利,通過重命名,,一方面我們不用為函數(shù)的大小寫傷透腦筋,,同時它也可以保證與已有的命名規(guī)則保持一致,允許帶有不同參數(shù)類型的函數(shù)共存,,更重要的是它簡化了對ANSI和Unicode版本的調(diào)用,。CharSet用于標識函數(shù)調(diào)用所采用的是Unicode或是ANSI版本,ExactSpelling=false將告訴編譯器,讓編譯器決定使用Unicode或者是Ansi版本,。其它的參數(shù)請參考MSDN在線幫助. 在C#中,,你可以在EntryPoint域通過名字和序號聲明一個動態(tài)鏈接庫函數(shù),如果在方法定義中使用的函數(shù)名與DLL入口點相同,,你不需要在EntryPoint域顯示聲明函數(shù),。否則,你必須使用下列屬性格式指示一個名字和序號,。 [DllImport("dllname", EntryPoint="Functionname")] [DllImport("dllname", EntryPoint="#123")] 值得注意的是,,你必須在數(shù)字序號前加“#” 下面是一個用MsgBox替換MessageBox名字的例子: using System.Runtime.InteropServices; [DllImport("user32.dll", EntryPoint="MessageBox")] public static extern int MsgBox(int hWnd, String text, String caption, uint type); 許多受管轄的動態(tài)鏈接庫函數(shù)期望你能夠傳遞一個復(fù)雜的參數(shù)類型給函數(shù),,譬如一個用戶定義的結(jié)構(gòu)類型成員或者受管轄代碼定義的一個類成員,,這時你必須提供額外的信息格式化這個類型,以保持參數(shù)原有的布局和對齊,。 C#提供了一個StructLayoutAttribute類,,通過它你可以定義自己的格式化類型,在受管轄代碼中,,格式化類型是一個用StructLayoutAttribute說明的結(jié)構(gòu)或類成員,,通過它能夠保證其內(nèi)部成員預(yù)期的布局信息,。布局的選項共有三種: 布局選項 描述 LayoutKind.Automatic 為了提高效率允許運行態(tài)對類型成員重新排序。 注意:永遠不要使用這個選項來調(diào)用不受管轄的動態(tài)鏈接庫函數(shù),。 LayoutKind.Explicit 對每個域按照FieldOffset屬性對類型成員排序 LayoutKind.Sequential 對出現(xiàn)在受管轄類型定義地方的不受管轄內(nèi)存中的類型成員進行排序,。 傳遞結(jié)構(gòu)成員 下面的例子說明如何在受管轄代碼中定義一個點和矩形類型,并作為一個參數(shù)傳遞給User32.dll庫中的PtInRect函數(shù),, 函數(shù)的不受管轄原型聲明如下: BOOL PtInRect(const RECT *lprc, POINT pt); 注意你必須通過引用傳遞Rect結(jié)構(gòu)參數(shù),因為函數(shù)需要一個Rect的結(jié)構(gòu)指針,。 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); 類似你可以調(diào)用GetSystemInfo函數(shù)獲得系統(tǒng)信息: 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); 類成員的傳遞 同樣只要類具有一個固定的類成員布局,,你也可以傳遞一個類成員給一個不受管轄的動態(tài)鏈接庫函數(shù),下面的例子主要說明如何傳遞一個sequential順序定義的MySystemTime類給User32.dll的GetSystemTime函數(shù), 函數(shù)用C/C++調(diào)用規(guī)范如下: void GetSystemTime(SYSTEMTIME* SystemTime); 不像傳值類型,類總是通過引用傳遞參數(shù). [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); 回調(diào)函數(shù)的傳遞: 從受管轄的代碼中調(diào)用大多數(shù)動態(tài)鏈接庫函數(shù),你只需創(chuàng)建一個受管轄的函數(shù)定義,,然后調(diào)用它即可,這個過程非常直接,。 如果一個動態(tài)鏈接庫函數(shù)需要一個函數(shù)指針作為參數(shù),你還需要做以下幾步: 首先,,你必須參考有關(guān)這個函數(shù)的文檔,,確定這個函數(shù)是否需要一個回調(diào);第二,,你必須在受管轄代碼中創(chuàng)建一個回調(diào)函數(shù),;最后,你可以把指向這個函數(shù)的指針作為一個參數(shù)創(chuàng)遞給DLL函數(shù),. 回調(diào)函數(shù)及其實現(xiàn): 回調(diào)函數(shù)經(jīng)常用在任務(wù)需要重復(fù)執(zhí)行的場合,譬如用于枚舉函數(shù),譬如Win32 API 中的EnumFontFamilies(字體枚舉), EnumPrinters(打印機), EnumWindows (窗口枚舉)函數(shù). 下面以窗口枚舉為例,談?wù)勅绾瓮ㄟ^調(diào)用EnumWindow 函數(shù)遍歷系統(tǒng)中存在的所有窗口 分下面幾個步驟: 1. 在實現(xiàn)調(diào)用前先參考函數(shù)的聲明 BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam) 顯然這個函數(shù)需要一個回調(diào)函數(shù)地址作為參數(shù). 2. 創(chuàng)建一個受管轄的回調(diào)函數(shù),這個例子聲明為代表類型(delegate),也就是我們所說的回調(diào),它帶有兩個參數(shù)hwnd和lparam,第一個參數(shù)是一個窗口句柄,,第二個參數(shù)由應(yīng)用程序定義,,兩個參數(shù)均為整形。 當這個回調(diào)函數(shù)返回一個非零值時,,標示執(zhí)行成功,,零則暗示失敗,這個例子總是返回True值,,以便持續(xù)枚舉,。 3. 最后創(chuàng)建以代表對象(delegate),并把它作為一個參數(shù)傳遞給EnumWindows 函數(shù),,平臺會自動地 把代表轉(zhuǎn)化成函數(shù)能夠識別的回調(diào)格式,。 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; } } 指針類型參數(shù)傳遞: 在Windows API函數(shù)調(diào)用時,大部分函數(shù)采用指針傳遞參數(shù),,對一個結(jié)構(gòu)變量指針,,我們除了使用上面的類和結(jié)構(gòu)方法傳遞參數(shù)之外,我們有時還可以采用數(shù)組傳遞參數(shù),。 下面這個函數(shù)通過調(diào)用GetUserName獲得用戶名 BOOL GetUserName( LPTSTR lpBuffer, // 用戶名緩沖區(qū) LPDWORD nSize // 存放緩沖區(qū)大小的地址指針 ); [DllImport("Advapi32.dll", EntryPoint="GetComputerName", ExactSpelling=false, SetLastError=true)] static extern bool GetComputerName ( [MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer, [MarshalAs(UnmanagedType.LPArray)] Int32[] nSize ); 這個函數(shù)接受兩個參數(shù),,char * 和int *,因為你必須分配一個字符串緩沖區(qū)以接受字符串指針,你可以使用String類代替這個參數(shù)類型,,當然你還可以聲明一個字節(jié)數(shù)組傳遞ANSI字符串,,同樣你也可以聲明一個只有一個元素的長整型數(shù)組,,使用數(shù)組名作為第二個參數(shù)。上面的函數(shù)可以調(diào)用如下: byte[] str=new byte[20]; Int32[] len=new Int32[1]; len[0]=20; GetComputerName (str,len); MessageBox.Show(System.Text.Encoding.ASCII.GetString(str)); C#與C++之間類型的對應(yīng) 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轉(zhuǎn)換時,,需要加入前綴[MarshalAs(UnmanagedType.LPStr)] LPDWORD 對應(yīng)于 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 [In] ref 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 操作系統(tǒng)上為 32 位,,在 64 位 Windows 操作系統(tǒng)上為 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. |
|