




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、C#調(diào)用外部dll詳解1、 DLL與應(yīng)用程序動(dòng)態(tài)鏈接庫(kù)(也稱為DLL,即為"DynamicLinkLibrary”的縮寫)是MicrosoftWindows最重要的組成要素之一,打開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)用來完成一定操作的函數(shù)(方法。注:C#中一般稱為方法”)但這些函數(shù)不是執(zhí)行程序本身的一部分,而是根據(jù)進(jìn)程的需要按需載入,此時(shí)才能發(fā)揮作用。DLL只有在應(yīng)用程序需要時(shí)才被系統(tǒng)加載到進(jìn)程的虛擬空
2、間中,成為調(diào)用進(jìn)程的一部分,此時(shí)該DLL也只能被該進(jìn)程的線程訪問,它的句柄可以被調(diào)用進(jìn)程所使用,而調(diào)用進(jìn)程的句柄也可以被該DLL所使用。在內(nèi)存中,一個(gè)DLL只有一個(gè)實(shí)例,且它的編制與具體的編程語(yǔ)言和編譯器都沒有關(guān)系,所以可以通過DLL來實(shí)現(xiàn)混合語(yǔ)言編程。DLL函數(shù)中的代碼所創(chuàng)建的任何對(duì)象(包括變量)都?xì)w調(diào)用它的線程或進(jìn)程所有。下面列出了當(dāng)程序使用DLL時(shí)提供的一些優(yōu)點(diǎn):11) 使用較少的資源當(dāng)多個(gè)程序使用同一個(gè)函數(shù)庫(kù)時(shí),DLL可以減少在磁盤和物理內(nèi)存中加載的代碼的重復(fù)量。這不僅可以大大影響在前臺(tái)運(yùn)行的程序,而且可以大大影響其他在Windows操作系統(tǒng)上運(yùn)行的程序。2) 推廣模塊式體系結(jié)構(gòu)DLL
3、有助于促進(jìn)模塊式程序的開發(fā)。這可以幫助您開發(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í),此問題可能會(huì)更頻繁地出現(xiàn)。2、 DLL的調(diào)用每種編程語(yǔ)言調(diào)用DLL的方法都不盡相同,在此只對(duì)用C#調(diào)用DLL的方法進(jìn)行介紹。首先,您需要了解什么是托管,什么是非托管。一般可以認(rèn)為:非托管代碼主要是基于win
4、32平臺(tái)開發(fā)的DLL,activeX的組件,托管代碼是基于.net平臺(tái)開發(fā)的。如果您想深入了解托管與非托管的關(guān)系與區(qū)別,及它們的運(yùn)行機(jī)制,請(qǐng)您自行查找資料,本文件在此不作討論。(一)調(diào)用DLL中的非托管函數(shù)一般方法首先,應(yīng)該在C#語(yǔ)言源程序中聲明外部方法,其基本形式是:DLLImport(“DLL件”)修飾符extern返回變量類型方法名稱(參數(shù)列表)其中:DLL文件:包含定義外部方法的庫(kù)文件。修飾符:訪問修飾符,除了abstract以外在聲明方法時(shí)可以使用的修飾符。返回變量類型:在DLL文件中你需調(diào)用方法的返回變量類型。方法名稱:在DLL文件中你需調(diào)用方法的名稱。參數(shù)列表:在DLL文件中你需
5、調(diào)用方法的列表。注意:需要在程序聲明中使用System.Runtime.InteropServices命名空間。DllImport只能放置在方法聲明上。DLL文件必須位于程序當(dāng)前目錄或系統(tǒng)定義的查詢路徑中(即:系統(tǒng)環(huán)境變量中Path所設(shè)置的路徑)。返回變量類型、方法名稱、參數(shù)列表一定要與DLL文件中的定義相一致。若要使用其它函數(shù)名,可以使用EntryPoint屬性設(shè)置,如:DllImport("user32.dll",EntryPoint="MessageBoxA")staticexternintMsgBox(inthWnd,stringmsg,stri
6、ngcaption,inttype);其它可選的DllImportAttribute屬性:CharSet指示用在入口點(diǎn)中白字符集,如:CharSet=CharSet.Ansi;SetLastError指示方法是否保留Win32"上一錯(cuò)誤",如:SetLastError=true;ExactSpelling指示EntryPoint是否必須與指示的入口點(diǎn)的拼寫完全匹配,如:ExactSpelling=false;PreserveSig指示方法的簽名應(yīng)當(dāng)被保留還是被轉(zhuǎn)換,如:PreserveSig=true;CallingConvention指示入口點(diǎn)的調(diào)用約定,如:Callin
7、gConvention=CallingConvention.Winapi;此外,關(guān)于數(shù)據(jù)封送處理”及封送數(shù)字和邏輯標(biāo)量”請(qǐng)參閱其它一些文章2。C#例子:1. 啟動(dòng)VS.NET,新建一個(gè)項(xiàng)目,項(xiàng)目名稱為“Tzb,”模板為“Windows應(yīng)用程序”。2. 在工具箱"的"Windows窗體"項(xiàng)中雙擊"Button項(xiàng),向"Forml窗體中添加一個(gè)按鈕。3. 改變按鈕的屬性:Name為“B1,"Text為用DllImport調(diào)用DLL彈出提示框",并將按鈕B1調(diào)整到適當(dāng)大小,移到適當(dāng)位置。4. 在類視圖中雙擊“Form1;打開“For
8、m1.cs”代碼視圖,在"namespaceTzb上面輸入“usingSystem.Runtime.InteropServices;,以導(dǎo)入該命名空間。5. 在“Form1.cs設(shè)計(jì)”視圖中雙擊按鈕B1,在“B1_Click方法上面使用關(guān)鍵字static和extern聲明方法"MsgBox;將DllImport屬性附加到該方法,這里我們要使用的是“user32.dll中的"MessageBoxA函數(shù),具體代碼如下:DllImport("user32.dll",EntryPoint="MessageBoxA")staticex
9、ternintMsgBox(inthWnd,stringmsg,stringcaption,inttype);然后在“B1_Click”方法體內(nèi)添加如下代碼,以調(diào)用方法“MsgBox:MsgBox(0,"這就是用DllImport調(diào)用DLL彈出的提示框哦!","挑戰(zhàn)杯",0x30);6. 按“F5運(yùn)行該程序,并點(diǎn)擊按鈕B1,便彈出如下提示框:(二)動(dòng)態(tài)裝載、調(diào)用DLL中的非托管函數(shù)在上面已經(jīng)說明了如何用DllImport調(diào)用DLL中的非托管函數(shù),但是這個(gè)是全局的函數(shù),假若DLL中的非托管函數(shù)有一個(gè)靜態(tài)變量S,每次調(diào)用這個(gè)函數(shù)的時(shí)候,靜態(tài)變量S就自動(dòng)加1。
10、結(jié)果,當(dāng)需要重新計(jì)數(shù)時(shí),就不能得出想要的結(jié)果。下面將用例子說明:1. DLL的創(chuàng)建1) 啟動(dòng)VisualC+6.0;2) 新建一個(gè)“Win32Dynamic-LinkLibrary工程,工程名稱為“Count;"3) 在"Dllkind選擇界面中選擇"Asimpledllproject;"4) 打開Count.cpp,添加如下代碼:/導(dǎo)出函數(shù),使用“_stdcall”標(biāo)準(zhǔn)調(diào)用extern"C"_declspec(dllexport)int_stdcallcount(intinit);int_stdcallcount(intinit)/
11、count函數(shù),使用參數(shù)init初始化靜態(tài)的整形變量S,并使S自加1后返回該值staticintS=init;S+;returnS;5) 按“FT®行編譯,得到Count.dll(在工程目錄下的Debug文件夾中)。2. 用DllImport調(diào)用DLL中的count函數(shù)1) 打開項(xiàng)目“Tzb,”向“Form1窗體中添加一個(gè)按鈕。2) 改變按鈕的屬性:Name為“B2:Text為用DllImport調(diào)用DLL中count函數(shù)”,并將按鈕B1調(diào)整到適當(dāng)大小,移到適當(dāng)位置。3) 打開"Form1.cs”代碼視圖,使用關(guān)鍵字static和extern聲明方法"count并
12、使其具有來自Count.dll的導(dǎo)出函數(shù)count的實(shí)現(xiàn),代碼如下:DllImport("Count.dll")staticexternintcount(intinit);4) 在“Form1.cs設(shè)計(jì)”視圖中雙擊按鈕B2,在“B2_Click方'法體內(nèi)添加如下代碼:MessageBox.Show("用DllImport調(diào)用DLL中的count函數(shù),n傳入的實(shí)參為0,得到的結(jié)果是:"+count(0).ToString(),"挑戰(zhàn)杯");MessageBox.Show("用DllImport調(diào)用DLL中的count函
13、數(shù),n傳入的實(shí)參為10,得到的結(jié)果是:"+count(10).ToString()+"n結(jié)果可不是想要的11哦!","挑戰(zhàn)杯");MessageBox.Show("所得結(jié)果表明:n用DllImport調(diào)用DLL中的非托管n函數(shù)是全局的、靜態(tài)的函數(shù)!","挑戰(zhàn)杯");5) 把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)”的結(jié)果,由所得結(jié)
14、果可以證明用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/unloadassembly那樣,所以只能借助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的AfxFreeLibra
15、ry),釋放動(dòng)態(tài)鏈接庫(kù)。它們的原型分別是:HMODULELoadLibrary(LPCTSTRlpFileName);FARPROCGetProcAddress(HMODULEhModule,LPCWSTRlpProcName);BOOLFreeLibrary(HMODULEhModule);現(xiàn)在,我們可以用IntPtrhModule=LoadLibrary("Count.dll");來獲得Dll的句柄,用IntPtrfarProc=GetProcAddress(hModule,"_count4來御導(dǎo)函數(shù)的入口地址。但是,知道函數(shù)的入口地址后,怎樣調(diào)用這個(gè)函數(shù)呢?
16、因?yàn)樵贑#中是沒有函數(shù)指針的,沒有像C+那樣的函數(shù)指針調(diào)用方式來調(diào)用函數(shù),所以我們得借助其它方法。經(jīng)過研究,發(fā)現(xiàn)我們可以通過結(jié)合使用System.Reflection.Emit及System.Reflection.Assembly里的類和函數(shù)達(dá)到我們的目的。為了以后使用方便及實(shí)現(xiàn)代碼的復(fù)用,我們可以編寫一個(gè)類。1) dld類的編寫:1. 打開項(xiàng)目“Tzb,”打開類視圖,右擊“Tzb,”選擇添加"->'類”,類名設(shè)置為“dld,"即dynamicloadingdll的每個(gè)單詞的開頭字母。用DllImport需用此命名空間2. 添加所需的命名空間及聲明參數(shù)傳遞方式
17、枚舉:usingSystem.Runtime.InteropServices;/使用Assembly類需用此命名空間usingSystem.Reflection;/usingSystem.Reflection.Emit;/使用Generator需用此命名空間在"publicclassdld上面添加如下代碼聲明參數(shù)傳遞方式枚舉:/<summary>/參數(shù)傳遞方式枚舉,ByValue表示值傳遞,ByRef表示址傳遞/</summary>publicenumModePassByValue=0x0001,ByRef=0x00023. 聲明LoadLibrary、Get
18、ProcAddress、FreeLibrary及私有變量hModule和farProc/<summary>/原型是:HMODULELoadLibrary(LPCTSTRlpFileName);/</summary>/<paramname="lpFileName">DLL文件名</param>/<returns>函數(shù)庫(kù)模塊的句柄</returns>DllImport("kernel32.dll")staticexternIntPtrLoadLibrary(stringlpFileNam
19、e);/<summary>/原型是:FARPROCGetProcAddress(HMODULEhModule,LPCWSTRlpProcName);Ill</summary>III<paramname="hModule">包含需調(diào)用函數(shù)的函數(shù)庫(kù)模塊的句柄<lparam>Ill<paramname="lpProcName">調(diào)用函數(shù)的名稱<lparam>Ill<returns>函數(shù)指針<lreturns>DllImport("kernel32.dll&
20、quot;)staticexternIntPtrGetProcAddress(IntPtrhModule,stringlpProcName);Ill<summary>Ill原型是:BOOLFreeLibrary(HMODULEhModule);Ill<lsummary>Ill<paramname="hModule">需釋放的函數(shù)庫(kù)模塊的句柄<lparam>Ill<returns>是否已釋放指定的Dll<lreturns>DllImport("kernel32",EntryPoint=
21、"FreeLibrary",SetLastError=true)staticexternboolFreeLibrary(IntPtrhModule);Ill<summary>IllLoadlibrary返回的函數(shù)庫(kù)模塊的句柄Ill<lsummary>privateIntPtrhModule=IntPtr.Zero;Ill<summary>IllGetProcAddress返回的函數(shù)指針I(yè)ll<lsummary>privateIntPtrfarProc=IntPtr.Zero;4. 添加LoadDll方法,并為了調(diào)用時(shí)方便,重載
22、了這個(gè)方法:Ill<summary>/裝載DllIII</summary>/<paramname="lpFileName">DLL文件名</param>publicvoidLoadDll(stringlpFileName)(hModule=LoadLibrary(lpFileName);if(hModule=IntPtr.Zero)throw(newException("沒有找到:"+lpFileName+".");)若已有已裝載Dll的句柄,可以使用LoadDll方法的第二個(gè)版本:pu
23、blicvoidLoadDll(IntPtrHMODULE)(if(HMODULE=IntPtr.Zero)throw(newException("所傳入的函數(shù)庫(kù)模塊的句柄HMODUL時(shí)空.");hModule=HMODULE;)5. 添加LoadFun方法,并為了調(diào)用時(shí)方便,也重載了這個(gè)方法,方法的具體代碼及注釋如下:/<summary>/獲得函數(shù)指針/</summary>Ill<paramname="lpProcName">調(diào)用函數(shù)的名稱</param>publicvoidLoadFun(stringI
24、pProcName)II若函數(shù)庫(kù)模塊的句柄為空,則拋出異常if(hModule=IntPtr.Zero)throw(newException("函數(shù)庫(kù)模塊的句柄為空,請(qǐng)確保已進(jìn)行LoadDll操作!");II取得函數(shù)指針farProc=GetProcAddress(hModule,lpProcName);II若函數(shù)指針,則拋出異常if(farProc=IntPtr.Zero)throw(newException("沒有找到:"+lpProcName+”這個(gè)函數(shù)的入口點(diǎn)");)III<summary>III獲得函數(shù)指針I(yè)II<I
25、summary>III<paramname="lpFileName">包含需調(diào)用函數(shù)的DLL文件名<Iparam>III<paramname="lpProcName">調(diào)用函數(shù)的名稱<Iparam>publicvoidLoadFun(stringlpFileName,stringlpProcName)II取得函數(shù)庫(kù)模塊的句柄hModule=LoadLibrary(lpFileName);II若函數(shù)庫(kù)模塊的句柄為空,則拋出異常if(hModule=IntPtr.Zero)throw(newExcepti
26、on("沒有找到:"+lpFileName+".");II取得函數(shù)指針farProc=GetProcAddress(hModule,lpProcName);II若函數(shù)指針,則拋出異常if(farProc=IntPtr.Zero)throw(newException("沒有找到:"+lpProcName+”這個(gè)函數(shù)的入口點(diǎn)");)6.添加UnLoadDll及Invoke方法,Invoke方法也進(jìn)行了重載:/<summary>/卸載Dll/</summary>publicvoidUnLoadDll()(F
27、reeLibrary(hModule);hModule=IntPtr.Zero;farProc=IntPtr.Zero;)Invoke方法的第一個(gè)版本:/<summary>/調(diào)用所設(shè)定的函數(shù)/</summary>/<paramname="ObjArray_Parameter">實(shí)參</param>/<paramname="TypeArray_ParameterType">實(shí)參類型</param>/<paramname="ModePassArray_Parameter&
28、quot;>實(shí)參傳送方式</param>/<paramname="Type_Return">返回類型</param>/<returns>返回所調(diào)用函數(shù)的object</returns>publicobjectInvoke(objectObjArray_Parameter,Type口TypeArray_ParameterType,ModePass口ModePassArray_Parameter,TypeType_Return)(/下面3個(gè)if是進(jìn)行安全檢查,若不能通過,則拋出異常if(hModule=IntPt
29、r.Zero)throw(newException("函數(shù)庫(kù)模塊的句柄為空,請(qǐng)確保已進(jìn)行LoadDll操作!");if(farProc=IntPtr.Zero)throw(newException("函數(shù)指針為空,請(qǐng)確保已進(jìn)行LoadFun操作!");if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length)throw(newException("參數(shù)個(gè)數(shù)及其傳遞方式的個(gè)數(shù)不匹配.");/下面是創(chuàng)建MyAssemblyName對(duì)象并設(shè)置其Name屬性AssemblyNam
30、eMyAssemblyName=newAssemblyName();MyAssemblyName.Name="InvokeFun"/生成單模塊配件AssemblyBuilderMyAssemblyBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,AssemblyBuilderAccess.Run);ModuleBuilderMyModuleBuilder=MyAssemblyBuilder.DefineDynamicModule("InvokeDll");/定義要調(diào)用
31、的方法,方法名為"MyFun”,返回類型是"Type_Return”參數(shù)類型是"TypeArray_ParameterTypeMethodBuilderMyMethodBuilder=MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public|MethodAttributes.Static,Type_Return,TypeArray_ParameterType);/獲取一個(gè)ILGenerator,用于發(fā)送所需的ILILGeneratorIL=MyMethodBuilder
32、.GetILGenerator();inti;for(i=0;i<ObjArray_Parameter.Length;i+)/用循環(huán)將參數(shù)依次壓入堆棧switch(ModePassArray_Parameteri)caseModePass.ByValue:IL.Emit(OpCodes.Ldarg,i);break;caseModePass.ByRef:IL.Emit(OpCodes.Ldarga,i);break;default:throw(newException("第"+(i+1).ToString()+"個(gè)參數(shù)沒有給定正確的傳遞方式.");
33、)if(IntPtr.Size=4)/判斷處理器類型IL.Emit(OpCodes.Ldc_I4,farProc.ToInt32();)elseif(IntPtr.Size=8)IL.Emit(OpCodes.Ldc_I8,farProc.ToInt64();)elsethrownewPlatformNotSupportedException();)IL.EmitCalli(OpCodes.Calli,CallingConvention.StdCall,Type_Return,TypeArray_ParameterType);IL.Emit(OpCodes.Ret);/返回值MyModuleB
34、uilder.CreateGlobalFunctions();/取得方法信息MethodinfoMyMethodInfo=MyModuleBuilder.GetMethod("MyFun");returnMyMethodInfo.Invoke(null,ObjArray_Parameter);/調(diào)用方法,并返回其值)Invoke方法的第二個(gè)版本,它是調(diào)用了第一個(gè)版本的:Ill<summary>/調(diào)用所設(shè)定的函數(shù)Ill<lsummary>Ill<paramname="IntPtr_Function">函數(shù)指針<lp
35、aram>lll<paramname="ObjArray_Parameter">實(shí)參<lparam>lll<paramname="TypeArray_ParameterType">實(shí)參類型<lparam>/<paramname="ModePassArray_Parameter">實(shí)參傳送方式<lparam>lll<paramname="Type_Return">返回類型</param>/<returns>
36、;返回所調(diào)用函數(shù)的object</returns>publicobjectInvoke(IntPtrIntPtr_Function,objectObjArray_Parameter,TypeTypeArray_ParameterType,ModePass口ModePassArray_Parameter,TypeType_Return)(/下面2個(gè)if是進(jìn)行安全檢查,若不能通過,則拋出異常if(hModule=IntPtr.Zero)throw(newException("函數(shù)庫(kù)模塊的句柄為空,請(qǐng)確保已進(jìn)行LoadDll操作!");if(IntPtr_Functi
37、on=IntPtr.Zero)throw(newException("函數(shù)指針I(yè)ntPtr_Function為空!");farProc=IntPtr_Function;returnInvoke(ObjArray_Parameter,TypeArray_ParameterType,ModePassArray_Parameter,Type_Return);)2) dld類的使用:1 .打開項(xiàng)目“Tzb,”向“Forml窗體中添加三個(gè)按鈕。Name和Text屬性分別為“B3;'用LoadLibrary方法裝載Count.dll"B4:'調(diào)用count方法
38、","B5:'卸載Count.dll,”并調(diào)整到適當(dāng)?shù)拇笮〖拔恢谩? .在“Forml.cs設(shè)計(jì)”視圖中雙擊按鈕B3,在“B3_Click方'法體上面添加代碼,創(chuàng)建一個(gè)dld類實(shí)例:/<summary>/創(chuàng)建一個(gè)dld類對(duì)象/</summary>privatedldmyfun=newdld();3 .在“B3_Click方法體內(nèi)添加如下代碼:myfun.LoadDll("Count.dll");/加載"Count.dll"myfun.LoadFun("_count4");/調(diào)
39、入函數(shù)count,"_count4"是它的入口,可通過Depends查看4 .“Form1.cs設(shè)計(jì)”視圖中雙擊按鈕B4,在“B4_Click方法體內(nèi)添加如下代碼:object口Parameters=newobject口(int)0;/實(shí)參為0TypeParameterTypes=newType口typeof(int);實(shí)參類型為intModePass口themode=newModePass口ModePass.ByValue;/傳送方式為值傳TypeType_Return=typeof(int);/返回類型為int/彈出提示框,顯示調(diào)用myfun.Invoke方法的結(jié)果,即
40、調(diào)用count函數(shù)MessageBox.Show("這是您裝載該Dll后第"+myfun.Invoke(Parameters,ParameterTypes,themode,Type_Return).ToString()+”次點(diǎn)擊此按鈕。","挑戰(zhàn)杯");5.“Forml.cs設(shè)計(jì)”視圖中雙擊按鈕B5,在“B5_Click方法體內(nèi)添加如下代碼:myfun.UnLoadDll();6.按“F調(diào)行該程序,并先點(diǎn)擊按鈕B3以加載“Count.dll,接著點(diǎn)擊按鈕B4三次以調(diào)用3次“count(0),'先后彈出的提示框如下:這三個(gè)提示框所得出的結(jié)
41、果說明了靜態(tài)變量為為:7.點(diǎn)擊按鈕B5以卸載“Count.dll,再點(diǎn)擊按鈕調(diào)用了"count(0)”的結(jié)果:經(jīng)初始化后,再傳入實(shí)參“理不會(huì)改變其值B3進(jìn)行裝載“Count.dll,再點(diǎn)擊按鈕B4查看也就是實(shí)現(xiàn)了DLL的動(dòng)態(tài)裝載與卸載了。從彈出的提示框所顯示的結(jié)果可以看到又開始重新計(jì)數(shù)了,(3) 調(diào)用托管DLL一般方法C#調(diào)用托管DLL是很簡(jiǎn)單的,只要在解決方案資源管理器”中的需要調(diào)用DLL的項(xiàng)目下用鼠標(biāo)右擊引用”,并選擇添加引用”,然后選擇已列出的DLL或通過瀏覽來選擇DLL文件,最后需要用using導(dǎo)入相關(guān)的命名空間。(4) 動(dòng)態(tài)調(diào)用托管DLLC#動(dòng)態(tài)調(diào)用托管DLL也需要借助Sy
42、stem.Reflection.Assembly里的類和方法,主要使用了Assembly.LoadFrom?,F(xiàn)在,用例子說明:首先,啟動(dòng)VS.NET,新建一個(gè)VisualC#項(xiàng)目,使用的模板為類庫(kù)”,名稱為“CsCount:并在類"Class1"中添加靜態(tài)整型變量S及方法count:/由于static不能修飾方法體內(nèi)的變量,所以需放在這里,且初始化值為int.MinValuestaticintS=int.MinValue;publicintcount(intinit)/判斷S是否等于int.MinValue,是的話把init賦值給Sif(S=int.MinValue)S=i
43、nit;S+;S自增1returnS;/返回S然后,打開項(xiàng)目“Tzb”,向“Form1”窗體中添加一個(gè)按鈕,Name屬性為"B6',Text屬性為用Assembly類來動(dòng)態(tài)調(diào)用托管DLL”,調(diào)整到適當(dāng)大小和位置,雙擊按鈕B6,轉(zhuǎn)入代碼視圖,先導(dǎo)入命名空間:usingSystem.Reflection;接著添加Invoke方法和B6_Click方法代碼:privateobjectInvoke(stringlpFileName,stringNamespace,stringClassName,stringlpProcName,object口ObjArray_Parameter)Tr
44、y/載入程序集AssemblyMyAssembly=Assembly.LoadFrom(lpFileName);Type口type=MyAssembly.GetTypes();foreach(Typetintype)/查找要調(diào)用的命名空間及類if(t.Namespace=Namespace&&t.Name=ClassName)/查找要調(diào)用的方法并進(jìn)行調(diào)用MethodInfom=t.GetMethod(lpProcName);if(m!=null)objecto=Activator.CreateInstance(t);returnm.Invoke(o,ObjArray_Param
45、eter);elseMessageBox.Show("裝載出錯(cuò)!");/trycatch(System.NullReferenceExceptione)MessageBox.Show(e.Message);/catchreturn(object)0;/Invoke“B6_Click方法體內(nèi)代碼如下:/顯示count(0)返回的值MessageBox.Show("這是您第"+Invoke("CsCount.dll","CsCount","Class1","count",newo
46、bject(int)0).ToString()+”次點(diǎn)擊此按鈕。","挑戰(zhàn)杯");最后,把項(xiàng)目“CsCount”的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)用'byte口返回,然后就用Invoke方法那樣對(duì)DLLDLL中必須有該接口的DLL文
47、件作為資源嵌入在C#程序中,我們只要讀取該資源文件并以aAssemblyLoad(byte);得至DLL中的程序集,最后就可以像上面的中的方法進(jìn)行調(diào)用。當(dāng)然不用上面方法也可以,如用接口實(shí)現(xiàn)動(dòng)態(tài)調(diào)用,但4?,F(xiàn)在我只對(duì)像上面的定義并且程序中也要有該接口的定義;也可用反射發(fā)送實(shí)現(xiàn)動(dòng)態(tài)調(diào)用Invoke方法那樣對(duì)DLL中的方法進(jìn)行調(diào)用進(jìn)行討論,為了以后使用方便及實(shí)現(xiàn)代碼的復(fù)用,我們可以結(jié)合上一個(gè)編寫一個(gè)類。1) ldfs類的編寫:在項(xiàng)目"Tzb"中新建一個(gè)名為ldfs的類,意為"loaddllfromresource",請(qǐng)注意,在這個(gè)類中aresource不
48、9;只是嵌入在EXE程序中的資源,它也可以是硬盤上任意一個(gè)DLL文件,這是因?yàn)閘dfs的類中的方法LoadDll有些特別,就是先從程序的內(nèi)嵌的資源中查找需加載的DLL,如果找不到,就查找硬盤上的。首先導(dǎo)入所需的命名空間:usingSystem.IO;/對(duì)文件的讀寫需要用到此命名空間usingSystem.Reflection;/使用Assembly類需用此命名空間usingSystem.Reflection.Emit;/使用Generator需用此命名空間聲明一靜態(tài)變量MyAssembly/記錄要導(dǎo)入的程序集staticAssemblyMyAssembly;添加LoadDll方法:privat
49、ebyteLoadDll(stringlpFileName)(AssemblyNowAssembly=Assembly.GetEntryAssembly();Streamfs=null;try/嘗試讀取資源中的DLLfs=NowAssembly.GetManifestResourceStream(NowAssembly.GetName().Name+”."+lpFileName);finally/如果資源沒有所需的DLL,就查看硬盤上有沒有,有的話就讀取if(fs=null&&!File.Exists(lpFileName)throw(newException(&qu
50、ot;找不到文件:"+lpFileName);elseif(fs=null&&File.Exists(lpFileName)FileStreamFs=newFileStream(lpFileName,FileMode.Open);fs=(Stream)Fs;bytebuffer=newbyte(int)fs.Length;fs.Read(buffer,0,buffer.Length);fs.Close();returnbuffer;/以byte返回讀到的DLL)添加UnLoadDll方法來卸載DLL:publicvoidUnLoadDll()/使MyAssembly指
51、空MyAssembly=null;)添加Invoke方法來進(jìn)行對(duì)DLL中方法的調(diào)用,其原理大體上和“Form1.cs”中的方法Invoke相同,不過這里用的是"Assembly.Load”,而且用了靜態(tài)變量MyAssembly來保存已加載的DLL,如果已加載的話就不再加載,如果還沒加載或者已加載的不同現(xiàn)在要加載的DLL就進(jìn)行加載,其代碼如下所示:publicobjectInvoke(stringlpFileName,stringNamespace,stringClassName,stringlpProcName,object口ObjArray_Parameter)try/判斷MyAssembly是否為空或MyAssembly的命名空間不等于要調(diào)用方法的命名空間,如果條件為真,就用Assembly.Load加載所需DLL作為程序集i
溫馨提示
- 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 汽車美容師網(wǎng)絡(luò)營(yíng)銷與在線推廣試題及答案
- 醫(yī)學(xué)理論試題及答案高中
- 賀州焊工考試題目及答案
- 接單易考試題及答案
- 汽車電路圖的讀取與分析試題及答案
- 小學(xué)語(yǔ)文實(shí)訓(xùn)測(cè)驗(yàn)題試題及答案
- 2024汽車美容師行業(yè)發(fā)展研究試題及答案
- 一年級(jí)語(yǔ)文考題參考與試題答案
- 2024年汽車美容師個(gè)案分析試題及答案
- 如何有效培訓(xùn)
- 常用儀器設(shè)備和搶救物品使用的制度及流程
- 2023年浙江省杭州市余杭區(qū)徑山鎮(zhèn)招聘村務(wù)工作者招聘14人(共500題含答案解析)筆試歷年難、易錯(cuò)考點(diǎn)試題含答案附詳解
- 妊娠滋養(yǎng)細(xì)胞腫瘤課件
- 個(gè)人原因動(dòng)物檢產(chǎn)品檢疫合格證明丟失情況說明
- 中國(guó)的預(yù)算管理
- 油田伴生地?zé)岬拈_發(fā)與利用
- 如坐針氈:我與通用電氣的風(fēng)雨16年
- 部編小學(xué)語(yǔ)文四年級(jí)下冊(cè)第四單元教材分析解讀課件
- 塔機(jī)基礎(chǔ)轉(zhuǎn)換腳計(jì)算書
- GB/T 32620.2-2016電動(dòng)道路車輛用鉛酸蓄電池第2部分:產(chǎn)品品種和規(guī)格
- 污水處理廠設(shè)備安裝方案
評(píng)論
0/150
提交評(píng)論