日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

动态链接库编写与使用(VC6)

發布時間:2025/3/21 c/c++ 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态链接库编写与使用(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獲取函數指針。
代碼如下:

#include "stdafx.h"int main(int argc, char* argv[]) {HINSTANCE hModule = LoadLibrary("TestDll.dll");int (__cdecl *Plus)(int, int, int);Plus = (int (__cdecl *)(int, int, int)) GetProcAddress(hModule, "Plus");printf("%d\n", Plus(1,2,3));return 0; }

六、發布

不管是隱式鏈接還是顯式鏈接,發布程序時都要將 dll 和 exe 一同發布,lib 只在編譯鏈接階段用到。

如果沒有dll,會報錯!

七、__stdcall

如果使用 __stdcall,則要注意導入函數時,函數名和dll工程的函數名是不一樣的,這個可以用 dependency walker 確認。
現在我將dll函數的調用約定修改為 __stdcall

extern "C" _declspec(dllexport) __stdcall int Plus(int x, int y, int z);

隱式鏈接
由于隱式鏈接是通過 lib 來獲取函數位置的,所以可以使用和DLL中定義的相同的函數名。

// Helloworld.cpp : Defines the entry point for the console application. //#include "stdafx.h"#pragma comment(lib, "TestDll.lib") extern "C" __declspec(dllimport) int __stdcall Plus(int, int, int);int main(int argc, char* argv[]) {printf("%d\n", Plus(1,2,3));return 0; }

顯式鏈接
注意修改了調用約定和函數名

// Helloworld.cpp : Defines the entry point for the console application. //#include "stdafx.h"int main(int argc, char* argv[]) {HINSTANCE hModule = LoadLibrary("TestDll.dll");int (__stdcall *Plus)(int, int, int);Plus = (int (__stdcall *)(int, int, int)) GetProcAddress(hModule, "_Plus@12");printf("%d\n", Plus(1,2,3));return 0; }

總結

以上是生活随笔為你收集整理的动态链接库编写与使用(VC6)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。