亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > .NET > 正文

ASP.NET/C#中如何調用動態鏈接庫DLL

2024-07-10 13:30:00
字體:
來源:轉載
供稿:網友
這篇文章主要為大家詳細介紹了ASP.NET/C#中如何調用動態鏈接庫DLL,感興趣的小伙伴們可以參考一下
 

動態鏈接庫(也稱為DLL,即為“Dynamic Link Library”的縮寫)是Microsoft Windows最重要的組成要素之一,打開Windows系統文件夾,你會發現文件夾中有很多DLL文件,Windows就是將一些主要的系統功能以DLL模塊的形式實現。 
動態鏈接庫是不能直接執行的,也不能接收消息,它只是一個獨立的文件,其中包含能被程序或其它DLL調用來完成一定操作的函數(方法。注:C#中一般稱為“方法”),但這些函數不是執行程序本身的一部分,而是根據進程的需要按需載入,此時才能發揮作用。
DLL只有在應用程序需要時才被系統加載到進程的虛擬空間中,成為調用進程的一部分,此時該DLL也只能被該進程的線程訪問,它的句柄可以被調用進程所使用,而調用進程的句柄也可以被該DLL所使用。在內存中,一個DLL只有一個實例,且它的編制與具體的編程語言和編譯器都沒有關系,所以可以通過DLL來實現混合語言編程。DLL函數中的代碼所創建的任何對象(包括變量)都歸調用它的線程或進程所有。
下面列出了當程序使用 DLL 時提供的一些優點:

1)使用較少的資源
當多個程序使用同一個函數庫時,DLL 可以減少在磁盤和物理內存中加載的代碼的重復量。這不僅可以大大影響在前臺運行的程序,而且可以大大影響其他在 Windows 操作系統上運行的程序。 
2)推廣模塊式體系結構
DLL 有助于促進模塊式程序的開發。這可以幫助您開發要求提供多個語言版本的大型程序或要求具有模塊式體系結構的程序。模塊式程序的一個示例是具有多個可以在運行時動態加載的模塊的計帳程序。 
3)簡化部署和安裝
當 DLL 中的函數需要更新或修復時,部署和安裝 DLL 不要求重新建立程序與該 DLL 的鏈接。此外,如果多個程序使用同一個 DLL,那么多個程序都將從該更新或修復中獲益。當您使用定期更新或修復的第三方 DLL 時,此問題可能會更頻繁地出現。 
每種編程語言調用DLL的方法都不盡相同,在此只對用C#調用DLL的方法進行介紹。首先,您需要了解什么是托管,什么是非托管。一般可以認為:非托管代碼主要是基于win 32平臺開發的DLL,activeX的組件,托管代碼是基于.net平臺開發的。如果您想深入了解托管與非托管的關系與區別,及它們的運行機制,請您自行查找資料,本文件在此不作討論。 

(一) 、調用DLL中的非托管函數一般方法
首先,應該在C#語言源程序中聲明外部方法,其基本形式是:
[DLLImport(“DLL文件”)]
修飾符 extern 返回變量類型 方法名稱 (參數列表)
其中:
DLL文件:包含定義外部方法的庫文件。
修飾符: 訪問修飾符,除了abstract以外在聲明方法時可以使用的修飾符。
返回變量類型:在DLL文件中你需調用方法的返回變量類型。
方法名稱:在DLL文件中你需調用方法的名稱。
參數列表:在DLL文件中你需調用方法的列表。
注意:需要在程序聲明中使用System.Runtime.InteropServices命名空間。
          DllImport只能放置在方法聲明上。

DLL文件必須位于程序當前目錄或系統定義的查詢路徑中(即:系統環境變量中Path所設置的路徑)。
返回變量類型、方法名稱、參數列表一定要與DLL文件中的定義相一致。
若要使用其它函數名,可以使用EntryPoint屬性設置,如:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static 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指示入口點的調用約定, 如:CallingConvention=CallingConvention.Winapi;
此外,關于“數據封送處理”及“封送數字和邏輯標量”請參閱其它一些文章[2]。

C#例子:

