濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > ASP.NET/C#中如何調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL

ASP.NET/C#中如何調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL

熱門(mén)標(biāo)簽:遂寧市地圖標(biāo)注app 400電話辦理哪家性?xún)r(jià)比高 地圖定位圖標(biāo)標(biāo)注 地圖標(biāo)注專(zhuān)業(yè)團(tuán)隊(duì) 濮陽(yáng)外呼電銷(xiāo)系統(tǒng)怎么樣 塔城代理外呼系統(tǒng) 代理接電話機(jī)器人如何取消 天心智能電銷(xiāo)機(jī)器人 地圖標(biāo)注的公司有哪些

動(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)加載到進(jìn)程的虛擬空間中,成為調(diào)用進(jìn)程的一部分,此時(shí)該DLL也只能被該進(jìn)程的線程訪問(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)用它的線程或進(jìn)程所有。
下面列出了當(dāng)程序使用 DLL 時(shí)提供的一些優(yōu)點(diǎn):

1)使用較少的資源
當(dāng)多個(gè)程序使用同一個(gè)函數(shù)庫(kù)時(shí),DLL 可以減少在磁盤(pán)和物理內(nèi)存中加載的代碼的重復(fù)量。這不僅可以大大影響在前臺(tái)運(yùn)行的程序,而且可以大大影響其他在 Windows 操作系統(tǒng)上運(yùn)行的程序。
2)推廣模塊式體系結(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)。
每種編程語(yǔ)言調(diào)用DLL的方法都不盡相同,在此只對(duì)用C#調(diào)用DLL的方法進(jìn)行介紹。首先,您需要了解什么是托管,什么是非托管。一般可以認(rèn)為:非托管代碼主要是基于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(“DLL文件”)]
修飾符 extern 返回變量類(lèi)型 方法名稱(chēng) (參數(shù)列表)
其中:
DLL文件:包含定義外部方法的庫(kù)文件。
修飾符: 訪問(wèn)修飾符,除了abstract以外在聲明方法時(shí)可以使用的修飾符。
返回變量類(lèi)型:在DLL文件中你需調(diào)用方法的返回變量類(lèi)型。
方法名稱(chēng):在DLL文件中你需調(diào)用方法的名稱(chēng)。
參數(shù)列表:在DLL文件中你需調(diào)用方法的列表。
注意:需要在程序聲明中使用System.Runtime.InteropServices命名空間。
          DllImport只能放置在方法聲明上。

DLL文件必須位于程序當(dāng)前目錄或系統(tǒng)定義的查詢(xún)路徑中(即:系統(tǒng)環(huán)境變量中Path所設(shè)置的路徑)。
返回變量類(lèi)型、方法名稱(chēng)、參數(shù)列表一定要與DLL文件中的定義相一致。
若要使用其它函數(shù)名,可以使用EntryPoint屬性設(shè)置,如:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
其它可選的 DllImportAttribute 屬性:阿
CharSet 指示用在入口點(diǎn)中的字符集,如:CharSet=CharSet.Ansi;
SetLastError 指示方法是否保留 Win32"上一錯(cuò)誤",如:SetLastError=true;
ExactSpelling 指示 EntryPoint 是否必須與指示的入口點(diǎn)的拼寫(xiě)完全匹配,如:ExactSpelling=false;
PreserveSig指示方法的簽名應(yīng)當(dāng)被保留還是被轉(zhuǎn)換, 如:PreserveSig=true;
CallingConvention指示入口點(diǎn)的調(diào)用約定, 如:CallingConvention=CallingConvention.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. 在“工具箱”的“ Windows 窗體”項(xiàng)中雙擊“Button”項(xiàng),向“Form1”窗體中添加一個(gè)按鈕。
3. 改變按鈕的屬性:Name為 “B1”,Text為 “用DllImport調(diào)用DLL彈出提示框”,并將按鈕B1調(diào)整到適當(dāng)大小,移到適當(dāng)位置。
4. 在類(lèi)視圖中雙擊“Form1”,打開(kāi)“Form1.cs”代碼視圖,在“namespace Tzb”上面輸入“using System.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")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);

然后在“B1_Click”方法體內(nèi)添加如下代碼,以調(diào)用方法“MsgBox”:
MsgBox(0," 這就是用 DllImport 調(diào)用 DLL 彈出的提示框哦! "," 挑戰(zhàn)杯 ",0x30);
6. 按“F5”運(yùn)行該程序,并點(diǎn)擊按鈕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 調(diào)用 DLL 彈出的提示框哦! ", " 挑戰(zhàn)杯 ", 0x30);
    }

    private void button2_Click(object sender, EventArgs e)
    {
      MsgBox2(0, " 這就是用 DllImport 調(diào)用 DLL 彈出的提示框哦222222f! ", " 222222 ", 0x30);

    }
  }
}

(二)     動(dòng)態(tài)裝載、調(diào)用DLL中的非托管函數(shù)
在上面已經(jīng)說(shuō)明了如何用DllImport調(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)用
extern "C" _declspec(dllexport)int _stdcall count(int init);
int _stdcall count(int init)
{//count 函數(shù),使用參數(shù) init 初始化靜態(tài)的整形變量 S ,并使 S 自加 1 后返回該值
static int S=init;
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”,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)自 Count.dll 的導(dǎo)出函數(shù)count的實(shí)現(xiàn),代碼如下:

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

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 函數(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é)果可以證明“用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那樣,所以只能借助API函數(shù)了。在kernel32.dll中,與動(dòng)態(tài)庫(kù)調(diào)用有關(guān)的函數(shù)包括:

