- 浏览: 297141 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
M大米饭:
19774279 写道xj1990129 写道PackageF ...
Eclipse插件开发之获得当前项目 -
zhongmin2012:
AST抽象的java语法树 -
wd3389:
好可惜,你写的文章很有帮助,谢谢!
关于博客更新 -
zxjlwt:
http://surenpi.com/2015/07/13/e ...
eclipse扩展点清单 -
zxjlwt:
学习了。http://surenpi.com
Console 控制台扩展(一)
代码的复用:
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所示。
图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.dll class 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 variable WIN32DLL_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所示。
使用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所示。
图3 向Solution'DLLTEST'添加项目UseDLL
编写UseDLL.cpp的代码为:
- /*--UseDLL.cpp
- *Author:wintherlost
- *Use CreateDLL.dll explicitly
- */
- #include<Windows.h>
- #include<iostream>
- typedef void(*FUNA)(int&,int&);
- typedef void(*FUNB)(int&,int&,int&);
- int main()
- {
- const char* dllName="CreateDLL.dll";
- const char* funName1="printMax";
- const char* funName2="printMax";
- int x(100),y(100),z(100);
- HMODULE hDLL=LoadLibrary(dllName);
- if(hDLL!=NULL)
- {
- FUNA fp1=FUNA(GetProcAddress(hDLL,funName1));
- if(fp1!=NULL)
- {
- std::cout<<"Input 2 Numbers:";
- std::cin>>x>>y;
- fp1(x,y);
- }
- else
- {
- std::cout<<"Cannot Find Function "<<funName1<<std::endl;
- }
- FUNB fp2=FUNB(GetProcAddress(hDLL,funName2));
- if(fp2!=NULL)
- {
- std::cout<<"Input 3 Numbers:";
- std::cin>>x>>y>>z;
- fp2(x,y,z);
- }
- else
- {
- std::cout<<"Cannot Find Function "<<funName2<<std::endl;
- }
- FreeLibrary(hDLL);
- }
- else
- {
- std::cout<<"Cannot Find "<<dllName<<std::endl;
- }
- system("pause");
- return 1;
- }
代码比较长,但是并不难理解,这里仅说明代码中的一些要点。
- 包含头文件Windows.h,原因在于程序中用到了LoadLibrary、FreeLibrary、GetProcAddress等Win32 API函数。
- FUNA和FUNB是函数指针类型的声明。
- 当程序不再使用dll时,应该调用FreeLibrary及时释放它占用的内存空间。
- 如果在const char* dllName和funName底部出现红色波浪线提示,说明采用的字符集不匹配,需要修改项目UseDLL的属性CharaterSet为Not Set。
- 为方便项目的调试,建议修改解决方案的Startup Project属性为Single startup project并以UseDLL为首选。
然而,这个程序还有错误。编译并运行,结果如图4所示。
图4 UseDLL的运行结果
这并不是期望中的结果。实际上,正如第二节提到的那样,造成这种错误的原因正是导出函数的修饰名称。虽然在CreateDLL.cpp中两个printMax函数有相同的名称,但在dll二进制文件中,经过编译器的“加工”,它们实际上各自有不同的名称了。这也是函数重载机制得以实现的一个技术支持。
使用VS2010附带工具dumpbin,查看CreateDLL.dll的导出函数名,结果如图5所示。
图5 查看CreateDLL.dll的导出函数名
观察图5可以发现,CreateDLL.dll导出函数名为?printMax@@YAXAAH00@Z和?printMax@@YAXAAH0@Z。它们分别对应着3个整数的printMax和两个整数的printMax。因此,Use.DLL中funName应当相应修改为:
- const char* funName1="?printMax@@YAXAAH0@Z";
- const char* funName2=“?printMax@@YAXAAH00@Z”;
修改之后,再次编译运行,结果正确,如图6所示。
图6 UseDLL正常运行
dll导出函数名称规范化
创建、使用dll并不复杂,走过前三节,相信读者肯定有这样的体会。然而,一个问题仍然值得思考:导出函数的修饰名称太“奇怪”,为dll的使用带来了不便,能不能让导出函数的修饰名称规范一些?
答案是肯定的,而且方法至少有两种:一是运用extern "C"修饰printMax;二是运用模块定义文件.def。后者的效果更好,所以本节将使用.def来规范化导出函数的修饰名称。
CreateDLL.dll导出的两个函数功能很简单,根据功能描述,理想的函数名称是pMaxA2和pMaxA3。在CreateDLL项目中添加CreateDLL.def文件:
- LIBRARY CreateDLL
- EXPORTS
- pMaxA2=?printMax@@YAXAAH0@Z
- pMaxA3=?printMax@@YAXAAH00@Z
重新build项目CreateDLL,使用dumpbin再次查看CreateDLL.dll的导出函数名称,结果如图7所示。
图7 规范化的函数名,奇怪的修饰名称还存在
出现了期望的结果,但仍然有小缺憾:奇怪的修饰名称仍然存在。能否去掉这些不太规范的修饰名称呢?当然是可以的。只需要将CreateDLL.h中#define CREATEDLL_API __declspec(dllexport) 修改为#define CREATEDLL_API即可。修改之后重新编译生成CreateDLL.dll,使用dumpbin查看导出函数名称,结果如图8所示。
图8 规范化的函数名,去除了奇怪的修饰名称
回到UseDLL.cpp,修改funName:
- const char* funName1="pMaxA2";
- const char* funName2="pMaxA3";
重新编译运行UseDLL,结果正确,与图6类似。
dll的不足:
动态链接库虽然一定程度上实现了“黑盒复用”,但仍然存在着诸多不足,笔者能够想到的有下面几点。
- dll节省了编译期的时间,但相应延长了运行期的时间,因为在使用dll的导出函数时,不但要加载dll,而且程序将会在模块间跳转,降低了cache的命中率。
- 若采用隐式调用,仍然需要.h、.lib、.dll文件(“三件套”),并不能有效支持模块的更新。
- 显式调用虽然很好地支持模块的更新,但却不能导出类和变量。
- dll不支持Template。
二进制级别的代码复用相比源码级别的复用已经有了很大的进步,但在二进制级别的代码复用中,dll显得太古老。想真正完美实现跨平台、跨语言的黑盒复用,采用COM才是正确的选择。
发表评论
-
win32基础实例
2012-10-08 22:59 1301本文毫无看点,完全是 ... -
rapidxml操作xml
2012-10-07 14:14 5314rapidxml:(内容源自网络) 一个项目对xml的操作是 ... -
文件操作
2012-10-07 09:50 711文件操作: 文件的读写操作,是一个程序最基本的功能。 ... -
C++的字符应用(TCHAR,WCHAR,LPSTR,LPWSTR,LPCTSTR)
2012-09-26 18:01 2682来自:http://www.cnblogs.com/lazyc ... -
#pragma 预处理指令
2012-09-15 23:19 899在所有的预处理指令中,#pragma 指令可能是最复杂的了,它 ... -
.rc Windows资源文件定义和使用
2012-09-15 18:47 18010统一资源管理: 在win32 ... -
关于"符号已定义"的链接错误
2012-09-09 17:13 1370在写C++程序的时候,在编译和连接的时候,经常容易看到: ... -
VS和Resharper
2012-08-28 20:11 4作为一个java出身的eclipse IDE程序员,学习C++ ... -
C++头文件一览
2012-08-24 11:32 1646C、传统 C++ #include &l ... -
C++函数
2012-08-19 10:05 938函数的作用,代码的重用,这种模块的概念在面向过程和面向对象的编 ... -
C++复杂类型
2012-08-17 08:51 922基础: 1.赋值: 结构 ... -
VS的快捷键
2012-08-15 15:21 1026VS的快捷键与eclipse的很不同,相同功能的按键不同,但是 ... -
C++基础类型
2012-08-12 21:23 969基础类型: 1.基础类型的长度:(基础类型的长度会根据 ... -
C++的命名空间
2012-06-28 14:20 827命名空间: 对于一个大型程序来说,变量名重名是很合理而 ... -
户端程序员必备知识
2012-06-27 19:43 976网络游戏客户端结构: 程序框架 文件读写模块 自动 ... -
window常用的基本数据类型及句柄类型
2012-06-26 13:57 14windows的运行原理: 应用程序 ----- 操作 ...
相关推荐
dll创建和使用工程,可借鉴作为模板。开发环境VS2012。
vs2010 导出创建dll 导入使用dll 导出有命名空间的类 函数 外部函数
vs2010创建和使用动态链接库(dll) 提供详细代码 和 说明 http://blog.csdn.net/qq_17242957/article/details/48288559
vs2010创建和使用动态链接库(dll),里面包括具体的文档说明以及VS2010的实例代码工程文件,可以正常跑运行,方便用户使用。这里面不是函数,而是类。
dll的创建与使用 dll的创建与使用 dll的创建与使用
一步一步学习Visual Studio 2015 Community创建DLL,整体来看和Visual Studio 6.0是一样的。只是IDE的环境变了,本例程是创建一个WIN32空的DLL工程,手动创建.h文件,创建.cpp文件。 #ifndef TEST_VS2015_DLL_...
使用DLL创建程序快捷方式,简单,轻便~~欢迎下载!
易语言创建进程注入DLL源码,创建进程注入DLL,GetCmdLine,命令行缓冲区_,取文本内容长度_,CopyMemory,SN_CreateProcessA,SN_InjectDllA
VS2015中用C++创建MFC DLL动态库,包含了mfc dll的创建以及在控制台中调用
1、打开Microsoft Visual Studio 2010,选择File->New->Project。 2、在New Project中选择Installed Templates->Visual C++->Win32。 3、选择Win32 Console Application,设置名称:simpledll,设置解决方案名:...
本例说明如何使用vc6创建和使用dll,其中dll导出函数为一些本人实现的字符串函数,可供初学这参考,详细内容可参考readme文件
DelphiDll创建与调用源码 使用delphi生成动态连接库文件 并使用动态连接库
vc2010创建dll比vc6.0方便很多很多
Delphi创建Dll和调用Dll示例(包含Dll窗体调用) 网上介绍比较杂乱,特地整理了一份Demo代大家学习参考。 1.socketA_dll 为dll工程目录。 2.LoadDllDemo 为【静态调用】dll工程目录。 3.LoadDllDemo_动态调用 为...
一 链接库概述 二 静态链接库 三 库的调试与查看 四 一个简单的DLL 非MFC动态库 五 MFC规则DLL Regular 六 MFC扩展DLL的创建 七 让EXE导出函数及DLL木马
DLL在Qt中的创建,DLL在Qt中的显式与隐式的使用
该资源提供MFC常规DLL的定义,与使用方法,对初学者有一定帮助
详细讲解通过def文件创建DLL,方便初学者能快速掌握使用和创建dll
使用vs2008创建dll的源代码,从这个例子中可以学习怎样创建dll,内有详细说明文档
运用DELPHI7.0创建并调用DLL计算两个数中的最大数和最小数。