動態鏈接庫的編寫及使用(c++)

一、編寫動態鏈接庫
mydll.cpp:
//dll的入口點
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}
int myadd(int a,int b)
{
    return a+b;
}
int __stdcall mysub(int a,int b)//這裏只是爲了說明使用__stdcall的情況
{
	return a-b;
}

重要的是怎麼導出動態鏈接庫中的函數,首先要知道c/c++的默認的函數調用約定爲__cdecl,Win32 API的調用約定是__stdcall(關於__函數的調用約定請自行百度)
1.若函數使用了Win32 API,則函數應使用__stdcall修飾
2.__stdcall會改變函數符號
3.因爲c++在導出函數時會改變函數符號,應當用 extern "C"修飾
4.extern "C"和__stdcall不能同時修飾函數(有時候還是會改變函數符號)
5.用.def文件導出函數不會修改函數符號

總結:推薦使用.def導出函數(編譯dll的時候就不需要後面兩個頭文件了),再手動編寫兩個mydlllib.h和mydll.h分別作爲隱式鏈接和顯示鏈接提供給使用者
mydlllib.h://隱式調用時需要包含的頭文件
//這裏僅僅是隱式調用dll時的頭文件,如果要顯示調用,應當再編寫一個頭文件供外部使用
#pragma once
#pragma comment(lib,"mydll.lib")//這裏需要將mydll.lib放到exe文件相同目錄
extern "C" __declspec(dllimport) int myadd(int,int); //聲明一個可以導出的方法
extern "C" __declspec(dllimport) int __stdcall mysub(int,int); //tt

mydll.h://顯式調用時需要包含的頭文件
#pragma once
typedef int (* dll_myadd) (int,int);//這裏加dll_只是爲了在後面定義函數的時候可以取myadd這個變量名
typedef int (__stdcall* dll_mysub) (int,int);


拓展:使用__declspec(dllexport)導出函數的方法
在mydll.cpp添加
#define DLL_API extern "C" __declspec(dllexport)

//mydlllib.h寫成:
#pragma once
#ifdef DLL_API
#else
	#pragma comment(lib,"mydll.lib")//這裏需要將mydll.lib放到exe文件相同目錄
	#define DLL_API extern "C" __declspec(dllimport)
#endif


DLL_API int myadd(int,int); //聲明一個可以導出的方法
DLL_API int __stdcall mysub(int,int); //tt

mydll.h不變

二、使用動態鏈接庫
隱式調用:
1.包含mydlllib.h
2.將mydll.lib和mydll.dll複製到exe相同目錄


顯示調用:
1.包含mydll.h//不包含的話要自己typedef,不嫌麻煩的話也可以
2.將mydll.dll複製到exe相同目錄
3.調用時:
HINSTANCE hinstDLL;//獲取dll
dll_myadd myadd;//定義函數名
dll_mysub mysub;//定義函數名
hinstDLL = LoadLibrary("sampleDLL.dll");
if (hinstDLL != NULL)
{
    myadd = (dll_myadd) GetProcAddress(hinstDLL, "myadd");//獲取函數地址
	mysub = (dll_mysub) GetProcAddress(hinstDLL, "mysub");//獲取函數地址
    if (myadd != NULL)
        myadd(1,2);
	if (mysub != NULL)
        mysub(1,2);	
	FreeLibrary(hinstDLL);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章