如何編寫DLL動(dòng)態(tài)鏈接庫(kù)

本文轉(zhuǎn)載自CSDN https://blog.csdn.net/qq_23100787/article/details/51241103?

我們需要學(xué)會(huì)使用dll是為了模塊化編程,這點(diǎn)非常好,而編譯調(diào)用dll我們需要解決如下的問(wèn)題:

1,如何聲明dll中的函數(shù)及文件

2,如何在應(yīng)用程序中調(diào)用dll

在如下的文章中,這兩個(gè)問(wèn)題的語(yǔ)法都能夠得到解決 ??

在大學(xué)大一的時(shí)候?qū)W的是C,然后后來(lái)大二的時(shí)候?qū)I(yè)又開(kāi)了C++這個(gè)課程,然后再后來(lái)自己又自學(xué)了一點(diǎn)VC++,大三的時(shí)候也試著編寫過(guò)一個(gè)MFC的最簡(jiǎn)單的窗口程序。到大四的時(shí)候,自己又做了一個(gè)GIS的項(xiàng)目,是用C#.NET來(lái)編寫的,然后發(fā)現(xiàn)C#上手好容易,而且還大部分語(yǔ)法規(guī)則都沿用了C,C++的習(xí)慣,于是覺(jué)得C++實(shí)在是沒(méi)有一點(diǎn)優(yōu)勢(shì)可言啊。但這個(gè)暑假的實(shí)習(xí)經(jīng)歷又改變了我的觀點(diǎn):C++在寫窗口程序雖然麻煩,但是卻什么能做,而且對(duì)比C#來(lái)說(shuō),對(duì)運(yùn)行環(huán)境的要求不高,不用像C#程序在安裝之前還要安裝100M多的運(yùn)行.NET環(huán)境。C++和C#各有優(yōu)缺,目前我對(duì)它們倆的定位是:C++用來(lái)寫一些底層的程序,比如驅(qū)動(dòng),或者是一些算法類型的函數(shù)接口,然后用C#來(lái)調(diào)用這些接口并進(jìn)行界面設(shè)計(jì)。如何函數(shù)的實(shí)現(xiàn)跨語(yǔ)言呢?顯然DLL是個(gè)很重要的內(nèi)容,故在此對(duì)VC++的DLL模塊進(jìn)行介紹。

1?用VC創(chuàng)建DLL動(dòng)態(tài)連接庫(kù)


1.1 創(chuàng)建dll項(xiàng)目

然后選擇“一個(gè)空的dll工程”,然后點(diǎn)擊“確定”便完成了“創(chuàng)建dll項(xiàng)目”的流程。


1.2 為dll項(xiàng)目編寫源文件

新建兩個(gè)文件:dllDemo.h, dllDemo.cpp

在頭文件”dllDemo.h”中聲明三個(gè)接口函數(shù):

extern"C" _declspec(dllexport)intSum(inta,intb);//加法函數(shù)。extern"C" _declspec(dllexport)intMax(inta,intb);//取較大值函數(shù)extern"C" _declspec(dllexport)intMin(inta,intb);//取較小值函數(shù)


然后在“dllDemo.cpp”文件中實(shí)現(xiàn)三個(gè)接口函數(shù):


#include "dllDemo.h"extern "C" _declspec(dllexport)int Sum(int a, intb)

{

return a+b;

}

extern "C" _declspec(dllexport)int Max(int a, intb)

{

if(a>=b)returna;

elsereturnb;

}

extern "C" _declspec(dllexport)int Min(int a, intb)

{

if(a>=b)returnb;

elsereturna;

}



1.3 生成dll文件

編譯源文件,如果沒(méi)有出現(xiàn)錯(cuò)誤提示,那么,在項(xiàng)目文件根目錄的Debug文件夾內(nèi)會(huì)生成一個(gè)dll文件“dllDemo.dll”。



2 DLL調(diào)用


2.1 用C++調(diào)用顯式鏈接

新建一個(gè)Win32的控制臺(tái)程序進(jìn)行顯式調(diào)用:

1. 新建“dllConsoleEvident”的Win32控制臺(tái)程序項(xiàng)目

