之前在写VC程序的时候习惯了将所有的代码都使用静态编译来生成程序,虽然方便,但是考虑到以后难免会由于某些原因而需要使用动态编译来链接程序。所以,经过一番摸索,终于学会制作自己的Dll,以下我就举两个例子来分享下,以方便自己以后查看用到,同时也方便其他同仁遇到同样的问题时能快速解决问题。
以下例子本人在 VC2010 中成功测试通过!
例子一:
1、 新建项目 “Win32 Dynamic-Link Library” 项目名称“MyDll”,确定后选择“一个空的DLL工程”点击“完成”。
2、添加头文件 MyDll.h ,代码如下
#include <iostream> using namespace std; #ifndef POINT_H #define POINT_H extern "C" _declspec(dllexport) int add(int a, int b); class _declspec(dllexport) point { public: point(); void show(); private: int a; int b; }; #endif
3、添加MyDll.cpp文件,代码如下:
#include "class_a.h" int add(int a, int b) { return a + b; } point::point():a(1), b(2) {}; void point::show() { cout<<"a: "<<a<<endl <<"b: "<<b<<endl; }
4、编译后会在工程的 “Debug” 文件夹下面生成 “MyDll.dll” 和 “MyDll.lib”两个文件。
5、新建另一个 空的控制台工程,如“testDll” ,然后把上一个工程生成的 “MyDll.dll” 和 “MyDll.lib” 两个文件复制到 新生成的工程目录.......\testDll 下面。
6、添加一个源文件 “testDll.cpp”, 然后添加如下代码:
#include <iostream> #include "class_a.h" using namespace std; #pragma comment(lib,"MyDll.lib") //加载自己生成的库“MyDll.lib” int main() { cout<<add(1, 2)<<endl; point pt; pt.show(); return 0; }
编译链接后执行程序,控制台成功输出如下:
以下说明程序中几个应该注意的地方:
1、该 Dll '例子 导出了 一个普通的函数 和 一个 C++类,其中到处的普通的函数的声明如下
extern "C" _declspec(dllexport) int add(int a, int b);
前面多了 extern "C" 声明,该声明的作用是这样的,它可以在动态链接库文件编译时,到处的函数的名称不要发生改变,从而可以解决不同的编译器在进行 C++ 和 C 语言之间相互调用时函数命名的问题,但它不适用于一个类的成员函数,所以在声明类是,我没有加上这个声明。
2、读者可以试一下把程序中 _declspec(dllexport) 替换成_declspec(dllimport),然后再重新生成 *.Dll 和 *.lib ,同时要记得把新生成的这两个文件覆盖之前另一个工程的 *.Dll
和 *.lib ,然后在重新编译程序,可以发现,程序也能正常执行。
出现这种情况是否就意味着这两个声明可以互换使用呢?答案当然不是,只是有些情况下确实可以互换使用,但不是所有的情况都如此。
以下是我在网上搜索到的对这两个声明的解释:
__declspec(dllexport)
声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。
__declspec(dllimport)
声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中 不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于
DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。
大家参考一下就行,若真想知道为什么,我还是建议大家有时间的话上MSDN上面了解比较好!