欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中調用Windows API的技術要點說明

 更新時間:2014年01月22日 09:58:45   作者:  
本篇文章主要是對C#中調用Windows API的技術要點進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助

在.Net Framework SDK文檔中,關于調用Windows API的指示比較零散,并且其中稍全面一點的是針對Visual Basic .net講述的。本文將C#中調用API的要點匯集如下,希望給未在C#中使用過API的朋友一點幫助。另外如果安裝了Visual Studio .net的話,在C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Samples\Technologies\Interop\PlatformInvoke\WinAPIs\CS目錄下有大量的調用API的例子。

一、調用格式

復制代碼 代碼如下:

 using System.Runtime.InteropServices; //引用此名稱空間,簡化后面的代碼
...
//使用DllImportAttribute特性來引入api函數(shù),注意聲明的是空方法,即方法體為空。
[DllImport("user32.dll")]
public static extern ReturnType FunctionName(type arg1,type arg2,...);
//調用時與調用其他方法并無區(qū)別

可以使用字段進一步說明特性,用逗號隔開,如:
復制代碼 代碼如下:

[ DllImport( "kernel32", EntryPoint="GetVersionEx" )] 

DllImportAttribute特性的公共字段如下:
1、CallingConvention 指示向非托管實現(xiàn)傳遞方法參數(shù)時所用的 CallingConvention 值。
CallingConvention.Cdecl : 調用方清理堆棧。它使您能夠調用具有 varargs 的函數(shù)。
CallingConvention.StdCall : 被調用方清理堆棧。它是從托管代碼調用非托管函數(shù)的默認約定。

2、CharSet 控制調用函數(shù)的名稱版本及指示如何向方法封送 String 參數(shù)。

此字段被設置為 CharSet 值之一。如果 CharSet 字段設置為 Unicode,則所有字符串參數(shù)在傳遞到非托管實現(xiàn)之前都轉換成 Unicode 字符。這還導致向 DLL EntryPoint 的名稱中追加字母“W”。如果此字段設置為 Ansi,則字符串將轉換成 ANSI 字符串,同時向 DLL EntryPoint 的名稱中追加字母“A”。

大多數(shù) Win32 API 使用這種追加“W”或“A”的約定。如果 CharSet 設置為 Auto,則這種轉換就是與平臺有關的(在 Windows NT 上為 Unicode,在 Windows 98 上為 Ansi)。CharSet 的默認值為 Ansi。CharSet 字段也用于確定將從指定的 DLL 導入哪個版本的函數(shù)。

CharSet.Ansi 和 CharSet.Unicode 的名稱匹配規(guī)則大不相同。對于 Ansi 來說,如果將 EntryPoint 設置為“MyMethod”且它存在的話,則返回“MyMethod”。如果 DLL 中沒有“MyMethod”,但存在“MyMethodA”,則返回“MyMethodA”。

對于 Unicode 來說則正好相反。如果將 EntryPoint 設置為“MyMethod”且它存在的話,則返回“MyMethodW”。如果 DLL 中不存在“MyMethodW”,但存在“MyMethod”,則返回“MyMethod”。如果使用的是 Auto,則匹配規(guī)則與平臺有關(在 Windows NT 上為 Unicode,在 Windows 98 上為 Ansi)。如果 ExactSpelling 設置為 true,則只有當 DLL 中存在“MyMethod”時才返回“MyMethod”。

3、EntryPoint 指示要調用的 DLL 入口點的名稱或序號。
如果你的方法名不想與api函數(shù)同名的話,一定要指定此參數(shù),例如:

復制代碼 代碼如下:

[DllImport("user32.dll",CharSet="CharSet.Auto",EntryPoint="MessageBox")]
public static extern int MsgBox(IntPtr hWnd,string txt,string caption, int type);

4、ExactSpelling 指示是否應修改非托管 DLL 中的入口點的名稱,以與 CharSet 字段中指定的 CharSet 值相對應。如果為 true,則當 DllImportAttribute.CharSet 字段設置為 CharSet 的 Ansi 值時,向方法名稱中追加字母 A,當 DllImportAttribute.CharSet 字段設置為 CharSet 的 Unicode 值時,向方法的名稱中追加字母 W。此字段的默認值是 false。

5、PreserveSig 指示托管方法簽名不應轉換成返回 HRESULT、并且可能有一個對應于返回值的附加 [out, retval] 參數(shù)的非托管簽名。

6、SetLastError 指示被調用方在從屬性化方法返回之前將調用 Win32 API SetLastError。 true 指示調用方將調用 SetLastError,默認為 false。運行時封送拆收器將調用 GetLastError 并緩存返回的值,以防其被其他 API 調用重寫。用戶可通過調用 GetLastWin32Error 來檢索錯誤代碼。

二、參數(shù)類型:

1、數(shù)值型直接用對應的就可。(DWORD -> int , WORD -> Int16)
2、API中字符串指針類型 -> .net中string
3、API中句柄 (dWord)  -> .net中IntPtr
4、API中結構   -> .net中結構或者類。注意這種情況下,要先用StructLayout特性限定聲明結構或類

公共語言運行庫利用StructLayoutAttribute控制類或結構的數(shù)據字段在托管內存中的物理布局,即類或結構需要按某種方式排列。如果要將類傳遞給需要指定布局的非托管代碼,則顯式控制類布局是重要的。它的構造函數(shù)中用LayoutKind值初始化 StructLayoutAttribute 類的新實例。 LayoutKind.Sequential 用于強制將成員按其出現(xiàn)的順序進行順序布局。

LayoutKind.Explicit 用于控制每個數(shù)據成員的精確位置。利用 Explicit, 每個成員必須使用 FieldOffsetAttribute 指示此字段在類型中的位置。如:

復制代碼 代碼如下:

 [StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public class MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset(2)]public ushort wMonth;
[FieldOffset(4)]public ushort wDayOfWeek;
[FieldOffset(6)]public ushort wDay;
[FieldOffset(8)]public ushort wHour;
[FieldOffset(10)]public ushort wMinute;
[FieldOffset(12)]public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}

下面是針對API中OSVERSIONINFO結構,在.net中定義對應類或結構的例子:
復制代碼 代碼如下:

  /**********************************************
* API中定義原結構聲明
* OSVERSIONINFOA STRUCT
*  dwOSVersionInfoSize   DWORD      ?
*  dwMajorVersion        DWORD      ?
*  dwMinorVersion        DWORD      ?
*  dwBuildNumber         DWORD      ?
*  dwPlatformId          DWORD      ?
*  szCSDVersion          BYTE 128 dup (?)
* OSVERSIONINFOA ENDS
*
* OSVERSIONINFO  equ  <OSVERSIONINFOA>
*********************************************/
 
復制代碼 代碼如下:

 //.net中聲明為類
[ StructLayout( LayoutKind.Sequential )]  
public class OSVersionInfo
{  
public int OSVersionInfoSize;
public int majorVersion;
public int minorVersion;
public int buildNumber;
public int platformId;
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]   
public String versionString;
}
//或者
//.net中聲明為結構
[ StructLayout( LayoutKind.Sequential )] 
public struct OSVersionInfo2
{
public int OSVersionInfoSize;
public int majorVersion;
public int minorVersion;
public int buildNumber;
public int platformId;

復制代碼 代碼如下:

[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]   
public String versionString;
}

此例中用到MashalAs特性,它用于描述字段、方法或參數(shù)的封送處理格式。用它作為參數(shù)前綴并指定目標需要的數(shù)據類型。例如,以下代碼將兩個參數(shù)作為數(shù)據類型長指針封送給 Windows API 函數(shù)的字符串 (LPStr):
復制代碼 代碼如下:

 [MarshalAs(UnmanagedType.LPStr)]
String existingfile;
[MarshalAs(UnmanagedType.LPStr)]
String newfile;

注意結構作為參數(shù)時候,一般前面要加上ref修飾符,否則會出現(xiàn)錯誤:對象的引用沒有指定對象的實例。
復制代碼 代碼如下:

 [ DllImport( "kernel32", EntryPoint="GetVersionEx" )]
public static extern bool GetVersionEx2( ref OSVersionInfo2 osvi ); 

三、如何保證使用托管對象的平臺調用成功?
如果在調用平臺 invoke 后的任何位置都未引用托管對象,則垃圾回收器可能將完成該托管對象。這將釋放資源并使句柄無效,從而導致平臺invoke 調用失敗。用 HandleRef 包裝句柄可保證在平臺 invoke 調用完成前,不對托管對象進行垃圾回收。

例如下面:

復制代碼 代碼如下:

 FileStream fs = new FileStream( "a.txt", FileMode.Open );
StringBuilder buffer = new StringBuilder( 5 );
int read = 0;
ReadFile(fs.Handle, buffer, 5, out read, 0 ); //調用Win API中的ReadFile函數(shù)

由于fs是托管對象,所以有可能在平臺調用還未完成時候被垃圾回收站回收。將文件流的句柄用HandleRef包裝后,就能避免被垃圾站回收:
復制代碼 代碼如下:

 [ DllImport( "Kernel32.dll" )]
public static extern bool ReadFile(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
ref Overlapped flag );
......
......
FileStream fs = new FileStream( "HandleRef.txt", FileMode.Open );
HandleRef hr = new HandleRef( fs, fs.Handle );
StringBuilder buffer = new StringBuilder( 5 );
int read = 0;
// platform invoke will hold reference to HandleRef until call ends
ReadFile( hr, buffer, 5, out read, 0 );

相關文章

  • C#基礎入門之算法:交換

    C#基礎入門之算法:交換

    本文主要介紹了C#中算法:交換的相關知識,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • C#提取網頁中超鏈接link和text部分的方法

    C#提取網頁中超鏈接link和text部分的方法

    這篇文章主要介紹了C#提取網頁中超鏈接link和text部分的方法,涉及C#正則表達式及字符串操作相關技巧,需要的朋友可以參考下
    2016-02-02
  • C#?使用PrintDocument類打印標簽的方法

    C#?使用PrintDocument類打印標簽的方法

    本文介紹打印機初步配置,以及實現(xiàn)方法,標簽主要展示資產基本信息以及二維碼,對C#?使用PrintDocument類打印標簽的詳細過程感興趣的朋友一起看看吧
    2022-04-04
  • C# 批處理調用方法

    C# 批處理調用方法

    當批處理和aspx不在同一目錄中時,最好用WorkingDirectory設置啟動的進程的初始目錄為批處理所在目錄,否則如上例中批處理新建的目錄就應在aspx所在目錄中而不是批處理所在目錄了!
    2008-12-12
  • C#異常處理的技巧和方法

    C#異常處理的技巧和方法

    在本篇文章里小編給大家整理了關于C#異常處理的技巧和方法以及相關知識點,需要的朋友們學習下。
    2019-03-03
  • C#判斷訪問來源是否為搜索引擎鏈接的方法

    C#判斷訪問來源是否為搜索引擎鏈接的方法

    這篇文章主要介紹了C#判斷訪問來源是否為搜索引擎鏈接的方法,實例分析了C#解析URL來源的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • C#并查集(union-find)算法詳解

    C#并查集(union-find)算法詳解

    本文詳細講解了C#并查集(union-find)算法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • C#實現(xiàn)飛行棋項目

    C#實現(xiàn)飛行棋項目

    這篇文章主要為大家詳細介紹了C#實現(xiàn)飛行棋項目,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • c#系列 list詳情

    c#系列 list詳情

    這篇文章主要介紹了c#系列 list,list 本質是一個數(shù)組,。就跟我們操作系統(tǒng)一樣,提前申請內存大小。所以我們程序一般都有一個申請內存,實際使用內存,內存碎片這幾個概念,下面?zhèn)z看文章詳細內容吧
    2021-10-10
  • Unity3D自定義創(chuàng)建圓錐體

    Unity3D自定義創(chuàng)建圓錐體

    這篇文章主要為大家詳細介紹了Unity3D自定義創(chuàng)建圓錐體,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02

最新評論