C調(diào)用外部dll_第1頁(yè)
C調(diào)用外部dll_第2頁(yè)
C調(diào)用外部dll_第3頁(yè)
C調(diào)用外部dll_第4頁(yè)
C調(diào)用外部dll_第5頁(yè)
已閱讀5頁(yè),還剩17頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、C#調(diào)用外部dll一、DLL與應(yīng)用程序動(dòng)態(tài)鏈接庫(kù) (也稱(chēng)為 DLL,即為“ Dynamic Link Library ”的縮寫(xiě))是Microsoft Windows 最重要的組成要素之一,打開(kāi) Windows 系統(tǒng)文件夾,你會(huì)發(fā)現(xiàn)文件夾中有很多DLL文件,Windows 就是將一些主要的系統(tǒng)功能以 DLL模塊的形式實(shí)現(xiàn)。動(dòng)態(tài)鏈接庫(kù)是不能直接執(zhí)行的,也不能接收消息,它只是一個(gè)獨(dú)立的文件,其中包含能被 程序或其它DLL調(diào)用來(lái)完成一定操作的函數(shù) (方法。注:C#中一般稱(chēng)為 方法”)但這些函數(shù)不 是執(zhí)行程序本身的一部分,而是根據(jù)進(jìn)程的需要按需載入,此時(shí)才能發(fā)揮作用。DLL只有在應(yīng)用程序需要時(shí)才被系統(tǒng)加

2、載到進(jìn)程的虛擬空間中,成為調(diào)用進(jìn)程的一部分, 此時(shí)該DLL也只能被該進(jìn)程的線(xiàn)程訪(fǎng)問(wèn),它的句柄可以被調(diào)用進(jìn)程所使用,而調(diào)用進(jìn)程的句柄 也可以被該DLL所使用。在內(nèi)存中,一個(gè) DLL只有一個(gè)實(shí)例,且它的編制與具體的編程語(yǔ)言和 編譯器都沒(méi)有關(guān)系,所以可以通過(guò)DLL來(lái)實(shí)現(xiàn)混合語(yǔ)言編程。DLL函數(shù)中的代碼所創(chuàng)建的任何對(duì)象(包括變量)都?xì)w調(diào)用它的線(xiàn)程或進(jìn)程所有。下面列岀了當(dāng)程序使用DLL時(shí)提供的一些優(yōu)點(diǎn):11)使用較少的資源當(dāng)多個(gè)程序使用同一個(gè)函數(shù)庫(kù)時(shí),DLL可以減少在磁盤(pán)和物理內(nèi)存中加載的代碼的重復(fù)量。這不僅可以大大影響在前臺(tái)運(yùn)行的程序,而且可以大大影響其他在Win dows 操作系統(tǒng)上運(yùn)行的程序。2)

3、推廣模塊式體系結(jié)構(gòu)DLL有助于促進(jìn)模塊式程序的開(kāi)發(fā)。這可以幫助您開(kāi)發(fā)要求提供多個(gè)語(yǔ)言版本的大型程序 或要求具有模塊式體系結(jié)構(gòu)的程序。模塊式程序的一個(gè)示例是具有多個(gè)可以在運(yùn)行時(shí)動(dòng)態(tài)加載的模塊的計(jì)帳程序。3)簡(jiǎn)化部署和安裝當(dāng)DLL中的函數(shù)需要更新或修復(fù)時(shí),部署和安裝 DLL不要求重新建立程序與該DLL的鏈接。此外,如果多個(gè)程序使用同一個(gè)DLL,那么多個(gè)程序都將從該更新或修復(fù)中獲益。當(dāng)您使用定期更新或修復(fù)的第三方DLL時(shí),此問(wèn)題可能會(huì)更頻繁地岀現(xiàn)。二、DLL的調(diào)用每種編程語(yǔ)言調(diào)用 DLL的方法都不盡相同,在此只對(duì)用C#調(diào)用DLL的方法進(jìn)行介紹。首先,您需要了解什么是托管,什么是非托管。一般可以認(rèn)為:

4、非托管代碼主要是基于win 32平臺(tái)開(kāi)發(fā)的DLL,activeX 的組件,托管代碼是基于.net平臺(tái)開(kāi)發(fā)的。如果您想深入了解托管與非托管的關(guān)系與區(qū)別,及它們的運(yùn)行機(jī)制,請(qǐng)您自行查找資料,本文件在此不作討論。(一)調(diào)用DLL中的非托管函數(shù)一般方法首先,應(yīng)該在C#語(yǔ)言源程序中聲明外部方法,其基本形式是:DLLImport( “ DL文件”)修飾符extern返回變量類(lèi)型方法名稱(chēng)(參數(shù)列表)其中:DLL文件:包含定義外部方法的庫(kù)文件。修飾符:訪(fǎng)問(wèn)修飾符,除了 abstract以外在聲明方法時(shí)可以使用的修飾符。返回變量類(lèi)型:在 DLL文件中你需調(diào)用方法的返回變量類(lèi)型。方法名稱(chēng):在 DLL文件中你需調(diào)用

5、方法的名稱(chēng)。參數(shù)列表:在 DLL文件中你需調(diào)用方法的列表。注意:需要在程序聲明中使用System.Runtime.lnteropServices命名空間。Dlllmport只能放置在方法聲明上。DLL文件必須位于程序當(dāng)前目錄或系統(tǒng)定義的查詢(xún)路徑中(即:系統(tǒng)環(huán)境變量中 Path所設(shè)置的路徑)。返回變量類(lèi)型、方法名稱(chēng)、參數(shù)列表一定要與DLL文件中的定義相一致。若要使用其它函數(shù)名,可以使用En tryPoi nt屬性設(shè)置,如:Dlllmport("user32.dll", En tryPoi nt="MessageBoxA")static extern int

6、 MsgBox(int hWnd, string msg, string caption, int type);其它可選的DllImportAttribute 屬性:CharSet指示用在入口點(diǎn)中的字符集,如:CharSet=CharSet.A nsi;SetLastError指示方法是否保留Win32"上一錯(cuò)誤",如:SetLastError=true ;ExactSpelling指示EntryPoint是否必須與指示的入口點(diǎn)的拼寫(xiě)完全匹配,如:ExactSpelli ng=false ;PreserveSig指示方法的簽名應(yīng)當(dāng)被保留還是被轉(zhuǎn)換,女口: PreserveS

7、ig=true ;Calli ngCo nve nti on指示入口點(diǎn)的調(diào)用約定,女口:Calli ngConven tio n=Calli ngConven tio n.Winapi;此外,關(guān)于 數(shù)據(jù)封送處理”及 封送數(shù)字和邏輯標(biāo)量”請(qǐng)參閱其它一些文章2。C#例子:1. 啟動(dòng)VS.NET,新建一個(gè)項(xiàng)目項(xiàng)目名稱(chēng)為“Tzb,”模板為“ Windows應(yīng)用程序”2. 在工具箱"的“ Win dows窗體"項(xiàng)中雙擊“ Butt on項(xiàng),向“ Form1窗體中添加一個(gè)按鈕。3. 改變按鈕的屬性:Name為“ B1: Text為 用DllImport 調(diào)用DLL彈岀提示框”并將按鈕

8、B1調(diào)整到適當(dāng)大小,移到適當(dāng)位置。4. 在類(lèi)視圖中雙擊“ Form1,打開(kāi)“ Form1.cs ”弋碼視圖,在“namespace Tzb 上面輸入“ usingSystem.Ru ntime.l nteropServices;,以導(dǎo)入該命名空間。5. 在“ Form1. cs 設(shè)計(jì)"視圖中雙擊按鈕B1,在“ B1_Click方法上面使用關(guān)鍵字static 和extern聲明方法“ MsgBox :將DllImport屬性附加到該方法,這里我們要使用的是“ user32 . dll中的“ MessageBoxA 函數(shù),具體代碼如下:DllImport("user32.dll

9、", En tryPoi nt="MessageBoxA")static extern int MsgBox(int hWnd, string msg, string caption, inttype);然后在“B1_Click :方法體內(nèi)添加如下代碼,以調(diào)用方法“MsgBox :MsgBox(0," 這就是用 DllImport 調(diào)用DLL彈岀的提示框哦!",“挑戰(zhàn)杯",0x30);6. 按“ F5運(yùn)行該程序,并點(diǎn)擊按鈕B1,便彈岀如下提示框:|這就顯用Dlllport調(diào)用D曲出的提示框峨,(二) 動(dòng)態(tài)裝載、調(diào)用DLL中的非托管函數(shù)

10、在上面已經(jīng)說(shuō)明了如何用Dlllmport 調(diào)用DLL中的非托管函數(shù),但是這個(gè)是全局的函數(shù),假若DLL中的非托管函數(shù)有一個(gè)靜態(tài)變量S,每次調(diào)用這個(gè)函數(shù)的時(shí)候,靜態(tài)變量S就自動(dòng)加1。結(jié)果,當(dāng)需要重新計(jì)數(shù)時(shí),就不能得岀想要的結(jié)果。下面將用例子說(shuō)明:1. DLL的創(chuàng)建1) 啟動(dòng) Visual C+ 6.0;2) 新建一個(gè) “ Win32 Dynamic - Link Library 工程,工程名稱(chēng)為 “ Count ;3) 在 “ Dll kind 選擇界面中選擇“ A simple dll project ;”4) 打開(kāi)Count.cpp,添加如下代碼:/導(dǎo)岀函數(shù),使用“ _stdcall標(biāo)準(zhǔn)調(diào)用e

11、xter n "C" _declspec(dllexport )int _stdcall cou nt(i nt ini t);int _stdcall cou nt(i nt init)/count 函數(shù),使用參數(shù)init初始化靜態(tài)的整形變量S ,并使S自加1后返回該值static int S=in it;S+;return S;5) 按“ F7進(jìn)行編譯,得到Count.dll(在工程目錄下的Debug文件夾中)。2. 用DllImport 調(diào)用DLL中的count函數(shù)1) 打開(kāi)項(xiàng)目“Tzb,”向“ Form1窗體中添加一個(gè)按鈕。2) 改變按鈕的屬性:Name為 “ B2

12、," Text為 用DllImport 調(diào)用DLL中count函數(shù)”,并將按鈕B1調(diào)整到適當(dāng)大小,移到適當(dāng)位置。3) 打開(kāi)“ Form1. cs "代碼視圖,使用關(guān)鍵字static 和extern 聲明方法“ count,"并使其具有來(lái)自Cou nt.dll的導(dǎo)岀函數(shù)cou nt的實(shí)現(xiàn),代碼如下:DllImport("Cou nt.dll")static exter n int cou nt(i nt ini t);4) 在“ Form1. cs 設(shè)計(jì)"視圖中雙擊按鈕B2,在“ B2_Click方法體內(nèi)添加如下代碼:MessageBo

13、x.Show(”用Dlllmport調(diào)用DLL中的count函數(shù),n傳入的實(shí)參為 0,得到的結(jié)果是:"+count(O).ToString(),"挑戰(zhàn)杯“);MessageBox.Show(”用DllImport調(diào)用DLL中的count函數(shù),n傳入的實(shí)參為 10 ,得到的結(jié)果是:"+cou nt(10).ToStr in g()+"n結(jié)果可不是想要的 11哦! !",“挑戰(zhàn)杯“);MessageBox.Show(”所得結(jié)果表明:n 用 DllImport 調(diào)用 DLL 中的非托管n函數(shù)是全局的、靜態(tài)的函數(shù)! !",“挑戰(zhàn)杯“);5)把

14、Count.dll復(fù)制到項(xiàng)目“Tzb的binDebug文件夾中,按“ F5運(yùn)行該程序,并點(diǎn)擊按鈕B2,便彈出如下三個(gè)提示框:第1個(gè)提示框顯示的是調(diào)用“count(0)"的結(jié)果,第2個(gè)提示框顯示的是調(diào)用“count(10) ”踣累可術(shù)是想娶的M哦? * *I;殛的結(jié)果,由所得結(jié)果可以證明 用DllImport 調(diào)用DLL中的非托管函數(shù)是全局的、 靜態(tài)的函數(shù)”。 所以,有時(shí)候并不能達(dá)到我們目的,因此我們需要使用下面所介紹的方法:C#動(dòng)態(tài)調(diào)用DLL中的函數(shù)。3.C#動(dòng)態(tài)調(diào)用DLL中的函數(shù)因?yàn)镃#中使用 DllImport是不能像動(dòng)態(tài) load/unload assembly那樣,所以只能借