1. 啟動VS.NET,新建一個項目,項目名稱為“Tzb”,模板為“Windows 應用程序”。
2. 在“工具箱”的“ Windows 窗體”項中雙擊“Button”項,向“Form1”窗體中添加一個按鈕。
3. 改變按鈕的屬性:Name為 “B1”,Text為 “用DllImport調用DLL彈出提示框”,并將按鈕B1調整到適當大小,移到適當位置。
4. 在類視圖中雙擊“Form1”,打開“Form1.cs”代碼視圖,在“namespace Tzb”上面輸入“using System.Runtime.InteropServices;”,以導入該命名空間。
5. 在“Form1.cs[設計]”視圖中雙擊按鈕B1,在“B1_Click”方法上面使用關鍵字 static 和 extern 聲明方法“MsgBox”,將 DllImport 屬性附加到該方法,這里我們要使用的是“user32.dll”中的“MessageBoxA”函數,具體代碼如下:

[DllImport("user32.dll", EntryPoint="MessageBoxA")]static extern int MsgBox(int hWnd, string msg, string caption, int type);

然后在“B1_Click”方法體內添加如下代碼,以調用方法“MsgBox”:
MsgBox(0," 這就是用 DllImport 調用 DLL 彈出的提示框哦! "," 挑戰杯 ",0x30);
6. 按“F5”運行該程序,并點擊按鈕B1,便彈出如下提示框:

7.代碼如下:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;namespace WindowsFormsApplication1{  public partial class Form1 : Form  {    [DllImport("user32.dll", EntryPoint = "MessageBoxA")]    static extern int MsgBox2(int hWnd, string msg, string caption, int type);    public Form1()    {      InitializeComponent();    }    private void Form1_Load(object sender, EventArgs e)    {    }        private void button1_Click(object sender, EventArgs e)    {      MsgBox2(0, " 這就是用 DllImport 調用 DLL 彈出的提示框哦! ", " 挑戰杯 ", 0x30);    }    private void button2_Click(object sender, EventArgs e)    {      MsgBox2(0, " 這就是用 DllImport 調用 DLL 彈出的提示框哦222222f! ", " 222222 ", 0x30);    }  }}

(二)     動態裝載、調用DLL中的非托管函數
在上面已經說明了如何用DllImport調用DLL中的非托管函數,但是這個是全局的函數,假若DLL中的非托管函數有一個靜態變量S,每次調用這個函數的時候,靜態變量S就自動加1。結果,當需要重新計數時,就不能得出想要的結果。下面將用例子說明:
1.  DLL的創建
1) 、啟動Visual C++ 6.0;
2) 、新建一個“Win32 Dynamic-Link Library”工程,工程名稱為“Count”;
3) 、在“Dll kind”選擇界面中選擇“A simple dll project”;
4) 、打開Count.cpp,添加如下代碼:

// 導出函數,使用“ _stdcall ” 標準調用extern "C" _declspec(dllexport)int _stdcall count(int init);int _stdcall count(int init){//count 函數,使用參數 init 初始化靜態的整形變量 S ,并使 S 自加 1 后返回該值static int S=init;S++;return S;}

5) 、按“F7”進行編譯,得到Count.dll(在工程目錄下的Debug文件夾中)。
2.   用DllImport調用DLL中的count函數
1) 、打開項目“Tzb”,向“Form1”窗體中添加一個按鈕。
2) 、改變按鈕的屬性:Name為 “B2”,Text為 “用DllImport調用DLL中count函數”,并將按鈕B1調整到適當大小,移到適當位置。
3) 、打開“Form1.cs”代碼視圖,使用關鍵字 static 和 extern 聲明方法“count”,并使其具有來自 Count.dll 的導出函數count的實現,代碼如下:

[DllImport("Count.dll")]static extern int count(int init);