①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(HMODULE hModule);
現(xiàn)在,我們可以用IntPtr hModule=LoadLibrary(“Count.dll”);來(lái)獲得Dll的句柄,用IntPtr farProc=GetProcAddress(hModule,”_count@4”);來(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á)到我們的目的。為了以后使用方便及實(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”,即dynamic loading dll 的每個(gè)單詞的開(kāi)頭字母。
2. 添加所需的命名空間及聲明參數(shù)傳遞方式枚舉:

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

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

/// summary>
/// 參數(shù)傳遞方式枚舉 ,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> 函數(shù)庫(kù)模塊的句柄 /returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
/// summary>
/// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
/// /summary>
/// param name="hModule"> 包含需調(diào)用函數(shù)的函數(shù)庫(kù)模塊的句柄 /param>
/// param name="lpProcName"> 調(diào)用函數(shù)的名稱(chēng) /param>
/// returns> 函數(shù)指針 /returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
/// summary>
/// 原型是 : BOOL FreeLibrary(HMODULE hModule);
/// /summary>
/// param name="hModule"> 需釋放的函數(shù)庫(kù)模塊的句柄 /param>
/// returns> 是否已釋放指定的 Dll/returns>
[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
/// summary>
/// Loadlibrary 返回的函數(shù)庫(kù)模塊的句柄
/// /summary>
private IntPtr hModule=IntPtr.Zero;
/// summary>
/// GetProcAddress 返回的函數(shù)指針
/// /summary>
private IntPtr farProc=IntPtr.Zero;

4.添加LoadDll方法,并為了調(diào)用時(shí)方便,重載了這個(gè)方法:

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

5. 添加LoadFun方法,并為了調(diào)用時(shí)方便,也重載了這個(gè)方法,方法的具體代碼及注釋如下:

/// summary>
/// 獲得函數(shù)指針
/// /summary>
/// param name="lpProcName"> 調(diào)用函數(shù)的名稱(chēng) /param>
public void LoadFun(string lpProcName)
{ // 若函數(shù)庫(kù)模塊的句柄為空,則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函數(shù)庫(kù)模塊的句柄為空 , 請(qǐng)確保已進(jìn)行 LoadDll 操作 !"));
// 取得函數(shù)指針
farProc = GetProcAddress(hModule,lpProcName);
// 若函數(shù)指針,則拋出異常
if(farProc==IntPtr.Zero)
throw(new Exception(" 沒(méi)有找到 :"+lpProcName+" 這個(gè)函數(shù)的入口點(diǎn) "));
}
/// summary>
/// 獲得函數(shù)指針
/// /summary>
/// param name="lpFileName"> 包含需調(diào)用函數(shù)的 DLL 文件名 /param>
/// param name="lpProcName"> 調(diào)用函數(shù)的名稱(chēng) /param>
public void LoadFun(string lpFileName,string lpProcName)
{ // 取得函數(shù)庫(kù)模塊的句柄
hModule=LoadLibrary(lpFileName);
// 若函數(shù)庫(kù)模塊的句柄為空,則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 沒(méi)有找到 :"+lpFileName+"." ));
// 取得函數(shù)指針
farProc = GetProcAddress(hModule,lpProcName);
// 若函數(shù)指針,則拋出異常
if(farProc==IntPtr.Zero)
throw(new Exception(" 沒(méi)有找到 :"+lpProcName+" 這個(gè)函數(shù)的入口點(diǎn) "));
}

6. 添加UnLoadDll及Invoke方法,Invoke方法也進(jìn)行了重載:

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

以上就是ASP.NET調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL的方法,希望對(duì)大家的學(xué)習(xí)有所幫助。

您可能感興趣的文章:
  • Asp.NET Core 如何調(diào)用WebService的方法
  • ASP.NET:把a(bǔ)shx寫(xiě)到類(lèi)庫(kù)里并在頁(yè)面上調(diào)用的具體方法
  • asp.net 根據(jù)漢字的拼音首字母搜索數(shù)據(jù)庫(kù)(附 LINQ 調(diào)用方法)
  • 使用IronPython把Python腳本集成到.NET程序中的教程
  • 如何不用安裝python就能在.NET里調(diào)用Python庫(kù)

標(biāo)簽:汕頭 宜春 吉林 麗江 河南 重慶 本溪 婁底

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《ASP.NET/C#中如何調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL》,本文關(guān)鍵詞  ASP.NET,中,如何,調(diào)用,動(dòng)態(tài),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《ASP.NET/C#中如何調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于ASP.NET/C#中如何調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    宁陕县| 太谷县| 玉林市| 肥西县| 西林县| 宁都县| 隆安县| 锦屏县| 政和县| 壶关县| 莱州市| 灌阳县| 柯坪县| 葫芦岛市| 犍为县| 高唐县| 库伦旗| 台东市| 大丰市| 彭州市| 元阳县| 闸北区| 绥棱县| 临洮县| 青海省| 景洪市| 沈丘县| 桐乡市| 亚东县| 景谷| 阳城县| 永城市| 富宁县| 崇信县| 莱州市| 上思县| 平顺县| 开封县| 横峰县| 东至县| 汶上县|