C C C 呼叫非託管DLL的APIs

2021-04-21 15:18:37 字數 4073 閱讀 5020

上網baidu一下或google一下這個東東就有很多人在問這個問題,最近我也用到了 這個,所以就留下來以備往後需要是可以查詢。我想通過這個來作為c#呼叫windows apis的出發點,在以後的隨筆當中介紹一下我現階段用到的一些apis或非託管類庫。在呼叫非託管dll的apis前,我們應該好好掌握一下 dllimportattribute,msdn給出的定義為:可將該屬性應用於方法。dllimportattribute 屬性提供對從非託管 dll 匯出的函式進行呼叫所必需的資訊。作為最低要求,必須提供包含入口點的 dll 的名稱。

1[dllimport(

"kernel32.dll

", entrypoint="

movefilew

",     setlasterror

=true,2

3charset

=charset.unicode, exactspelling

=true,4

5callingconvention

=callingconvention.stdcall)]67

public

static

extern

bool

movefile(string src, string dst);89

從上面的例子中我們可以看出,從kernel32.dll中引入這個api,其中entrypoint一看就知道是入口點,也就是dll中的函式名稱。其 實只要用過vc++的人都知道,windows apis中都提供兩個版本,乙個是w,乙個是a也就是ansi和unicode之分,現在一般都採用w,unicode程式設計,但是.net和win32交 互的時候,預設是使用charset.ansi來傳送。在 dllimportattribute.exactspelling 欄位為 true 時(它是 visual basic .net 中的預設值),平台呼叫將只搜尋您指定的名稱。例如,如果指定 messagebox,則平台呼叫將搜尋 messagebox,如果它找不到完全相同的拼寫則失敗。當 exactspelling 欄位為 false(它是 c++ 託管擴充套件和 c# 中的預設值),平台呼叫將首先搜尋未處理的別名 (messagebox),如果沒有找到未處理的別名,則將搜尋已處理的名稱 (messageboxa)。

由於很多引數和c#中有所區別,下面讓我們看看引數是怎麼個情況:

extern 「c」 __declspec(dllexport)  int winapi sumab(int a,int b)這個和c#中一樣是值型別,a及b的變化不會對c#中的引數造成影響。通過dllimport表示為:

1[dllimport(「cppdll.dll")]

2//返回個int 型別

3public

static

extern

intsumab (

inta1,

intb1); 

下面的是引用型別:也就是說a和b的變化直接影響到a1和b1的值。

public

static

extern

intsum (

refint

a1,ref

intb1);

//dll中申明

extern

「c」 __declspec(dllexport)  

intwinapi sum(

int*

a,int

*b) 

同理我們可以得到一下幾種傳值方法:第一種引數的改變不影響c#中引數的變化,需要傳入char*型別。

[dllimport(「cppdll.dll")]

//傳入值

public

static

extern

inttogether (

string

astr,

string

bstr);

//dll中申明

extern

「c」 __declspec(dllexport)  

intwinapi together(

char

*stra,

char

*strb) 

當我們需要從引數中傳出char*型別是,那我們就要用到stringbuilder了。1//

傳出值2

public

static

extern

intgetparameter (stringbuilder sb1, stringbuilder sb2);3//

dll中申明

4extern

「c」 __declspec(dllexport)  

intwinapi getparameter(

char

*stra,

char

*strb) 

接著我們先來看看結構的封送,這裡我們要看看structlayoutattribute這個標籤,通過它可以定義自己的格式化型別,在託管**中,格式 化型別是乙個用structlayoutattribute說明的結構或類成員,通過它能夠保證其內部成員預期的布局資訊,他的成員說明如下:

layoutkind.automatic 為了提高效率允許執行態對型別成員重新排序。注意:永遠不要使用這個選項來呼叫非託管的動態鏈結庫函式。

layoutkind.explicit 對每個域按照fieldoffset屬性對型別成員排序

layoutkind.sequential 對出現在託管型別定義地方的非託管記憶體中的型別成員進行排序。

我們可以通過getsysteminfo來獲取系統的資訊,**如下:

1using

system.runtime.interopservices;

2[structlayout(layoutkind.sequential)]

3public

struct

system_info 

15//

呼叫16

[dllimport(

"kernel32")]

17static

extern

void

getsysteminfo(

refsystem_info psi);

18system_info psi 

=new

system_info();

19getsysteminfo(

refpsi);

當我們遇到函式指標引數是我們就需要考慮是否要用到**函式,例如列舉所有視窗。

bool enumwindows(wndenumproc lpenumfunc, lparmam iparam)

我們可以通過建立乙個**,它帶有兩個引數hwnd和lparam,第乙個引數是乙個視窗控制代碼,第二個引數由應用程式定義,兩個引數均為整形。當這個**函式返回乙個非零值時,標示執行成功,零則暗示失敗,這個例子總是返回true值,以便持續列舉。最後建立以**物件(delegate),並把它作為乙個引數傳遞給enumwindows 函式,平台會自動地 把**物件轉化成函式能夠識別的**格式。

1using

system;

2using

system.runtime.interopservices;

3public

delegate

bool

callback(

inthwnd, 

intlparam);

4public

class

5[dllimport(

"user32")]

6public

static

extern

intenumwindows(callback x, 

inty);

7public

static

void

main()812

public

static

bool

report(

inthwnd, 

intlparam) 17}

ok,如果熟悉了以上方方面面,基本上也能夠呼叫apis了別忘了p/invoke能夠幫上很大的忙,我們可以去wiki**查詢我們所要的api:http://pinvoke.net。還需要說明的是很多例子等都來自msdn和網上檢索得到的!!!

C C C 呼叫非託管DLL的APIs

上網baidu一下或google一下這個東東就有很多人在問這個問題,最近我也用到了這個,所以就留下來以備往後需要是可以查詢。我想通過這個來作為c 呼叫windows apis的出發點,在以後的隨筆當中介紹一下我現階段用到的一些apis或非託管類庫。在呼叫非託管dll的apis前,我們應該好好掌握一下...

託管呼叫非託管的DLL

dllimport createnewprocess.dll charset charset.unicode public static extern bool createprocess marshalas unmanagedtype.lpwstr string fullpath 以上是定義入口,...

託管非託管Dll動態呼叫

最近經常看到有人問託管非託管 dll呼叫的問題。對於動態庫的呼叫其實很簡單。網上很多 都實現了 dll的靜態呼叫方法。我主要談論下動態庫的動態載入。對於託管動態庫,實現動態載入很簡單。files dwwwing dlldemo.rar code assembly.loadfile filepath ...