2. 新建cpp文件“dllConsoleEvident.cpp”

3. 將在第一節(jié)中,在Debug目錄下編譯生成的“dllDemo.dll”(顯式調(diào)用時(shí)只需要這一個(gè)文件就夠了)文件復(fù)制到“dllConsoleEvident”項(xiàng)目下的Debug文件夾根目錄下

4. 在“dllConsoleEvident.cpp”文件中編寫以下代碼對(duì)dll中的函數(shù)進(jìn)行顯式調(diào)用


////////////////////////////////////////////////////////////////////////////動(dòng)態(tài)加載DLL文件#include

#include

void main(void)

{

typedef

int(*pMax)(int a,int b);//函數(shù)指針typedef int(*pMin)(int a,intb);

pMax Max

=NULL;

pMin Min

=NULL;

HINSTANCE hDLL;

hDLL

=LoadLibrary("MyDll.dll");//加載動(dòng)態(tài)鏈接庫(kù)MyDll.dll文件;Max=(pMax)GetProcAddress(hDLL,"Max");

Min

=(pMin)GetProcAddress(hDLL,"Min");

if (Max)//如果取出函數(shù)成功,則執(zhí)行下面的語(yǔ)句{

int A=Max(5,8);

cout

<<"比較的結(jié)果為"<

}

if(Min)

{

int B=Min(5,8);

cout

<<"比較的結(jié)果為"<

}

FreeLibrary(hDLL);

//卸載MyDll.dll文件;}




2.2 用C++隱式鏈接(Win32控制臺(tái)程序)

新建一個(gè)Win32控制臺(tái)程序演示靜態(tài)調(diào)用

1. 利用向?qū)陆ā癲llConsoleStaticDemo”的空工程

2. 將“dllDemo.dll”和“dllDemo.lib”文件復(fù)制到Debug目錄下,并在項(xiàng)目中包含“dllDemo.lib”文件(或者),否則會(huì)出現(xiàn)dll函數(shù)找不到的連接錯(cuò)誤

3. 新建“dllConsoleStaticDemo.cpp”文件,并寫入如下代碼:


extern "C"_declspec(dllimport) int Sum(int a,intb);

extern "C"_declspec(dllimport) int Max(int a,intb);

extern "C"_declspec(dllimport) int Min(int a,intb);

#include

voidmain()

{

int c=Sum(4,5);

c

=Max(5,6);

c

=Min(5,6);

cout

<<"Hello,dllConsoleTest~!";

}





4.通過(guò)斷點(diǎn),可以看到dll函數(shù)調(diào)用成功

這種方式的靜態(tài)調(diào)用的特點(diǎn)是:在程序一開(kāi)始執(zhí)行的時(shí)候,就將dll文件全部加載到程序中,不會(huì)釋放。


2.3 用C++隱式鏈接(MFC窗口程序)

新建一個(gè)MFC基本對(duì)話框窗口程序進(jìn)行調(diào)用:

1. 利用向?qū)Ы⒁粋€(gè)MFC基本對(duì)話框

2. 將“dllDemo.dll”和”dllDemo.lib”文件復(fù)制到本項(xiàng)目的Debug目錄下,在VC工作空間的文件視圖下面將”dllDemo.lib”添加到項(xiàng)目中

3. 在“dllMfcDemoDlg.h”頭文件中的前面對(duì)來(lái)自外部的dll函數(shù)進(jìn)行聲明


//dllMfcDemoDlg.h : header file

//

#if !defined(AFX_DLLMFCDEMODLG_H__E358B876_D188_48FD_8D83_794309C885A9__INCLUDED_)#define AFX_DLLMFCDEMODLG_H__E358B876_D188_48FD_8D83_794309C885A9__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000/////////////////////////////////////////////////////////////////////////////// CDllMfcDemoDlg dialogextern "C"_declspec(dllimport) int Sum(int a,intb);

extern "C"_declspec(dllimport) int Max(int a,intb);

extern "C"_declspec(dllimport) int Min(int a,intb);

……





