首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > VSTS >

在VS2010平台下创建并使用dll

2012-09-21 
在VS2010平台上创建并使用dll代码的复用:1.源码级别的复用:优点可以阅读和修改相关的内容,更加灵活。缺点可

在VS2010平台上创建并使用dll

代码的复用:

1.源码级别的复用:优点可以阅读和修改相关的内容,更加灵活。缺点可控性不好,容易增加代码级别的耦合,内存开支较大,升级和维护比较麻烦。

2.二进制级别的复用:优点就是上面的缺点,缺点就是上面的优点。lib和dll都是二进制级别的重用。

?

创建dll工程:

通过Start Page或者File菜单栏,新建一个Project,将会弹出新建项目对话框。选择Win32 Project向导,项目名称为CreateDLL,解决方案名为DLLTEST(注意Create directories for solution是勾选上的),点击OK,接着点击Next,到Application Settings,选择应用程序类型为dll,并勾选“Export Symbols”(选择后工程会生成一些可用代码),点击Finish。完成这一步之后,VS界面上左边的Solution Explorer中将会看到向导自动生成的文件列表,如图1所示。

在VS2010平台下创建并使用dll

????????? 图1 向导自动生成的文件列表

1.CreateDLL.h:

#ifdef WIN32DLL_EXPORTS#define WIN32DLL_API __declspec(dllexport)#else#define WIN32DLL_API __declspec(dllimport)#endif// This class is exported from the win32dll.dllclass WIN32DLL_API Cwin32dll {public:Cwin32dll(void);// TODO: add your methods here.};extern WIN32DLL_API int nwin32dll;WIN32DLL_API int fnwin32dll(void);

?

2.CreateDLL.cpp:

// This is an example of an exported variableWIN32DLL_API int nwin32dll=0;// This is an example of an exported function.WIN32DLL_API int fnwin32dll(void){return 42;}
?

接下来,选择菜单Build->Build CreateDLL,Output窗口提示CreateDLL.dll文件生成成功,如图2所示。

在VS2010平台下创建并使用dll

?

?

使用dll:

本例采用“显式调用”的方式使用CreateDLL.dll。显式调用方式相比于”隐式调用“有好有坏。显式调用只需要一个.dll文件就可以了,灵活性更好,更新模块方便;相对的,程序员需要做的事情更多,使用方法更为复杂。

右键单击Solution Explorer中的Solution 'DLLTEST',在弹出的菜单中选择Add->New Project,选择Win32 Console Application,输入项目名为UseDLL,点击OK,接着点击Next,在Application Settings界面勾选EmptyProject并点击Finish。右键单击项目UseDLL,给它添加源文件UseDLL.cpp。这样操作之后,Solution Explorer的信息如图3所示。

在VS2010平台下创建并使用dll

图3 向Solution'DLLTEST'添加项目UseDLL

编写UseDLL.cpp的代码为:

??????????????? 图4 UseDLL的运行结果

这并不是期望中的结果。实际上,正如第二节提到的那样,造成这种错误的原因正是导出函数的修饰名称。虽然在CreateDLL.cpp中两个printMax函数有相同的名称,但在dll二进制文件中,经过编译器的“加工”,它们实际上各自有不同的名称了。这也是函数重载机制得以实现的一个技术支持。

使用VS2010附带工具dumpbin,查看CreateDLL.dll的导出函数名,结果如图5所示。

在VS2010平台下创建并使用dll

[点击查看原图]

?

????????????????????????????????????????????????????????????????? 图5 查看CreateDLL.dll的导出函数名

观察图5可以发现,CreateDLL.dll导出函数名为?printMax@@YAXAAH00@Z和?printMax@@YAXAAH0@Z。它们分别对应着3个整数的printMax和两个整数的printMax。因此,Use.DLL中funName应当相应修改为:

?????????????????????????? 图6 UseDLL正常运行

?

dll导出函数名称规范化

创建、使用dll并不复杂,走过前三节,相信读者肯定有这样的体会。然而,一个问题仍然值得思考:导出函数的修饰名称太“奇怪”,为dll的使用带来了不便,能不能让导出函数的修饰名称规范一些?

答案是肯定的,而且方法至少有两种:一是运用extern "C"修饰printMax;二是运用模块定义文件.def。后者的效果更好,所以本节将使用.def来规范化导出函数的修饰名称。

CreateDLL.dll导出的两个函数功能很简单,根据功能描述,理想的函数名称是pMaxA2和pMaxA3。在CreateDLL项目中添加CreateDLL.def文件:

[点击查看原图]

?

???????????????????????????????????????????????????????????? 图7 规范化的函数名,奇怪的修饰名称还存在

出现了期望的结果,但仍然有小缺憾:奇怪的修饰名称仍然存在。能否去掉这些不太规范的修饰名称呢?当然是可以的。只需要将CreateDLL.h中#define CREATEDLL_API __declspec(dllexport)?修改为#define CREATEDLL_API即可。修改之后重新编译生成CreateDLL.dll,使用dumpbin查看导出函数名称,结果如图8所示。

在VS2010平台下创建并使用dll

[点击查看原图]

?

???????????????????????????????????????????????????????????????图8 规范化的函数名,去除了奇怪的修饰名称????

回到UseDLL.cpp,修改funName:

"pMaxA3";??

重新编译运行UseDLL,结果正确,与图6类似。


dll的不足:

动态链接库虽然一定程度上实现了“黑盒复用”,但仍然存在着诸多不足,笔者能够想到的有下面几点。

  1. dll节省了编译期的时间,但相应延长了运行期的时间,因为在使用dll的导出函数时,不但要加载dll,而且程序将会在模块间跳转,降低了cache的命中率。
  2. 若采用隐式调用,仍然需要.h、.lib、.dll文件(“三件套”),并不能有效支持模块的更新。
  3. 显式调用虽然很好地支持模块的更新,但却不能导出类和变量。
  4. dll不支持Template。

二进制级别的代码复用相比源码级别的复用已经有了很大的进步,但在二进制级别的代码复用中,dll显得太古老。想真正完美实现跨平台、跨语言的黑盒复用,采用COM才是正确的选择。

?

?

?

?

热点排行