15、助API函數(shù)了。在kernel32.dll中,與動(dòng)態(tài)庫(kù)調(diào)用有關(guān)的函數(shù)包括3: LoadLibrary (或 MFC 的 AfxLoadLibrary ),裝載動(dòng)態(tài)庫(kù)。 GetProcAddress,獲取要引入的函數(shù),將符號(hào)名或標(biāo)識(shí)號(hào)轉(zhuǎn)換為DLL內(nèi)部地址。 FreeLibrary (或 MFC 的 AfxFreeLibrary ),釋放動(dòng)態(tài)鏈接庫(kù)。它們的原型分別是:HMODULE LoadLibrary(LPCTSTR lpFileName);FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);BOOL FreeLibrary(

16、HMODULE hModule);現(xiàn)在,我們可以用IntPtr hModule=LoadLibrary( “Count.dll ”); 來(lái)獲得 Dll 的句柄,用 IntPtr farProc=GetProcAddress(hModule, ” _count4 ”);來(lái)獲得函數(shù)的入口地址。但是,知道函數(shù)的入口地址后,怎樣調(diào)用這個(gè)函數(shù)呢?因?yàn)樵贑#中是沒(méi)有函數(shù)指針的,沒(méi)有像C+那樣的函數(shù)指針調(diào)用方式來(lái)調(diào)用函數(shù),所以我們得借助其它方法。經(jīng)過(guò)研究,發(fā)現(xiàn)我們可以通過(guò)結(jié)合使用System.Reflection.Emit及 System.Reflection.Assembly里的類(lèi)和函數(shù)達(dá)至U我們的目的。

17、為了以后使用方便及實(shí)現(xiàn)代碼的復(fù)用,我們可以編寫(xiě)一個(gè)類(lèi)。1) dld類(lèi)的編寫(xiě):1. 打開(kāi)項(xiàng)目“ Tzb,"打開(kāi)類(lèi)視圖,右擊“ Tzb,"選擇 添加"-> “類(lèi)",類(lèi)名設(shè)置為“ dld,"即dynamicload ing dll的每個(gè)單詞的開(kāi)頭字母。2. 添加所需的命名空間及聲明參數(shù)傳遞方式枚舉:using System.Runtime.lnteropServices; /用 DllImport 需用此 命名空間using System.Reflection; /使用 Assembly類(lèi)需用此 命名空間usi ng System.Reflec

18、tio n.Emit; /使用 ILGe nerator 需用此 命名空間在“public class dld上面添加如下代碼聲明參數(shù)傳遞方式枚舉:/ <summary>/參數(shù)傳遞方式枚舉,ByValue表示值傳遞,ByRef表示址傳遞/ </summary>public enum ModePassByValue = 0x0001,ByRef = 0x00023. 聲明 LoadLibrary 、GetProcAddress 、FreeLibrary及私有變量 hModule 和 farProc :/ <summary>/ 原型是:HMODULE LoadL

19、ibrary(LPCTSTR lpFileName);/ </summary>/ <param n ame="lpFileName">DLL文件名 </param>/ <returns>函數(shù)庫(kù)模塊的句柄</retur ns>Dlllmport("kernel32.dll")static extern IntPtr LoadLibrary(string lpFileName);/ <summary>/ 原型是:FARPROC GetProcAddress(HMODULE hModule

20、,LPCWSTR IpProcName);III </summary>III <param name="hModuIe">包含需調(diào)用函數(shù)的函數(shù)庫(kù)模塊的句柄<Iparam>III vparam n ame="IpProcName">調(diào)用函數(shù)的名稱(chēng)<Iparam>III <returns> 函數(shù)指針 vIretur ns>Dlllmport("kernel32.dll")static extern In tPtr GetProcAddress(l ntPtr hMod

21、ule, stri nglpProcName);III <summary>III 原型是:BOOL FreeLibrary(HMODULE hModule);III <Isummary>III vparam name="hModule">需釋放的函數(shù)庫(kù)模塊的句柄<Iparam>III <returns> 是否已釋放指定的DllvIretur ns>DllImport("kernel32",E ntryPoi nt="FreeLibrary",SetLastError=true

22、)static extern bool FreeLibrary(IntPtr hModule);III <summary>III Loadlibrary返回的函數(shù)庫(kù)模塊的句柄III <Isummary>private In tPtr hModule=I ntPtr.Zero;III <summary>III GetProcAddress返回的函數(shù)指針I(yè)II <Isummary>private In tPtr farProc=l ntPtr.Zero;4. 添加LoadDll方法,并為了調(diào)用時(shí)方便,重載了這個(gè)方法:III <summary&g