4) 、 在“Form1.cs[設計]”視圖中雙擊按鈕B2,在“B2_Click”方法體內添加如下代碼:
MessageBox.Show(" 用 DllImport 調用 DLL 中的 count 函數, n 傳入的實參為 0 ,得到的結果是: "+count(0).ToString()," 挑戰杯 ");
MessageBox.Show(" 用 DllImport 調用 DLL 中的 count 函數, n 傳入的實參為 10 ,得到的結果是: "+count(10).ToString()+"n 結果可不是想要的 11 哦!?。?"," 挑戰杯 ");
MessageBox.Show(" 所得結果表明: n 用 DllImport 調用 DLL 中的非托管 n 函數是全局的、靜態的函數!?。?"," 挑戰杯 ");
5) 、把Count.dll復制到項目“Tzb”的binDebug文件夾中,按“F5”運行該程序,并點擊按鈕B2,便彈出如下三個提示框:

第1個提示框顯示的是調用“count(0)”的結果,第2個提示框顯示的是調用“count(10)”的結果,由所得結果可以證明“用DllImport調用DLL中的非托管函數是全局的、靜態的函數”。所以,有時候并不能達到我們目的,因此我們需要使用下面所介紹的方法:C#動態調用DLL中的函數。
3. C#動態調用DLL中的函數
因為C#中使用DllImport是不能像動態load/unload assembly那樣,所以只能借助API函數了。在kernel32.dll中,與動態庫調用有關的函數包括:

①LoadLibrary(或MFC 的AfxLoadLibrary),裝載動態庫。
②GetProcAddress,獲取要引入的函數,將符號名或標識號轉換為DLL內部地址。
③FreeLibrary(或MFC的AfxFreeLibrary),釋放動態鏈接庫。
它們的原型分別是:
HMODULE LoadLibrary(LPCTSTR lpFileName);
FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
BOOL FreeLibrary(HMODULE hModule);
現在,我們可以用IntPtr hModule=LoadLibrary(“Count.dll”);來獲得Dll的句柄,用IntPtr farProc=GetProcAddress(hModule,”_count@4”);來獲得函數的入口地址。
但是,知道函數的入口地址后,怎樣調用這個函數呢?因為在C#中是沒有函數指針的,沒有像C++那樣的函數指針調用方式來調用函數,所以我們得借助其它方法。經過研究,發現我們可以通過結合使用System.Reflection.Emit及System.Reflection.Assembly里的類和函數達到我們的目的。為了以后使用方便及實現代碼的復用,我們可以編寫一個類。
1)、 dld類的編寫:
1. 打開項目“Tzb”,打開類視圖,右擊“Tzb”,選擇“添加”-->“類”,類名設置為“dld”,即dynamic loading dll 的每個單詞的開頭字母。
2. 添加所需的命名空間及聲明參數傳遞方式枚舉:

using System.Runtime.InteropServices; // 用 DllImport 需用此 命名空間using System.Reflection; // 使用 Assembly 類需用此 命名空間using System.Reflection.Emit; // 使用 ILGenerator 需用此 命名空間

在“public class dld”上面添加如下代碼聲明參數傳遞方式枚舉:

/// <summary>/// 參數傳遞方式枚舉 ,ByValue 表示值傳遞 ,ByRef 表示址傳遞/// </summary>public enum ModePass{ByValue = 0x0001,ByRef = 0x0002}

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

/// <summary>/// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);/// </summary>/// <param name="lpFileName">DLL 文件名 </param>/// <returns> 函數庫模塊的句柄 </returns>[DllImport("kernel32.dll")]static extern IntPtr LoadLibrary(string lpFileName);/// <summary>/// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);/// </summary>/// <param name="hModule"> 包含需調用函數的函數庫模塊的句柄 </param>/// <param name="lpProcName"> 調用函數的名稱 </param>/// <returns> 函數指針 </returns>[DllImport("kernel32.dll")]static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);/// <summary>/// 原型是 : BOOL FreeLibrary(HMODULE hModule);/// </summary>/// <param name="hModule"> 需釋放的函數庫模塊的句柄 </param>/// <returns> 是否已釋放指定的 Dll</returns>[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]static extern bool FreeLibrary(IntPtr hModule);/// <summary>/// Loadlibrary 返回的函數庫模塊的句柄/// </summary>private IntPtr hModule=IntPtr.Zero;/// <summary>/// GetProcAddress 返回的函數指針/// </summary>private IntPtr farProc=IntPtr.Zero;

