使用c#調用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 中的實際名稱。
3 MarshalAsAttribute 
指示如何在托管代碼和非托管代碼之間封送數據。可將該屬性應用於參數、字段或返回值。
該屬性為可選屬性,因為每個數據類型都有默認的封送處理行為。
大多數情況下,該屬性只是使用  UnmanagedType 枚舉標識非托管數據的格式。
例如,默認情況下,公共語言運行庫將字符串參數作為  BStr 封送到 COM 方法,但是可以通過制定MarshalAs屬性,將字符串作為  LPStrLPWStrLPTStr 或  BStr 封送到非托管代碼。某些  UnmanagedType 枚舉成員需要附加信息。
 
 
三:進階,如何處理含有復雜的參數和返回值類型的API的調用(To Be Continue…)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM