程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> C#中怎麼調用WinAPI函數

C#中怎麼調用WinAPI函數

編輯:C#基礎知識

在C#中經常需要調用一些API函數,那麼怎樣才能正確的調用API函數呢,如下:

 

一、調用API格式

 

//引用此名稱空間,簡化後面的代碼

usingSystem.Runtime.InteropServices;

...

 

//使用DllImportAttribute特性來引入api函數,注意聲明的是空方法,即方法體為空。

[DllImport("user32.dll")]

publicstaticexternReturnTypeFunctionName(typearg1,typearg2,...);

 

 

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

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

 

DllImportAttribute特性的幾個公共字段如下:

 

1、CallingConvention:指示向非托管實現傳遞方法參數時所用的CallingConvention值。

CallingConvention.Cdecl:調用方清理堆棧。它使您能夠調用具有varargs的函數。

CallingConvention.StdCall:被調用方清理堆棧。它是從托管代碼調用非托管函數的默認約定。

 

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

此字段被設置為CharSet值之一。如果CharSet字段設置為Unicode,則所有字符串參數在傳遞到非托管實現之前都轉換成Unicode字符。這還導致向DLLEntryPoint的名稱中追加字母“W”。如果此字段設置為Ansi,則字符串將轉換成ANSI字符串,同時向DLLEntryPoint的名稱中追加字母“A”。大多數Win32API使用這種追加“W”或“A”的約定。如果CharSet設置為Auto,則這種轉換就是與平台有關的(在WindowsNT上為Unicode,在Windows98上為Ansi)。CharSet的默認值為Ansi。CharSet字段也用於確定將從指定的DLL導入哪個版本的函數。CharSet.Ansi和CharSet.Unicode的名稱匹配規則大不相同。對於Ansi來說,如果將EntryPoint設置為“MyMethod”且它存在的話,則返回“MyMethod”。如果DLL中沒有“MyMethod”,但存在“MyMethodA”,則返回“MyMethodA”。對於Unicode來說則正好相反。如果將EntryPoint設置為“MyMethod”且它存在的話,則返回“MyMethodW”。如果DLL中不存在“MyMethodW”,但存在“MyMethod”,則返回“MyMethod”。如果使用的是Auto,則匹配規則與平台有關(在WindowsNT上為Unicode,在Windows98上為Ansi)。如果ExactSpelling設置為true,則只有當DLL中存在“MyMethod”時才返回“MyMethod”。

 

3、EntryPoint:指示要調用的DLL入口點的名稱或序號。

如果你的方法名不想與api函數同名的話,一定要指定此參數,例如:

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

publicstaticexternintMsgBox(IntPtrhWnd,stringtxt,stringcaption,inttype);

 

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

 

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

 

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

 

二、參數類型:

1、數值型直接用對應的就可。(DWORD->int,或uint,WORD->Int16)

2、API中字符串指針類型->.net中string,或者數組,如byte[]

3、API中句柄(dWord)->.net中IntPtr

4、API中結構->.net中結構或者類。注意這種情況下,要先用StructLayout特性限定聲明結構或類

 

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

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

[StructLayout(LayoutKind.Explicit,Size=16,CharSet=CharSet.Ansi)]

publicclassMySystemTime

{

[FieldOffset(0)]publicushortwYear;

[FieldOffset(2)]publicushortwMonth;

[FieldOffset(4)]publicushortwDayOfWeek;

[FieldOffset(6)]publicushortwDay;

[FieldOffset(8)]publicushortwHour;

[FieldOffset(10)]publicushortwMinute;

[FieldOffset(12)]publicushortwSecond;

[FieldOffset(14)]publicushortwMilliseconds;

}

 

例如:下面是API函數CreateNamedPipe的原函數:

WINBASEAPI

HANDLE

WINAPI

CreateNamedPipeW(

LPCWSTRlpName,

DWORDdwOpenMode,

DWORDdwPipeMode,

DWORDnMaxInstances,

DWORDnOutBufferSize,

DWORDnInBufferSize,

DWORDnDefaultTimeOut,

LPSECURITY_ATTRIBUTESlpSecurityAttributes

);

在C#中可這麼調用(封裝在類NamedPipeNative當中):

[DllImport("kernel32.dll",SetLastError=true)]

publicstaticexternIntPtrCreateNamedPipe(

       StringlpName,                                                        

       uintdwOpenMode,                                                  

       uintdwPipeMode,                                                   

       uintnMaxInstances,                                                

       uintnOutBufferSize,                                         

       uintnInBufferSize,

       uintnDefaultTimeOut,

       IntPtrpipeSecurityDescriptor       

);

 

使用實例:

IntPtrm_HPipe=NamedPipeNative.CreateNamedPipe(m_PipeName,

NamedPipeNative.PIPE_ACCESS_DUPLEX,//數據雙工通信

NamedPipeNative.PIPE_TYPE_MESSAGE|NamedPipeNative.PIPE_WAIT,//字節流,並且阻塞

100,//最大實例個數

128,//流出數據緩沖大小

128,//流入數據緩沖大小

150,//超時,毫秒

IntPtr.Zero//安全信息

);

其中CreateNamedPipe函數,還有PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE,PIPE_WAIT等字段都封裝在類NamedPipeNative當中,以便於調用。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved