http://www.cnblogs.com/laogao/archive/2012/12/07/2806528.html?,其中在GetProcAddress第二個參數的填寫煞費苦心,我們需要比較麻煩地使用vs自帶的dumpbin查看dll的具體函數,即使后來可以使用MAKEINTRESOURCE直接填寫函數序號來不直接填寫函數名,依然你需要在dumpbin中查找函數的序號,比較費力。
???????? 其實我們有更好的方法來解決這個問題,其中一個比較好的一個方法是改用extern "C"來修飾函數,使之按照c的風格來編譯函數。我們知道c不支持函數重載,因此我們定義的時候用的什么名字,在顯式調用dll的時候也是用的這個名字,完全不用改變,很簡單。
??????? 在進行下面的介紹之前,先可以閱讀這個文章《extern "C"的簡單解析》
??????? 下面我們介紹兩個例子。
例1.?在純C++環境下使用c語言方式編譯dll,然后調用
??????CreateDLL.h
<span style="color:#000000;">// 下列 ifdef 塊是創建使從 DLL 導出更簡單的
// 宏的標準方法。此 DLL 中的所有文件都是用命令行上定義的 CREATEDLL_EXPORTS
// 符號編譯的。在使用此 DLL 的
// 任何其他項目上不應定義此符號。這樣,源文件中包含此文件的任何其他項目都會將
// CREATEDLL_API 函數視為是從 DLL 導入的,而此 DLL 則將用此宏定義的
// 符號視為是被導出的。
#ifdef CREATEDLL_EXPORTS
#define CREATEDLL_API __declspec(dllexport)
#else
#define CREATEDLL_API __declspec(dllimport)
#endif#ifdef __cplusplus
extern "C"
{
#endifCREATEDLL_API void printMax(int&, int&);
#ifdef __cplusplus
}
#endif // __cplusplus
</span>
// CreateDLL.cpp : 定義 DLL 應用程序的導出函數。
//#include "stdafx.h"
#include "CreateDLL.h"
#include <iostream>CREATEDLL_API void printMax(int& a, int& b)
{std::cout << "Among (" << a << "," << b << "), the Max Number is " << (a > b ? a : b) << "\n";
}
然后點擊“生成”,即可生成dll和lib。接下來我們就可以直接使用了。注意:生成dll的時候,需要先設置dll的項目為啟動項。當使用dll的時候,需設置使用dll的項目為啟動項。
先看顯式調用:
#include <Windows.h>
#include <iostream>typedef void(*FUNA)(int&, int&);int main()
{const char* dllName = "CreateDLL.dll";int x(100), y(100);HMODULE hDLL = LoadLibrary(dllName);if (hDLL!=NULL){FUNA fp1 = FUNA(GetProcAddress(hDLL, "printMax"));if (fp1!=NULL){std::cout << "Input 2 Numbers:";std::cin >> x >> y;fp1(x, y);}else{std::cout << "connot find the function "<<"printMax" << std::endl;}FreeLibrary(hDLL);}else{std::cout << "cannot load dll"<<dllName << std::endl;}system("pause");return 0;}
注意觀察,我們的GetProcAddress的第二個參數直接使用原來的函數名。另外需要注意的是在使用dll的項目中,我們沒有包含dll的頭文件,但是仍然可以使用。但是有時候也過不去,此時你需要包含dll的.h的路徑。
再看隱式調用:
#include "CreateDLL.h"
#include <iostream>
using namespace std;#pragma comment(lib,"CreateDLL.lib")int main()
{int a,b;cout << "input 2 num:";cin >> a >> b;printMax(a,b);system("pause");return 0;
}
將.h,.lib,.dll一塊兒放在項目目錄下,然后在程序中使用#pragma comment(lib,"CreateDLL.lib"),即可成功鏈接dll。與顯式調用,隱式調用比較簡單。
另外在上一篇《c++顯式加載dll并使用DLL的類》 ,我們也使用了extern "C"的風格
extern "C" INTERFACE_API Interface* Export(void);
例2.?在純C環境下使用c語言方式編譯dll,然后在C++中調用
????CreateDLL.h
//c.h
#ifndef _C_H_
#define _C_H_ //防止被重復包含#ifdef CREATEDLL_EXPORTS
#define CREATEDLL_API __declspec(dllexport)
#else
#define CREATEDLL_API __declspec(dllimport)
#endif#ifdef __cplusplus
extern "C" {
#endifextern CREATEDLL_API int add(int x, int y);#ifdef __cplusplus
}
#endif#endif
CreateDLL.c
#include "CreateDLL.h"
int add(int x, int y)
{return x + y;
}
然后我們就可以生成dll了。注意我們這里都是c語言。
然后我們在c++中調用dll。
顯式調用:
#include <Windows.h>
#include <iostream>
#include "CreateDLL.h"typedef int(*Func)(int, int);#pragma comment(lib,"CreateDLL.lib")int main()
{HMODULE Hdll = LoadLibrary("CreateDLL.dll");if (Hdll!=nullptr){Func f = Func(GetProcAddress(Hdll, "add"));if (f!=nullptr){std::cout << "input 2 num:";int a, b;std::cin >> a >> b;std::cout << "result is " << add(a, b);}else{std::cout << "connot find the function " << "add" << std::endl;}FreeLibrary(Hdll);}else{std::cout << "cannot load dll" << "CreateDLL.dll" << std::endl;}system("pause");return 0;
}
注意要將CreateDLL.h和CreateDLL.lib放在項目目錄下。
隱式調用:
#include "CreateDLL.h"
#include <iostream>
using namespace std;#pragma comment(lib,"CreateDLL.lib")int main()
{int a,b;cout << "input 2 num:";cin >> a >> b;cout<<"result is "<<add(a,b);system("pause");return 0;
}
解讀:
文件為*.c,__cplusplus沒有被定義,extern "C" {}這時沒有生效,對于C語言只是extern int add(int, int);而編譯c++源文件,__cplusplus被定義,對于C++他看到的是extern "C" {extern int add(int, int);},編譯器就會知道add(1, 0)調用的是C連接。?
很多DLL的生成文件(XXX.c)中常出現extern "C" ,windows采用C語言編譯創建dll,C程序可以正確調用DLL,而當用戶使用C++調用DLL時,extern "C" {}就起作用了。
附錄:
1.例1
2.例2