4.添加LoadDll方法,并為了調用時方便,重載了這個方法:

/// <summary>/// 裝載 Dll/// </summary>/// <param name="lpFileName">DLL 文件名 </param>public void LoadDll(string lpFileName){hModule=LoadLibrary(lpFileName);if(hModule==IntPtr.Zero)throw(new Exception(" 沒有找到 :"+lpFileName+"." ));}     若已有已裝載Dll的句柄,可以使用LoadDll方法的第二個版本:public void LoadDll(IntPtr HMODULE){if(HMODULE==IntPtr.Zero)throw(new Exception(" 所傳入的函數庫模塊的句柄 HMODULE 為空 ." ));hModule=HMODULE;}

5. 添加LoadFun方法,并為了調用時方便,也重載了這個方法,方法的具體代碼及注釋如下:

/// <summary>/// 獲得函數指針/// </summary>/// <param name="lpProcName"> 調用函數的名稱 </param>public void LoadFun(string lpProcName){ // 若函數庫模塊的句柄為空,則拋出異常if(hModule==IntPtr.Zero)throw(new Exception(" 函數庫模塊的句柄為空 , 請確保已進行 LoadDll 操作 !"));// 取得函數指針farProc = GetProcAddress(hModule,lpProcName);// 若函數指針,則拋出異常if(farProc==IntPtr.Zero)throw(new Exception(" 沒有找到 :"+lpProcName+" 這個函數的入口點 "));}/// <summary>/// 獲得函數指針/// </summary>/// <param name="lpFileName"> 包含需調用函數的 DLL 文件名 </param>/// <param name="lpProcName"> 調用函數的名稱 </param>public void LoadFun(string lpFileName,string lpProcName){ // 取得函數庫模塊的句柄hModule=LoadLibrary(lpFileName);// 若函數庫模塊的句柄為空,則拋出異常if(hModule==IntPtr.Zero)throw(new Exception(" 沒有找到 :"+lpFileName+"." ));// 取得函數指針farProc = GetProcAddress(hModule,lpProcName);// 若函數指針,則拋出異常if(farProc==IntPtr.Zero)throw(new Exception(" 沒有找到 :"+lpProcName+" 這個函數的入口點 "));}

6. 添加UnLoadDll及Invoke方法,Invoke方法也進行了重載:

/// <summary>/// 卸載 Dll/// </summary>public void UnLoadDll(){FreeLibrary(hModule);hModule=IntPtr.Zero;farProc=IntPtr.Zero;}

以上就是ASP.NET調用動態鏈接庫DLL的方法,希望對大家的學習有所幫助。

 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
