背景
公司所開發(fā)的程序大體上包含一個exe格式的可執(zhí)行文件作為主入口,同時在項目中包含了自身開發(fā)的、引用的dll(Dynamic Link Library動態(tài)數(shù)據(jù)庫)和lib(靜態(tài)數(shù)據(jù)庫),因此需要開發(fā)人員理解exe是如何調(diào)用DLL和lib的,以及開發(fā)時的文件組織框架(如dll、lib和.h文件的放置位置)。
另外,由于目前的開發(fā)IDE(Integrated Development Environment集成開發(fā)環(huán)境)是Visual Studio 2013,因此需要開發(fā)人員學(xué)習(xí)如何在該IDE中部署環(huán)境。
下文將試圖簡單回答上述三個問題。
問題1:什么是exe、dll和lib
可執(zhí)行文件:exe和dll
用戶可以直接運行的文件都是可執(zhí)行文件,只不過多數(shù)軟件將其主要的功能集合到一個可執(zhí)行文件作為同用戶交互的出入口,往往隨著軟件功能的劃分,一個軟件可以有多個出入口以實現(xiàn)不同的目的,【不知道為什么】通常將exe作為交互的出入口。
將exe所需的功能放在dll中,通過一定的方法導(dǎo)出dll中的功能,供exe在運行時調(diào)用。這樣做可以實現(xiàn)工作模塊化,同時,也可以減小用戶安裝文件的尺寸,因為有部分功能是利用了操作系統(tǒng)自帶的dll。
比如TIM,主程序TIM.exe以及其他主要功能Timwp.exe等。

靜態(tài)數(shù)據(jù)鏈接庫:lib
【只看了百度】lib與dll的區(qū)別
(1)lib是編譯時需要的,dll是運行時需要的。
如果要完成源代碼的編譯,有l(wèi)ib就夠了。
如果要使動態(tài)連接的程序運行起來,有dll就夠了。
在開發(fā)和調(diào)試階段,當(dāng)然最好都有。
(2)一般的動態(tài)庫程序有l(wèi)ib文件和dll文件。lib文件是必須在編譯期就連接到應(yīng)用程序中的,而dll文件是運行期才會被調(diào)用的。如果有dll文件,那么對應(yīng)的lib文件一般是一些索引信息,具體的實現(xiàn)在dll文件中。如果只有l(wèi)ib文件,那么這個lib文件是靜態(tài)編譯出來的,索引和實現(xiàn)都在其中。靜態(tài)編譯的lib文件有好處:給用戶安裝時就不需要再掛動態(tài)庫了。但也有缺點,就是導(dǎo)致應(yīng)用程序比較大,而且失去了動態(tài)庫的靈活性,在版本升級時,同時要發(fā)布新的應(yīng)用程序才行。
(3)在動態(tài)庫的情況下,有兩個文件,一個是引入庫(.LIB)文件,一個是DLL文件,引入庫文件包含被DLL導(dǎo)出的函數(shù)的名稱和位置,DLL包含實際的函數(shù)和數(shù)據(jù),應(yīng)用程序使用LIB文件鏈接到所需要使用的DLL文件,庫中的函數(shù)和數(shù)據(jù)并不復(fù)制到可執(zhí)行文件中,因此在應(yīng)用程序的可執(zhí)行文件中,存放的不是被調(diào)用的函數(shù)代碼,而是DLL中所要調(diào)用的函數(shù)的內(nèi)存地址,這樣當(dāng)一個或多個應(yīng)用程序運行時再把程序代碼和被調(diào)用的函數(shù)代碼鏈接起來,從而節(jié)省了內(nèi)存資源。從上面的說明可以看出,DLL文件必須隨應(yīng)用程序一起發(fā)行,否則應(yīng)用程序?qū)a(chǎn)生錯誤。
問題2:文件組織框架
合理的文件組織框架可以提高開發(fā)效率,開發(fā)者在使用其他模塊時可以采用相對路徑,減少使用絕對路徑時因路徑不同而增加的工作量。
文件組織框架如下圖,VS的solution文件也在此根目錄:

其中,
demo:VS2013的solution(解決方案)的名稱
debug、release:調(diào)試版本和發(fā)布版本
include:存放各模塊的.h文件,其他模塊也在該相對路徑下調(diào)用頭文件。
src:存放編譯時生成的文件包括項目文件、頭文件、dll文件和源代碼等
bin:存放編譯過程文件、exe可執(zhí)行文件和dll,其他模塊也在該相對路徑下調(diào)用dll。
lib:存放lib和exp
“demo_dll”、"hr_demo"等為solution下包含的項目的名稱。
問題3:舉例在VS2013部署exe,然后關(guān)聯(lián)dll
建solution和一個exe的project

命名如下

其application setting如下

console application:建立一個控制臺應(yīng)用,類似cmd命令的界面
MFC:Microsoft Foundation Classes 做UI用的,公司依然采用。
SDL:不用勾選【具體原因未知】
生成結(jié)果如下

demo1_exe:solution "demo1"的一個project。
demo1.sln:solution文件
demo1.sdf:【不知道】
ipch:編譯過程文件或輔助文件【不確認(rèn)】
注意,此時可以看到project "demo1_exe"下包含了待編譯的頭文件、源代碼和項目文件(.vcxproj)等。
重點:手動將一個建立的項目的文件夾整體放入src(手工創(chuàng)建)文件夾。

