关于dll的隐式调用及类、函数的导出

阅读Qt的源代码,发现其中有许多宏,最后定义为__declspec(dllexport),由于以前没有写过库,对此很陌生,于是研究了下。

        原来这是用于导入、导出函数用的,网上搜索了个例子,自己再总结下:

// File: SimpleDLLClass.h
#ifdef SIMPLEDLL_EXPORT
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif

class DLL_EXPORT SimpleDLLClass
{
public:
    SimpleDLLClass();
    virtual ~SimpleDLLClass();

    int getValue() { return m_nValue;}
private:
    int m_nValue;
};

// File: SimpleDLLClass.cpp
#define SIMPLEDLL_EXPORT
#include "SimpleDLLClass.h"

SimpleDLLClass::SimpleDLLClass()
{
   m_nValue=5;
}


SimpleDLLClass::~SimpleDLLClass()
{
}

以上便是写了一个类并将其进行了导出,其中比较需要注意的便是头文件中的#ifdef,通过这条预处理命令(库实现文件中定义了SIMPLEDLL_EXPORT),实现了库中类的导出以及使用时类的引入。

类导出来,我们还需要进行一下测试,于是写了个简单的测试函数:

#include "SimpleDLLClass.h"
#include <stdio.h>
#pragma comment(lib,"SimpleDLLClass.lib")  //导入库文件,也可以在编译参数中加
int main()
{
    SimpleDLLClass a;
    printf("a: %d\n", a.getValue());
    return 0;
}

为了测试方便,我也写了一个Makefile:

main: dll
#cl main.cpp /link SimpleDLLClass.lib /OUT:1.exe 如果不在头文件中导入库,则必须这样写
	cl main.cpp /link /OUT:1.exe /MAP:xx.map  #同时生成了下map文件,此处无用
	1.exe
dll:SimpleDLLClass.dll
SimpleDLLClass.dll:
	cl /LD SimpleDLLClass.cpp
clean:
	del *.dll
	del *.exp
	del *.lib
	del *.obj
	del *.exe
.PHONY: clean

由于在windows中测试,需要安装nmake或者安装mingw才能使用Makefile,我安装的是mingw。编写完毕后运行make即可运行我们生产的1.exe。

运行完make后,在同一目录中还生成了许多其他文件:main.obj、SimpleDLLClass.obj、SimpleDLLClass.dll、SimpleDLLClass.exp、SimpleDLLClass.lib。

其中.obj、.dll均了解,.exp和.lib不知其意,后来baidu后,知道:

.exp文件是指导出库文件的文件,简称导出库文件,它包含了导出函数和数据项的信息。当LIB创建一个导入库,同时它也创建一个导出库文件。如果你的程序链接到另一个程序,并且你的程序需要同时导出和导入到另一个程序中,这个时候就要使用到exp文件(LINK工具将使用EXP文件来创建动态链接库),一般我们不需要关心。

.lib文件,可以代表静态库,也可以代表动态库。若为静态库,则直接进行链接;若为动态库,则.lib将指导可执行程序如何与dll进行链接。

此外,导出库不光可以通过__declspec(dllexport)进行导出,也可以通过.def文件进行导出,先写个导出单个函数:

// File :SimpleDLLClass.h
#ifdef SIMPLEDLL_EXPORT
#define DLL_EXPORT 
#else
#define DLL_EXPORT __declspec(dllimport)
#endif

int DLL_EXPORT getValue();

// File: SimpleDLLClass.cpp
#define SIMPLEDLL_EXPORT
#include "SimpleDLLClass.h"

int getValue() { return 3;}

// File: main.cpp
#include "SimpleDLLClass.h"
#include <stdio.h>
#pragma comment(lib,"SimpleDLLClass.lib") 

int main()
{
	printf("a: %d\n", getValue());
	return 0;
}


Makefile:

main: dll
#cl main.cpp /link SimpleDLLClass.lib /OUT:1.exe
cl main.cpp /link /OUT:1.exe
1.exe
dll:SimpleDLLClass.dll
SimpleDLLClass.dll:
cl /LD SimpleDLLClass.cpp /link /DEF:SimpleDLLClass.def 
clean:
del *.dll
del *.exp
del *.lib
del *.obj
del *.exe
.PHONY: clean


SimpleDLLClass.def:

LIBRARY SimpleDLLClass
DESCRIPTION "our simple DLL"
EXPORTS getValue @1 

        def文件写得比较简单,只是将getValue导出到第一个位置上。比较奇怪的是,我直接写了导出函数名,并没有写出C++经过处理后的函数名,程序竟然能够正常运行,且通过nm查看生成的SimpleDLLClass.obj,看到符号名为00000000 T ?getValue@@YAHXZ,这还是让我比较奇怪的。

        以下再写一个导出类,和之前用__declspec(dllexport)导出一样,仅仅修改了下SimpleDLLClass.h

// File: SimpleDLLClass.h
#ifdef SIMPLEDLL_EXPORT
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif

class  SimpleDLLClass //去掉了DLL_EXPORT
{
public:
    SimpleDLLClass();
    virtual ~SimpleDLLClass();

    int getValue();   //将此函数改为非内联
private:
    int m_nValue;
};

        注意:一定得把需要把导出类中要使用的函数改为非内联,否则链接无法通过(原因:由于函数为内联,导致编译器并未生成符号表,最后将导致链接失败,可能有编译参数可以进行设置,但本人一直未找到,希望知道的朋友能告知我)。

至于def文件内容如下:

SimpleDLLClass.def:

 LIBRARY SimpleDLLClass

DESCRIPTION "our simple DLL"
EXPORTS 
??0SimpleDLLClass@@QAE@XZ @1
??1SimpleDLLClass@@UAE@XZ  @2
?getValue@SimpleDLLClass@@QAEHXZ @3

  也许大家对其中以?开头的文字有些疑惑,起始这是C++ 编译器的函数名修饰,可以通过如下方法获得:

        cl /c SimpleDLLClass.cpp

        nm SimpleDLLClass.obj

        但是看到有好多含有SimpleDLLClass的,其实,只要将以上命令中SimpleDLLClass.cpp改为main.cpp,就能找到实际使用的是哪些导出函数,将这些函数导出就行了。

           以上说的都是dll的隐式使用,其实还可以显示使用:

           生成dll的方法一样,只是在window中使用:LoadLibrary()、GetProcAdress()、FreeLibrary()进行使用;在qt中可以使用QLibrary:load()、resolve(const char *)、unload(),比较简单,具体不详解了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值