C C C 呼叫非託管DLL的APIs

2021-04-30 13:11:51 字數 4220 閱讀 2859

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

1  [dllimport(

" kernel32.dll

" , entrypoint

= "movefilew

" ,     setlasterror

= true

,2  3 

charset

= charset.unicode, exactspelling

= true

,4  5 

callingconvention

= callingconvention.stdcall)]6 

7  public

static

extern

bool

movefile(string src, string dst);8 

9 從上面的例子中我們可以看出,從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 型別 3 

public

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中申明 4 

extern

「c」 __declspec(dllexport)  

intwinapi getparameter(

char

*stra,

char

*strb) 

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

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

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

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

1  using

system.runtime.interopservices;

2  [structlayout(layoutkind.sequential)]

3      

public

struct

system_info 

15  //

呼叫 16  [dllimport(

" kernel32

" )]

17  static

extern

void

getsysteminfo(

refsystem_info psi);

18  system_info psi 

=  new

system_info();

19  getsysteminfo(

refpsi);

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

bool enumwindows(wndenumproc lpenumfunc, lparmam iparam)

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

1  using

system;

2  using

system.runtime.interopservices;

3  public

delegate

bool

callback(

inthwnd, 

intlparam);

4  public

class

[dllimport(

" user32

" )]

6  public

static

extern

intenumwindows(callback x, 

inty);

7  public

static

void

main()8 

12  public

static

bool

report(

inthwnd, 

intlparam) 

17  }

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

原創: http://www.cnblogs.com/xdotnet/archive/2007/08/10/csharp_cpp_dll_pinvoke.html

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 ...