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