4.在窗體界面上,雙擊“確定”按鈕,進(jìn)入到OnOk()的事件響應(yīng)函數(shù)體,編寫調(diào)用代碼:


voidCDllMfcDemoDlg::OnOK()

{

? // TODO: Add extra validation here? int c=Sum(4,5);

c

=Max(5,6);

c

=Min(5,6);

CDialog::OnOK();

}




通過(guò)設(shè)置斷點(diǎn)單步運(yùn)行就可以看到dll文件中的函數(shù)已經(jīng)被成功調(diào)用了。


2.4 用C#跨語(yǔ)言調(diào)用

C#控制臺(tái)程序調(diào)用VC++建立一個(gè)dll:

1. 用Visual Studio建立一個(gè)控制臺(tái)程序

2. 將“dllDemo.dll”文件復(fù)制到項(xiàng)目的Debug目錄下面

3. 在“Program.cs”中編寫如下代碼


usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

using System.Runtime.InteropServices;//引入dll文件中的函數(shù)namespaceConsoleDllDemo

{

classProgram

{

//引入dll文件中的函數(shù)[DllImport("dllDemo.dll")]

private static extern int Sum(int a, intb);

[DllImport(

"dllDemo.dll")]

private static extern int Max(int a, intb);

[DllImport(

"dllDemo.dll")]

private static extern int Min(int a, intb);

static void Main(string[] args)

{

int a = Sum(3, 5);

Console.WriteLine(a);

Console.WriteLine(Max(

5,10));

Console.WriteLine(Min(

12,25));

Console.ReadKey();

//要按鍵才退出。}

}

}




然后斷點(diǎn)單步運(yùn)行,便可以看到調(diào)用函數(shù)的結(jié)果了。

關(guān)于DLL的調(diào)用的更詳細(xì)內(nèi)容可以參考另外一些文章:

http://dev.firnow.com/course/3_program/c++/cppsl/2008127/97781.html

http://dev.yesky.com/283/2640283_2.shtml


3?dll調(diào)試方法

在建立了dll項(xiàng)目后,并寫好相應(yīng)的實(shí)現(xiàn)代碼,點(diǎn)擊“運(yùn)行”,會(huì)彈出現(xiàn)在的對(duì)話框:

然后瀏覽,找到一個(gè)調(diào)用了此dll文件的執(zhí)行文件“*.exe”文件,然后就可以對(duì)dll文件進(jìn)行斷點(diǎn)調(diào)試了。

這個(gè)“*.exe”文件可以是任何平臺(tái)的,C++也可以,C也可以,C#也可以,只要這個(gè)執(zhí)行文件調(diào)用了dll文件中的函數(shù)即可。

如果想更換調(diào)試的“*.exe”文件,可以在“工程-》設(shè)置”對(duì)話框中的“調(diào)試”選項(xiàng)卡進(jìn)行設(shè)置,瀏覽找到用戶需要的“*.exe”文件

說(shuō)明:以VC++環(huán)境中調(diào)用此dll為例,運(yùn)行dllDemo項(xiàng)目,然后會(huì)調(diào)用“*.exe”文件,如果此exe文件含有源文件,而且剛好在源文件的Debug目錄下面,那么,可以同時(shí)在exe文件的源文件中設(shè)置斷點(diǎn),進(jìn)行dll和調(diào)用dll兩個(gè)程序的聯(lián)調(diào)。(好像跨語(yǔ)言調(diào)用的時(shí)候不能進(jìn)行聯(lián)調(diào),筆者只在C++互相調(diào)用的時(shí)候聯(lián)調(diào)成功過(guò),但C#調(diào)用的時(shí)候沒(méi)有聯(lián)調(diào)成功,這個(gè)問(wèn)題有待解決)



4. DLL返回?cái)?shù)據(jù)類型探究

目前寫的DLL函數(shù)反返回值還僅限于整形,還沒(méi)有嘗試其它特殊類型的返回值。更豐富的返回值類型,還要今后慢慢學(xué)習(xí)和研究。等回學(xué)校了再研究吧。請(qǐng)見(jiàn)后續(xù)文章吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容