中文字幕视频在线免费欧美日韩综合在线看| 午夜美女久久久久爽久久| 日本精品久久久久久久| 国产精品18久久久久久麻辣| 麻豆国产va免费精品高清在线| 精品久久久999| 中文字幕精品—区二区| 中文字幕在线看视频国产欧美| 亚洲理论电影网| 国产91色在线|免| 国产亚洲视频中文字幕视频| 国产精品久久久久久久久久ktv| 色偷偷噜噜噜亚洲男人的天堂| 欧美精品电影在线| 国产精品尤物福利片在线观看| www.欧美三级电影.com| 欧美激情视频在线免费观看 欧美视频免费一| 91精品久久久久久久久久久| 国产一区二区丝袜| 91爱爱小视频k| 欧美午夜宅男影院在线观看| 国产精品久久久久久久天堂| 91久久久国产精品| 米奇精品一区二区三区在线观看| 亚洲第一av在线| 久久精品中文字幕| 亚州av一区二区| 欧美亚洲国产精品| 韩剧1988在线观看免费完整版| 亚洲丝袜一区在线| 98精品国产自产在线观看| 欧美日韩一区二区在线播放| 狠狠躁18三区二区一区| 亚洲欧洲在线看| 亚洲综合在线做性| 91夜夜未满十八勿入爽爽影院| 中文字幕无线精品亚洲乱码一区| 精品国产精品自拍| 在线国产精品播放| 国产精品入口免费视频一| 成人羞羞国产免费| 一区二区三区国产视频| 在线精品高清中文字幕| 97精品一区二区三区| 日韩精品在线视频美女| 97精品国产97久久久久久春色| 欧美日韩在线另类| 亚洲人永久免费| 国产精品99免视看9| 黄色91在线观看| 精品久久香蕉国产线看观看亚洲| 精品人伦一区二区三区蜜桃免费| 国产一区二区三区高清在线观看| 亚洲国产精品成人av| 久久精品国产视频| 欧美成人久久久| 性欧美视频videos6一9| 亚洲精品国产福利| 91香蕉亚洲精品| 欧美wwwxxxx| 国产亚洲福利一区| 亚洲国产日韩欧美在线99| 国产一区二区日韩| 26uuu另类亚洲欧美日本一| 国产成人精品综合久久久| 九色成人免费视频| 欧美视频精品一区| 91精品国产自产在线老师啪| 亚洲第一天堂无码专区| 日韩经典一区二区三区| 色噜噜狠狠色综合网图区| 日韩风俗一区 二区| 日本人成精品视频在线| 一区二区成人精品| 精品偷拍一区二区三区在线看| 搡老女人一区二区三区视频tv| 日韩精品高清在线观看| 国产精品视频地址| 日韩av片永久免费网站| 国产亚洲一区二区在线| 狠狠色狠色综合曰曰| 国产成人激情小视频| 日韩精品在线电影| 亚洲午夜色婷婷在线| 91精品91久久久久久| 国产成人在线播放| 色偷偷91综合久久噜噜| 欧美大片va欧美在线播放| 97成人精品视频在线观看| 精品国产户外野外| 国产精品av在线| 欧美精品中文字幕一区| 久久精品视频99| 成人网在线观看| 国产精品久久不能| 欧美午夜性色大片在线观看| 色噜噜国产精品视频一区二区| 91精品视频大全| 91国偷自产一区二区三区的观看方式| 日韩精品免费电影| 亚洲欧美日韩国产精品| 欧美精品亚州精品| 欧美日韩综合视频网址| 高跟丝袜欧美一区| 在线观看成人黄色| 性欧美办公室18xxxxhd| 亚洲欧美激情视频| 欧美一级免费视频| 欧美一区二区影院| 国产精品成久久久久三级| 日韩精品免费一线在线观看| 91精品国产91久久久久久久久| 日本不卡高字幕在线2019| 日韩在线视频导航| 国产成+人+综合+亚洲欧洲| 久久精品久久久久| 亚洲国产99精品国自产| 久久久久久69| 国产日韩欧美在线观看| 国产婷婷成人久久av免费高清| 三级精品视频久久久久| 成人免费直播live| 国产成人a亚洲精品| 久久国产精品久久精品| 亚洲小视频在线观看| 亚洲大胆人体视频| 91精品国产99| 97热在线精品视频在线观看| xvideos成人免费中文版| 国产欧美精品va在线观看| 97在线免费视频| 久久精品国产欧美亚洲人人爽| 亚洲第一区中文99精品| 懂色av一区二区三区| 欧美日韩在线视频首页| 久久亚洲精品视频| 国产精品日日摸夜夜添夜夜av| 高清在线视频日韩欧美| 欧美国产日韩一区二区三区| 7m精品福利视频导航| 久久综合色影院| 日韩免费观看在线观看| 久久精品国产成人| 国产亚洲精品91在线| 日韩国产在线看| 国产美女久久精品| 欧美专区中文字幕| 国产精品视频男人的天堂| 欧美在线观看网址综合| 欧美孕妇孕交黑巨大网站| 在线播放精品一区二区三区| 欧美综合一区第一页| 国内精品美女av在线播放| 精品视频在线播放色网色视频| 伊人男人综合视频网| 91国内精品久久| 亚洲精品美女网站| 国产成人午夜视频网址| 欧美亚洲激情视频| 97精品伊人久久久大香线蕉| 午夜精品免费视频| 欧美在线精品免播放器视频| 亚洲第一区在线观看| 亚洲乱码国产乱码精品精天堂|