本文轉(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ù)文章吧。