古詩詞大全網 - 藝術簽名 - 求高手幫忙!!怎麽才能調用處理數組的函數!

求高手幫忙!!怎麽才能調用處理數組的函數!

首先要在C#語言的源程序中聲明外部方法,其基本形式是:

[[DLLImport("DLL文件")]

修飾符extern返回變量類型方法名(參數列表)

其中包括:

DLL文件:包含外部方法的庫文件。

修飾符:訪問修飾符,可以在聲明除abstract以外的方法時使用。

返回變量類型:在DLL文件中,需要調用方法的返回變量類型。

方法名:您需要在DLL文件中調用的方法的名稱。

參數列表:需要在DLL文件中調用的方法列表。

註意:需要使用系統。程序聲明中的Runtime.InteropServices命名空間。

DllImport只能放在方法聲明上。

DLL文件必須位於程序的當前目錄中或系統定義的查詢路徑中(即系統環境變量Path中設置的路徑)。

返回變量類型、方法名和參數列表必須與DLL文件中的定義壹致。

若要使用其他函數名,可以使用EntryPoint屬性設置,例如:

[DllImport("user32.dll ",EntryPoint="MessageBoxA")]

靜態extern int MsgBox(int hWnd,string msg,string caption,int type);

其他可選的DllImportAttribute屬性:

CharSet表示入口點中使用的字符集,例如CharSet=CharSet。Ansi;

SetLastError指示該方法是否保留Win32“最後壹個錯誤”,例如,SetLastError = true;

ExactSpelling指示EntryPoint是否必須與所指示的入口點的拼寫完全匹配,例如ExactSpelling=false。;

PreserveSig表示方法的簽名是應該保留還是轉換,比如:PreserveSig = true;

CallingConvention表示入口點的調用約定,如:calling conventi on = calling conventi on . winapi;

另外,請參考其他壹些關於“數據封送”和“封送數字和邏輯標量”的文章[2]。

C#示例:

1.啟動VS.NET,創建壹個名為“Tzb”的新項目,模板為“Windows應用程序”。

2.雙擊工具箱中Windows窗體項中的Button項,向窗體1添加壹個按鈕。

3.更改按鈕的屬性:名稱為“B1”,文本為“調用DllImport彈出提示框”,將按鈕B1調整到合適的大小,移動到合適的位置。

4.在類視圖中雙擊“Form1”,打開“Form1.cs”的代碼視圖,輸入“使用系統。runtime.interop服務在“命名空間Tzb”上。導入命名空間。

5.雙擊“表格1”中的按鈕B1。CS”視圖中,在“B1_Click”方法上方用關鍵字static和extern聲明方法“MsgBox”,並將DllImport屬性附加到該方法。這裏我們要用“user32.dll”。

[DllImport("user32.dll ",EntryPoint="MessageBoxA")]

靜態extern int MsgBox(int hWnd,string msg,string caption,int type);

然後在“B1_Click”方法體中添加以下代碼,以調用方法“MsgBox”:

MsgBox(0,“這是調用DllImport時彈出的提示框!”,“挑戰杯”,0x 30);

6.按F5運行程序,點擊B1,彈出如下提示框:

(2)動態加載和調用DLL中的非托管函數。

上面已經解釋了如何使用DllImport調用DLL中的非托管函數,但這是壹個全局函數。如果DLL中的非托管函數有壹個靜態變量S,那麽每次調用這個函數時,靜態變量S都會自動加上1。結果當需要重新計數時,得不到想要的結果。下面將通過例子來說明:

創建1。動態鏈接庫

1)啟動Visual c++ 6.0;;

2)新建壹個名為“Win32動態鏈接庫”的項目;

3)在“dll種類”選擇界面選擇“壹個簡單的Dll項目”;

4)打開Count.cpp並添加以下代碼:

//導出函數,由“_stdcall”標準調用。

extern " C " _ declspec(dll export)int _ stdcall count(int init);

int _stdcall計數(int init)

{//count函數,用參數init初始化靜態塑料變量S,使S返回加1後的值。

static int S = init

s++;

返回S;

}

5)按“F7”編譯並獲取Count.dll(在項目目錄下的調試文件夾中)。

2.用DllImport調用DLL中的count函數。

1)打開項目“Tzb”並向“Form1”窗體添加壹個按鈕。

2)更改按鈕的屬性:名稱為“B2”,文本為“調用DllImport中的計數函數”,將按鈕B1調整到合適的大小,移動到合適的位置。

3)打開“Form1.cs”的代碼視圖,用關鍵字static和extern聲明方法“count ”,使其具有從Count.dll導出函數count的實現。代碼如下:

[DllImport("Count.dll")]

靜態外部整數計數(整數初始化);

4)在"窗體1 "視圖中雙擊按鈕B2。CS”,並在“B2_Click”方法的正文中添加以下代碼:

MessageBox。Show("調用DllImport中的count函數,傳入的參數為0,結果為"+count(0)。ToString(),“挑戰杯”);

MessageBox。Show("調用DllImport中的count函數,傳入的參數是10,結果是:"+count (10)。tostring()+" n結果不是預期的11!!! "、“挑戰杯”);

MessageBox。Show("結果表明在DllImport中調用非托管n函數是壹個全局的靜態函數!!! "、“挑戰杯”);

5)將Count.dll復制到項目“Tzb”的binDebug文件夾中,按“F5”運行程序,點擊B2按鈕,彈出如下三個提示框:

提示框1顯示調用“count(0)”的結果,第二個提示框顯示調用“count(10)”的結果,證明“在DllImport中調用非托管函數是壹個全局靜態函數”。所以,有時我們無法達到目的,所以我們需要使用以下方法:C#動態調用DLL中的函數。