23、t;III裝載DllIII <Isummary>III vparam n ame="lpFileName">DLL文件名 <Iparam> public void LoadDll(stri ng lpFileName) hModule=LoadLibrary (I pFileName);if(hModule=l ntPtr.Zero)throw( new Exceptio n("沒(méi)有找到 :"+lpFileName+".");若已有已裝載 Dll的句柄,可以使用LoadDll方法的第二個(gè)版本:public

24、 void LoadDll(IntPtr HMODULE)if(HMODULE=I ntPtr.Zero)throw( new Exceptio n(”所傳入的函數(shù)庫(kù)模塊的句柄HMODULE 為空.");hModule=HMODULE;5. 添加LoadFun方法,并為了調(diào)用時(shí)方便,也重載了這個(gè)方法,方法的具體代碼及注釋如下:/ <summary>/獲得函數(shù)指針/ </summary>/ vparam n ame="lpProcName">調(diào)用函數(shù)的名稱(chēng) </param>public void LoadFu n( stri

25、 ng lpProcName) /若函數(shù)庫(kù)模塊的句柄為空,則拋出異常if(hModule=I ntPtr.Zero)throw(new Exception(”函數(shù)庫(kù)模塊的句柄為空,請(qǐng)確保已進(jìn)行LoadDll 操作!");/取得函數(shù)指針farProc = GetProcAddress(hModule,lpProcName);/若函數(shù)指針,則拋出異常if(farProc=I ntPtr.Zero)throw( new Exceptio n("沒(méi)有找到:"+lpProcName+"這個(gè)函數(shù)的入口點(diǎn)");/ <summary>/獲得函數(shù)指針

26、/ </summary>III vparam name="lpFileName">包含需調(diào)用函數(shù)的</param>/ vparam name="lpProcName">調(diào)用函數(shù)的名稱(chēng)public void LoadFu n( stri ng lpFileName,stri ng IpProcName) /取得函數(shù)庫(kù)模塊的句柄hModule=LoadLibrary (l pFileName);/若函數(shù)庫(kù)模塊的句柄為空,則拋出異常if(hModule=l ntPtr.Zero)throw(new Exception(&qu

27、ot;沒(méi)有找到 :"+lpFileName+".");/取得函數(shù)指針farProc = GetProcAddress(hModule,lpProcName);/若函數(shù)指針,則拋出異常if(farProc=I ntPtr.Zero)throw( new Exceptio n("沒(méi)有找到:"+lpProcName+"點(diǎn)");6. 添加UnLoadDll 及Invoke 方法,Invoke 方法也進(jìn)行了重載:/ <summary>/ 卸載Dll/ </summary>public void Un LoadD

28、ll()FreeLibrary(hModule);hModule=I ntPtr.Zero;farProc=I ntPtr.Zero;In voke方法的第一個(gè)版本:/ <summary>/調(diào)用所設(shè)定的函數(shù)DLL文件名</param>這個(gè)函數(shù)的入口/ </summary>/ <param name="ObjArray_Parameter">實(shí)參 </param>/ <param name="TypeArray_ParameterType">實(shí)參類(lèi)型 </param>/ &

29、lt;param name="ModePassArray_Parameter">實(shí)參傳送方式 </param>/ <param name="Type_Return">返回類(lèi)型</param>/ <returns>返回所調(diào)用函數(shù)的 object</returns> public object Invoke(object ObjArray_Parameter,TypeTypeArray_ParameterType,ModePass ModePassArray_Parameter,TypeTyp

30、e_Return) / 下面 3 個(gè) if 是進(jìn)行安全檢查 , 若不能通過(guò) , 則拋出異常 if(hModule=IntPtr.Zero)throw(new Exception("函數(shù)庫(kù)模塊的句柄為空 , 請(qǐng)確保已進(jìn)行 LoadDll 操作 !");if(farProc=IntPtr.Zero)throw(new Exception("函數(shù)指針為空 , 請(qǐng)確保已進(jìn)行 LoadFun 操作 !" ) );if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length)throw(new Except

31、ion("參數(shù)個(gè)數(shù)及其傳遞方式的個(gè)數(shù)不匹配 ." ) );/ 下面是創(chuàng)建 MyAssemblyName 對(duì)象并設(shè)置其 Name 屬性AssemblyName MyAssemblyName = new AssemblyName();MyAssemblyName.Name = "InvokeFun"/ 生成單模塊配件AssemblyBuilder MyAssemblyBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,Assembl yBuilderAccess.Run);

32、ModuleBuilder MyModuleBuilder=MyAssemblyBuilder.DefineDynamicModule("InvokeDll");/ 定義要調(diào)用的方法 , 方法名為 “ MyFun ,”返回類(lèi)型是 “ Type_Return 參”數(shù)類(lèi)型是 “ TypeArray_ParameterType ”MethodBuilder MyMethodBuilder =MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public| MethodAttributes.S

33、tatic,Type_Return,TypeArray_ParameterType);/ 獲取一個(gè) ILGenerator ,用于發(fā)送所需的 ILILGenerator IL = MyMethodBuilder.GetILGenerator();int i;for (i = 0; i < ObjArray_Parameter.Length; i+)/ 用循環(huán)將參數(shù)依次壓入堆棧switch (ModePassArray_Parameteri)case ModePass.ByValue: IL.Emit(OpCodes.Ldarg, i);break;case ModePass.ByRef:

34、IL.Emit(OpCodes.Ldarga, i);break;default:throw(new Exception("第 " +(i+1).ToString() + " 個(gè)參數(shù)沒(méi)有給定正確的傳遞方式 ." ) );if (IntPtr.Size = 4) /判斷處理器類(lèi)型IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32();else if (IntPtr.Size = 8)IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64();elsethrow new PlatformNotSupport

35、edException();IL.EmitCalli(OpCodes.Calli,CallingConvention.StdCall,Type_Return,TypeArray_Par ameterType);IL.Emit(OpCodes.Ret); /返回值MyModuleBuilder.CreateGlobalFunctions();/ 取得方法信息Methodi nfo MyMethodl nfo = MyModuleBuilder.GetMethod("MyFu n");return MyMethodl nfo.l nvoke( null, ObjArray_Pa

36、rameter);調(diào)用方法,并返回其值In voke 方法的第二個(gè)版本,它是調(diào)用了第一個(gè)版本的:/ <summary>/調(diào)用所設(shè)定的函數(shù)/ </summary>/ vparam n ame="I ntPtr_Fu nctio n">函數(shù)指針 </param>/ vparam n ame="ObjArray_Parameter">實(shí)參 </param>/ vparam n ame="TypeArray_ParameterType">實(shí)參類(lèi)型 </param>/

37、 vparam n ame="ModePassArray_Parameter">實(shí)參傳送方式</param>/ vparam n ame="Type_Retur n">返回類(lèi)型v/param>/ vretur ns>返回所調(diào)用函數(shù)的objectv/retur ns>public object in voke(l ntPtr in tPtr_Fu ncti on,o bject ObjArray_Parameter,TypeTypeArray_ParameterType,ModePass ModePassArray

38、_Parameter,TypeType_Retur n)/下面2個(gè)if是進(jìn)行安全檢查,若不能通過(guò),則拋岀異常if(hModule=I ntPtr.Zero)throw(new Exception(”函數(shù)庫(kù)模塊的句柄為空 ,請(qǐng)確保已進(jìn)行LoadDll 操作!");if(ln tPtr_Fu nctio n=l ntPtr.Zero)throw(new Exception(”函數(shù)指針 IntPtr_Function 為空 r');farProc= In tPtr_Fu ncti on;returnIn voke(ObjArray_Parameter,TypeArray_Param

39、eterType,ModePassArray_Parameter,Type_Return);2) dld類(lèi)的使用:1 .打開(kāi)項(xiàng)目“Tzb,”向“ Forml窗體中添加三個(gè)按鈕。 Name 和Text屬性分別為“ B3、用LoadLibrary 方法裝載 Count.dll,” “ B4、 調(diào)用 count 方法”,“ B5、 卸載 Count.dll ,"并調(diào)整到適當(dāng)?shù)拇笮〖拔恢谩? .在“ Form1. cs 設(shè)計(jì)"視圖中雙擊按鈕dld類(lèi)實(shí)例:B3,在“ B3_Click方'法體上面添加代碼,創(chuàng)建一個(gè)/ <summary> / 創(chuàng)建一個(gè) dld類(lèi)對(duì)象

40、/ </summary> private dld myfun=new dld();3 .在“ B3 Click方法體內(nèi)添加如下代碼:加載"Count.dll"myfu n.LoadFu n("_cou nt4"); /調(diào)入函數(shù) cou nt, "_cou nt4"是它的入口,可通過(guò)Depe nds 查看4 .“ Form1. cs 設(shè)計(jì)"視圖中雙擊按鈕 B4 ,在“ B4 Click方法體內(nèi)添加如下代碼:object Parameters = new object(int)0; /實(shí)參為T(mén)ype Paramete

41、rTypes = new Typetypeof(i nt); /實(shí)參類(lèi)型為intModePass themode=new ModePassModePass.ByValue; /傳送方式為值傳Type Type_Retur n = typeof(i nt); /返回類(lèi)型為int/彈岀提示框,顯示調(diào)用myfun.lnvoke方法的結(jié)果,即調(diào)用cou nt 函數(shù)MessageBox.Show("這是您裝載該Dll后第myfu n.LoadDll("Cou nt.dll"); /"+myfu n.l nvoke(Parameters,ParameterTypes

42、,themode,Type_Return).ToStri ng()+"次點(diǎn)擊此按鈕。I! I!挑戰(zhàn)杯");5 .“ Form1. cs 設(shè)計(jì)”視圖中雙擊按鈕 B5,在“ B5_Click方法體內(nèi)添加如下代碼:myfun .U nLoadDll();6 按“ F5運(yùn)行該程序,并先點(diǎn)擊按鈕B3以加載“ Count.dll ,接著點(diǎn)擊按鈕 B4三次以調(diào)用3次“ count(O),先后彈岀的提示框如下:這三個(gè)提示框所得岀的結(jié)果說(shuō)明了靜態(tài)變量S經(jīng)初始化后,再傳入實(shí)參 “ 0”不會(huì)改變其值為“0”7 .點(diǎn)擊按鈕B5以卸載“ Count.dll ,再點(diǎn)擊按鈕 B3進(jìn)行裝載“ Count.

43、dll ,再點(diǎn)擊按鈕 B4查看 調(diào)用了 “count(0)"的結(jié)果:從彈岀的提示框所顯示的結(jié)果可以看到又開(kāi)始重新計(jì)數(shù)了,也就是實(shí)現(xiàn)了 DLL的動(dòng)態(tài)裝載與卸載了。(三)調(diào)用托管DLL 一般方法C#調(diào)用托管DLL是很簡(jiǎn)單的,只要在 解決方案資源管理器 ”中的需要調(diào)用 DLL的項(xiàng)目下 用鼠標(biāo)右擊 引用”并選擇 添加引用”,然后選擇已列岀的 DLL或通過(guò)瀏覽來(lái)選擇 DLL文件, 最后需要用using導(dǎo)入相關(guān)的命名空間。(四)動(dòng)態(tài)調(diào)用托管DLLC#動(dòng)態(tài)調(diào)用托管 DLL也需要借助System.Reflectio“.Assembly里的類(lèi)和方法,主要使用了Assembl y丄oadFrom?,F(xiàn)在,

44、用例子說(shuō)明:首先,啟動(dòng)VS.NET,新建一個(gè)Visual C# 項(xiàng)目 使用的模板為 類(lèi)庫(kù)”,名稱(chēng)為“ CsCount, 并在類(lèi)“Classi”中添加靜態(tài)整型變量S及方法count :/由于static不能修飾方法體內(nèi)的變量,所以需放在這里,且初始化值為in t.Mi nV alue static int S=i nt.Mi nV alue;public int cou nt(i nt init)/ 判斷S是否等于int.MinValue,是的話(huà)把init賦值給S if(S=i nt.Mi nValue) S=i nit;S+; S 自增 1return S; / 返回 S然后,打開(kāi)項(xiàng)目 “Tz

45、b”向“FormT窗體中添加一個(gè)按鈕, Name屬性為“B6” Text屬 性為用Assembly 類(lèi)來(lái)動(dòng)態(tài)調(diào)用托管 DLL',調(diào)整到適當(dāng)大小和位置,雙擊按鈕B6,轉(zhuǎn)入代碼視圖,先導(dǎo)入命名空間:using System.Reflection;接著添加Invoke 方法和B6_Click 方法代碼:private object In voke(stri ng lpFileName,stri ng Namespace,str ingClassName,str ing lpProcName,object ObjArray_Parameter)Try /載入程序集Assembly MyAsse

46、mbly=Assembly.LoadFrom(lpFileName);Type type=MyAssembly.GetTypes();foreach(Type t in type) 查找要調(diào)用的命名空間及類(lèi)if(t.Namespace=Namespace&&t.Name=ClassName)/查找要調(diào)用的方法并進(jìn)行調(diào)用MethodInfo m=t.GetMethod(lpProcName);if(m!=null)object o=Activator.Create In sta nce(t);return m.ln voke(o,ObjArray_Parameter);else

47、MessageBox.Show("裝載岀錯(cuò)!");/trycatch(System.NullReferenceException e)MessageBox.Show(e.Message);/catchreturn (object)O;/ I nvokeB6_Click方'法體內(nèi)代碼如下:II顯示 cou nt(O)返回的值MessageBox.Show("這是您第"+I nvoke("CsCou nt.dll","CsCou nt","Class1","cou nt"

48、, newobject(i nt)0).ToStri ng()+"次點(diǎn)擊此按鈕。",“挑戰(zhàn)杯");最后,把項(xiàng)目“CsCounf'的binDebug文件夾中的CsCount.dll復(fù)制到項(xiàng)目“Tzb"的binDebug 文件夾中,按 “ F5運(yùn)行該程序,并點(diǎn)擊按鈕 B6三次,將會(huì)彈岀3個(gè)提示框,內(nèi)容 分別是這是您第1次點(diǎn)擊此按鈕?!?、這是您第2次點(diǎn)擊此按鈕。”、這是您第3次點(diǎn)擊此 按鈕。”,由此知道了靜態(tài)變量 S在這里的作用。(五) C#程序嵌入DLL的調(diào)用DLL文件作為資源嵌入在C#程序中,我們只要讀取該資源文件并以“ byte返回,然后就用“A

49、ssembly Load(byte); ” 得到DLL中的程序集,最后就可以像上面的Invoke 方法那樣對(duì)DLL中的方法進(jìn)行調(diào)用。當(dāng)然不用上面方法也可以,如用接口實(shí)現(xiàn)動(dòng)態(tài)調(diào)用,但DLL中必須有該接口的定義并且程序中也要有該接口的定義;也可用反射發(fā)送實(shí)現(xiàn)動(dòng)態(tài)調(diào)用4?,F(xiàn)在我只對(duì)像上面的Invoke方法那樣對(duì)DLL中的方法進(jìn)行調(diào)用進(jìn)行討論,為了以后使用方便及實(shí)現(xiàn)代 碼的復(fù)用,我們可以結(jié)合上一個(gè)編寫(xiě)一個(gè)類(lèi)。1) ldfs 類(lèi)的編寫(xiě):在項(xiàng)目“Tzb"中新建一個(gè)名為 ldfs的類(lèi),意為 “l(fā)oad dll from resource ”,請(qǐng)注意,在這 個(gè)類(lèi)中“resource ”不只是嵌入在

50、EXE程序中的資源,它也可以是硬盤(pán)上任意一個(gè)DLL文件,這是因?yàn)閘dfs的類(lèi)中的方法LoadDll有些特別,就是先從程序的內(nèi)嵌的資源中查找需加載的 DLL,如果找不到,就查找硬盤(pán)上的。首先導(dǎo)入所需的命名空間:using System.IO; II對(duì)文件的讀寫(xiě)需要用到此命名空間using System.Reflection; II使用 Assembly類(lèi)需用此命名空間using System.Reflectio n.Emit; II使用 ILGe nerator需用此命名空間聲明一靜態(tài)變量 MyAssembly :II記錄要導(dǎo)入的程序集static Assembly MyAssembly;添加L

51、oadDll方法:private byte LoadDll(string lpFileName)Assembly NowAssembly = Assembly.GetE ntryAssembly();Stream fs=n ull;try/嘗試讀取資源中的DLLfs =NowAssembly.GetMa nifestResourceStream(NowAssembly.GetName().Name+"."+lpFileName);fin ally/如果資源沒(méi)有所需的DLL,就查看硬盤(pán)上有沒(méi)有,有的話(huà)就讀取if (fs=null&&!File.Exists (

52、l pFileName) throw( new Exceptio n("找不到文件:"+lpFileName);else if(fs=null&&File.Exists (l pFileName)FileStream Fs = new FileStream(lpFileName, FileMode.Open);fs=(Stream)Fs;byte buffer = new byte( int) fs.Le ngth;fs.Read(buffer, 0, buffer.Le ngth);fs.Close();return buffer; /以 byte返回讀到

53、的DLL添加UnLoadDll 方法來(lái)卸載 DLL :public void Un LoadDll()/ 使 MyAssembly 指空MyAssembly=n ull;添加Invoke 方法來(lái)進(jìn)行對(duì) DLL中方法的調(diào)用,其原理大體上和“ Form1 . cs"中的方法Invoke 相同,不過(guò)這里用的是 “ Assembly丄oad ,"而且用了靜態(tài)變量 MyAssembly 來(lái)保存已 加載的DLL,如果已加載的話(huà)就不再加載,如果還沒(méi)加載或者已加載的不同現(xiàn)在要加載的DLL就進(jìn)行加載,其代碼如下所示:public object Invoke(string lpFileName,string Namespace,stringClassName,string lpProcName,object ObjArray_Parameter)try/ 判斷MyAssembly是否為空或 MyAssembly的命名空間不等于要調(diào)用方法的命名空間

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論