动态链接库编写与使用(VC6)
靜態鏈接庫編寫與使用
與靜態鏈接相比,動態鏈接更靈活,修改動態鏈接庫的代碼不需要重新編譯exe程序,如果說靜態鏈接庫是編譯階段的模塊化,那么動態鏈接就是真正的運行時模塊化。
下面將演示使用VC6編寫動態鏈接庫(dll),然后在另一個程序中鏈接使用。
一、創建動態鏈接庫工程
選擇WIN32動態鏈接庫
simple DLL project
二、編寫代碼
創建頭文件和CPP文件,分別用于聲明和定義函數
MyDll.h
#if !defined(AFX_MYDLL_H__EF374ACC_12D5_44C8_A50E_2B61E8E3FADD__INCLUDED_) #define AFX_MYDLL_H__EF374ACC_12D5_44C8_A50E_2B61E8E3FADD__INCLUDED_#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000extern "C" _declspec(dllexport) __cdecl int Plus(int x, int y);#endif // !defined(AFX_MYDLL_H__EF374ACC_12D5_44C8_A50E_2B61E8E3FADD__INCLUDED_)其中,extern “C” 表示以C語言方式導出,這樣就不會修改函數名,如果不加說明,則會以C++方式導出,C++為了實現函數重載,會把修改函數名。
_declspec(dllexport) 表示這是導出函數,__cdecl C語言默認的調用約定,表示由調用者負責平衡參數堆棧,相對的,windows api 的調用約定一般是 __stdcall,表示由函數自己負責平衡堆棧。在這里,我將演示兩種調用約定的區別,先用默認的 __cdecl.
MyDll.cpp
int __cdecl Plus(int x, int y) {return x + y; }編譯后生成若干文件,我們把 TestDll.dll 和 TestDll.lib 拿出來備用。
這里說明一下 __cdecl 和 __stdcall 對導出函數名的影響,我們現在使用的是默認的 __cdecl,則函數名和源文件中一樣。使用dependency walker 工具打開dll,可以查看內部的函數名:
可以看到,函數名是Plus,和源文件中定義的一樣。現在我把調用約定修改成 __stdcall,觀察變化。
extern "C" _declspec(dllexport) __stdcall int Plus(int x, int y);生成DLL,用dependency walker打開,發現函數名變成了 _Plus@8,其中8表示參數的大小,兩個int剛好是8.
如果增加一個int參數,變成3個參數求和:
extern "C" _declspec(dllexport) __stdcall int Plus(int x, int y, int z);生成的函數名被修改成 _Plus@12 是顯而易見的。
弄清楚兩種調用約定的區別后,下一步就要研究怎么在其他工程中鏈接DLL了。注意,現在我的DLL使用的調用約定是默認的 __cdecl。如果要使用__stdcall,則要注意聲明函數指針類型時也要指定調用約定為__stdcall,以及函數名要相應地修改成_Plus@12(舉例)
下面將演示兩種鏈接方式。
三、將 lib 和 dll 復制到工程目錄
隱式鏈接需要用到 lib 和 dll,而顯式鏈接則只需要 dll。
四、隱式鏈接
代碼如下:
#include "stdafx.h"#pragma comment(lib, "TestDll.lib") extern "C" __declspec(dllimport) __cdecl int Plus(int x, int y, int z);int main(int argc, char* argv[]) {printf("%d\n", Plus(1,2,3));return 0; }lib的作用是告訴編譯器函數在哪,真正的代碼在dll里面。注意函數聲明和之前編寫dll的時候聲明的是一樣的。
五、顯式鏈接
調用LoadLibrary函數獲取dll模塊,再調用GetProcAddress獲取函數指針。
代碼如下:
六、發布
不管是隱式鏈接還是顯式鏈接,發布程序時都要將 dll 和 exe 一同發布,lib 只在編譯鏈接階段用到。
如果沒有dll,會報錯!
七、__stdcall
如果使用 __stdcall,則要注意導入函數時,函數名和dll工程的函數名是不一樣的,這個可以用 dependency walker 確認。
現在我將dll函數的調用約定修改為 __stdcall
隱式鏈接
由于隱式鏈接是通過 lib 來獲取函數位置的,所以可以使用和DLL中定義的相同的函數名。
顯式鏈接
注意修改了調用約定和函數名
總結
以上是生活随笔為你收集整理的动态链接库编写与使用(VC6)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 静态链接库编写与使用(VC6)
- 下一篇: 使用def导出动态链接库(VC6)