3.C#動態調用DLL中的函數

因為在C#中使用DllImport不能像動態加載/卸載匯編壹樣,只能使用API函數。在kernel32.dll,與動態庫調用相關的功能包括[3]:

①LoadLibrary(或MFC的AfxLoadLibrary)加載動態庫。

②GetProcAddress,獲取要引入的函數,將符號名或標識號轉換成DLL的內部地址。

③FreeLibrary(或MFC的AfxFreeLibrary),釋放動態鏈接庫。

他們的原型是:

h module LoadLibrary(LPCTSTR lpFileName);

FARPROC GetProcAddress(HMODULE HMODULE,LPCWSTR lpProcName);

BOOL free library(HMODULE HMODULE);

現在,我們可以使用intptrhmodule = loadlibrary(" count . dll ");要獲取Dll的句柄,請使用intptrfarproc = getprocaddress(hm odule," _ count @ 4 ");獲取函數的入口地址。

但是,知道了函數的入口地址之後,如何調用這個函數呢?因為C#中沒有函數指針,沒有像C++那樣的函數指針調用方法,所以我們要用其他方法。通過研究發現,我們可以通過結合系統中的類和函數來實現我們的目標。Reflection.Emit和System.Reflection.Assembly .為了以後使用和代碼重用的方便,我們可以寫壹個類。

1) dld類編寫:

1.打開工程Tzb,打開類視圖,右鍵單擊Tzb,選擇Add-Class,將類名設置為dld,即動態加載dll中每個單詞的首字母。

2.添加所需的命名空間,並聲明參數傳遞方法的枚舉:

使用系統。Runtime . InteropServicesDllImport需要此命名空間。

使用系統。反思;//使用Assembly類需要此命名空間。

使用系統。反射。發射;//此命名空間是使用ILGenerator所必需的。

在“公共類dld”上方添加以下代碼,以聲明參數傳遞方法的枚舉:

///摘要

///枚舉參數傳遞方法,ByValue表示值傳遞,ByRef表示地址傳遞。

////摘要

公共枚舉模式通行證

{

ByValue = 0x0001,

ByRef = 0x0002

}

3.聲明LoadLibrary、GetProcAddress、FreeLibrary和私有變量hModule和farProc:

///摘要

///原型為:Hmodule LoadLibrary(lpctstr lpfilename);

////摘要

///param name="lpFileName"DLL文件名/param

///返回庫模塊的句柄///返回

[DllImport("kernel32.dll")]

靜態extern IntPtr LoadLibrary(字符串LP filename);

///摘要

///原型為:farproc getprocaddress(hmodule hmodule,lpcwstr lpprocname);

////摘要

///param name="hModule "包含要調用的函數庫模塊的句柄/param。

///param name="lpProcName "調用函數的名稱/param

///返回函數指針/返回

[DllImport("kernel32.dll")]

靜態extern IntPtr GetProcAddress(IntPtr hModule,string lpProcName);

///摘要

///原型是BOOL free library(HMODULE HMODULE);

////摘要

///param name="hModule "要釋放的函數庫模塊的句柄/param

/// returns已經釋放了指定的Dll/returns?

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

靜態extern bool free library(IntPtr hModule);

///摘要

///LoadLibrary返回的函數庫模塊的句柄

////摘要

private IntPtr hModule=IntPtr。零;

///摘要

///getProcAddress返回的函數指針

////摘要

private IntPtr farProc=IntPtr。零;

4.添加LoadDll方法,為了調用方便,重載此方法:

///摘要

///加載Dll

////摘要

///param name="lpFileName"DLL文件名/param

公共void LoadDll(字符串lpFileName)

{

hm odule = LoadLibrary(LP filename);

if(hModule==IntPtr。零)

Throw(新異常("未找到:"+lpFileName+")。"));

}

如果已經有了已加載Dll的句柄,可以使用LoadDll方法的第二個版本:

公共void LoadDll(IntPtr HMODULE)

{

if(HMODULE==IntPtr。零)

Throw(new Exception("傳入的函數庫HMODULE的句柄為空。"));

hModule = HMODULE

}

5.添加LoadFun方法並重載它,以便於調用。方法的具體代碼和註釋如下:

///摘要

///獲取函數指針

////摘要

///param name="lpProcName "調用函數的名稱/param

public void LoadFun(字符串lpProcName)

{//如果函數庫模塊的句柄為空,則拋出異常。

if(hModule==IntPtr。零)

拋出(新異常("函數庫模塊的句柄為空,請確保已經執行了LoadDll的操作!"));

//獲取函數指針

farProc = GetProcAddress(hModule,lpProcName);

//如果函數指針,拋出異常。

if(farProc==IntPtr。零)

Throw(new Exception("未找到:"+lpProcName+"該函數的入口點"));

}

///摘要

///獲取函數指針

////摘要

///param name="lpFileName "包含要調用的函數的DLL文件名/param。

///param name="lpProcName "調用函數的名稱/param

public void LoadFun(字符串lpFileName,字符串lpProcName)

{//獲取函數庫模塊的句柄。

hm odule = LoadLibrary(LP filename);

//如果函數庫模塊的句柄為空,則拋出異常。

if(hModule==IntPtr。零)

Throw(新異常("未找到:"+lpFileName+")。"));

//獲取函數指針

farProc = GetProcAddress(hModule,lpProcName);

//如果函數指針,拋出異常。

if(farProc==IntPtr。零)

Throw(new Exception("未找到:"+lpProcName+"該函數的入口點"));

}

6.添加UnLoadDll和Invoke方法,該方法也是重載的:

///摘要

///卸載Dll

////摘要

公共void UnLoadDll()

{

free library(hModule);

hModule=IntPtr。零;

farProc=IntPtr。零;

}