在該solution下建立一個DLL文件


注意建立后續(xù)項目時的路徑是在src文件夾內(nèi)


生成的文件及原始路徑如下

--------------------------------------------------------華麗的分隔線-----------------------------------------------------------------
此時我們要做的時把這些待編譯的文件以及編譯后的文件放到問題2指定的文件夾中,以便能識別其他工程的頭文件及l(fā)ib庫,并進(jìn)行導(dǎo)入、使用
project設(shè)置輸出路徑:dll文件和exe文件到bin
首先,我們要看一下編譯之后會輸出什么文件。這里在Debug模式下編譯。

結(jié)果就是,在同項目文件夾平級的位置生成了一個Debug文件夾,里面包含了dll的的輸出和console application的輸出文件(如exe)。

通過右鍵項目,找到properties,可以看到原因是默認(rèn)的輸出路徑是“$(SolutionDir)$(Configuration)\”,即solution的路徑下根據(jù)configuration是Debug還是Release,來生成不同的文件夾。

而根據(jù)問題2中的描述,我們需要把dll和exe文件放入"debug\bin"或者"release\bin"中,因此我們需要修改這個宏命令。
同時,為區(qū)分debug和release版本,在debug版本的TargetName中加上"_d"的后綴。

注意,每個項目都需要為debug和release和屬性(properties)修改一次。
project設(shè)置輸出路徑(僅DLL項目):lib文件到lib

【至于為什么叫“import Library”,我也不懂了】
OutDir:項目輸出路徑,即

..\:為當(dāng)前目錄的上一級目錄
生成結(jié)果如下

project設(shè)置輸出路徑(僅DLL項目):h文件到include
這部操作是通過在編譯器的預(yù)編譯事件中加入宏命令,更新目標(biāo)文件夾下面的頭文件。

del /f /s /q $(SolutionDir)\include\$(ProjectName)\
xcopy /s /c /i /r /y *.h $(SolutionDir)\include\$(ProjectName)\
注意,可以在宏命令幫助中查看各變量的意義。

注意,由于properties是屬于各項目的,因此當(dāng)前路徑指的是項目路徑。
--------------------------------------------------------華麗的分隔線-----------------------------------------------------------------
由于一個模塊可以使用其他模塊的接口,需要設(shè)置相應(yīng)的輸入路徑
project設(shè)置輸入路徑:從include中讀取頭文件

project設(shè)置輸入路徑:從lib中讀取鏈接器的數(shù)據(jù)

project設(shè)置:其他
- 刪除def文件和設(shè)置:理由在下文exe和dll關(guān)聯(lián)機(jī)制中介紹。
image.png
image.png
2.將字符集改為multi-byte:由于公司歷史原因,沒有使用Unicode
image.png
注意,需要安裝multi-byte字符集文件《vc_mbcsmfc.exe》。
--------------------------------------------------------華麗的分隔線-----------------------------------------------------------------
exe和dll關(guān)聯(lián)機(jī)制
【其實不是很懂】
為方便導(dǎo)出dll的接口,同時便于其他模塊導(dǎo)入,將模塊導(dǎo)入導(dǎo)出的指令寫成代碼形式,統(tǒng)一文件名稱為marco.h,參考代碼如下:
#pragma once //網(wǎng)上查到:為避免被同一個文件include多次,可以用#ifndef的相關(guān)命令替換
#ifdef DEMO_DLL //如果定義了一個標(biāo)識 DEMO_DLL,即在dll文件的“預(yù)處理定義”中加上該標(biāo)識的情況下。
# define DEMO_API __declspec(dllexport) // MSDN:extended attribute syntax,定義標(biāo)識DEMO_API為dll輸出
#else
# define DEMO_API __declspec(dllimport) //否則為dll輸入
# ifdef _DEBUG //debug版
# pragma comment(lib, "demo_dll_d.lib") //用于指定導(dǎo)入模塊時要鏈接的lib文件(可通過項目屬性實現(xiàn),此處為便于維護(hù)和其他模塊使用,改用代碼方式實現(xiàn))
# pragma message("auto linking to demo_dll_d.lib")
# else //其他
# pragma comment(lib, "demo_dll.lib")
# pragma message("auto linking to demo_dll.lib")
# endif
#endif
在預(yù)處理定義中增加該標(biāo)識,以便在編譯時明確該項目是要導(dǎo)出接口。

另外,對于macro.h文件,一般每個頭文件或cpp源文件都需要包含,容易出錯,可在模塊預(yù)處理文件'stdafx.h'中統(tǒng)一添加。

然后在需要調(diào)用該模塊的源代碼處include該macro.h。

以避免各文件都要單獨包含重復(fù)代碼。
測試連通
-
先在dll項目中建立一個頭文件,聲明一個函數(shù)或者類
image.png -
在dll項目中建立一個同名的cpp,實現(xiàn)該函數(shù)或者類
image.png -
然后在exe的源代碼中創(chuàng)建一個cpp文件,include了dll中的頭文件和宏文件,然后運行sum函數(shù)。
image.png -
結(jié)果如下
image.png






