您的位置:首页 > 其它

VS2010的一些细节点(2)--建立dll项目时的相关知识

2014-01-07 11:06 423 查看
1、建立一个Win32项目,在应用程序类型中选择第三项DLL,在附加选项中根据需要选择是否到处符号,如下图所示:



建立好后会生成号框架,dllmain.cpp定义DLL应用程序的入口点,另外一个和项目名相同的cpp定义DLL应用程序的到处函数。下面就对这些定义进行一下说明。

2、什么是DLL

   动态链接库(Dynamic
Link Library或者Dynamic-link library,缩写为DLL),是微软公司微软视窗操作系统中实现共享函数库概念的一种实作方式。这些库函数的扩展名是.DLL、.OCX(包含ActiveX控制的库)或.DRV(旧式的系统驱动程序)。所谓动态链接,就是把一些经常会共用的代码(静态链接的OBJ程序库)制作成DLL档,当可执行文件调用到DLL档内的函数时,windows操作系统才会把DLL档加载存储器内,DLL档本身的结构就是可执行文件,当程序需求函数才进行链接。通过动态链接方式,存储器浪费的情形将可大幅降低。DLL的最初目的是节约应用程序所需的磁盘和内存空间。在一个传统的非共享库中,一部分代码简单地附加到调用的程序上。如果两个程序调用同一个子程序,就会出现两份那段代码。相反,许多应用共享的代码能够切分到一个DLL中,在硬盘上存为一个文档,在内存中使用一个实例(instance)。DLL的广泛应用使得早期的视窗能够在紧巴巴的内存条件下运行。DLL提供了如模块化这样的共享库的普通好处。模块化允许仅仅更改几个应用程序共享使用的一个DLL中的代码和数据而不需要更改应用程序自身。模块化的另外一个好处是插件的通用接口使用。单个的接口允许旧的模块与新的模块一样能够与以前的应用程序运行时无缝地集成到一起,而不需要对应用程序本身作任何更改。这种动态扩展的思想在ActiveX中发挥到了极致。尽管有这么多的优点,使用DLL也有一个缺点:DLL地狱,也就是几个应用程序在使用同一个共享DLL库发生版本冲突。这样的冲突可以通过将不同版本的问题DLL放到应用程序所在的文件夹而不是放到系统文件夹来解决;但是,这样将抵消共享DLL节约的空间。目前,Microsoft
.NET将解决DLL hell问题当作自己的目标,它允许同一个共享库的不同版本并列共存。由于现代的计算机有足够的磁盘空间和内存,这也可以作为一个合理的实现方法。(引用自维基百科)

     微软Visual
C++(MSVC)提供了许多标准C++的扩展,它允许直接在C++代码中将函数标为输入还是输出函数;这种做法已经被其它的Windows平台的C和C++编译器所采纳,其中包括Windows版的GCC。这种扩展在函数声明前使用__declspec属性。如果是遵从C命名规范(convention)的外部名字,它们必须在C++代码中声明为extern
"C"以避免它们使用C++命名规范。除了使用__declspec属性定义输入输出函数之外,它们也可以列在项目DEF文档的IMPORT或者EXPORTS部分。DEF文档由链接器而不是编译器进行处理,这样它就不是C++特有的。

 

3、编程实例


创建DLL输出函数

#include <windows.h>

// Export this function
extern "C" __declspec(dllexport) double AddNumbers(double a, double b);

// DLL initialization function
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

// Function that adds two numbers
double AddNumbers(double a, double b)
{
return a + b;
}



使用DLL输入

#include <windows.h>
#include <stdio.h>

// Import function that adds two numbers
extern "C" __declspec(dllimport) double AddNumbers(double a, double b);

int main(int argc, char **argv)
{
double result = AddNumbers(1, 2);
printf("The result was: %f\n", result);
return 0;
}


另在微软官网上可以查询DLL的相关信息http://msdn.microsoft.com/zh-cn/library/1ez7dh12(v=vs.90).aspx

4、__declspec(dllexport)和__declspec(dllimport)

__declspec(dllexport)

声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中 

省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类

__declspec(dllimport)

声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中 

不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。

引用自:http://www.cnblogs.com/xd502djj/archive/2010/09/21/1832493.html

5、系统中比较常见的几个dll

     Windows中有3个非常重要的底层DLL:Kernel32.dll、User32.dll、GDI32.dll。其中Kernel32.dll顾名思义就是内核相关的功能,主要包含用于管理内存、进程和线程的函数;而User32.dll中包含的则是用于执行用户界面任务的函数,比如把用户的鼠标点击操作传递给窗口,以便窗口根据用户的点击来执行预定的事件;GDI32.dll的名称用了缩写,全称是Graphical
Device Interface(图形设备接口),包含用于画图和显示文本的函数,比如要显示一个程序窗口,就调用了其中的函数来画这个窗口。 

6、刨根问底:DLL的寓言 

DLL引起的故障是很常见的,为什么会引起故障?遇到故障怎么解决?嘘~偷听一下DLL的对话,你就会明白了。 
  1.从搬运工谈接口兼容性 
  在Windows工地上,有一个名叫EXE的包工头,他手下有很多称为DLL的建筑工人。其中有一个专门负责搬运的DLL(暂且称为“搬运工A”),每次需要搬运水泥时,包工头EXE都只要对他喊一声:“来!搬。” 
  过了一段时间,搬运工A觉得自己的效率太低,于是从原来的每次搬1袋水泥改成了每次搬3袋水泥。改进了搬运方法后,EXE包工头仍然每次只是喊一声:“来!搬。”却不知搬运工A已经改变了搬运的方法。 
  但又过了一段时间,包工头EXE把搬运工A给辞退了,从别的工地上找来了另一个DLL(暂且称为“搬运工B”)。这个搬运工在别的工地的时候,搬运东西特别快,所以包工头EXE决定把搬运工作给“升级”一下。但真正开始工作时,包工头才发现出了问题……现在不管叫几遍“来!搬。”这个新来的搬运工B都不知道究竟应该搬什么。 
  上面的例子中,搬运工A改进搬运方法,但EXE调用它的方法仍不变,这就是DLL升级的原理,改进了内部的实现方法,但调用接口不变,这样EXE文件不用跟着升级,就能调用新版本的DLL了。而搬运工B的故事告诉我们,不管新版本的DLL效率多高,如果接口(可以理解为DLL中输出的函数名)与原来的不一致,那么EXE就不知道也无法调用它了。 
  2.登记身份证的DLL 
  在系统故障中,有很多都是由于DLL文件没有注册造成的,比如Windows XP的压缩文件夹功能出现故障就很有可能是系统目录中的zipfldr.dll没有注册造成的,这类故障的解决方法也大多是运行如下命令: 
  regsvr32 DLL文件名 
  很多人不理解为什么要这么做,是不是所有的DLL都能这样做呢? 
  其实系统中有两种DLL,一种是不需注册即可使用的,另一种则是必须经过系统登录(即注册)才能使用的。就好像一个临时工,和一个记录在员工名单上的长期合同工的区别一样。如何才能区分这两种DLL呢?方法很简单,用刚才的Depends打开这个DLL,同样是看函数输出表,如果其中包含以下两个函数(前者是注册DLL,后者是反注册DLL),那么就一定是需要注册才能使用的DLL了。 
  DllRegisterServer 
  DllUnregisterServer 
  而regsvr32这个命令,实际上就是调用DLL中的这两个函数(“regsvr32 /u DLL文件名”调用的即为DllUnregisterServer反注册函数)。 
  3.插件DLL的秘密 
  Winamp、Foobar 2000等很多软件都具有插件功能,从网上下载一个DLL放在插件目录下就能让程序支持新的功能,这是怎么做到的呢?就拿时下流行的播放软件“千千静听”来举例吧。 
  “千千静听”的插件目录在该软件安装目录下的Addin子目录下,程序的插件目录一般都会以“Plugins”、“Addin”来命名。在“千千静听”的插件目录中有许多DLL文件,比如tt_asf.dll、tt_rm.dll等,从文件名中就能看出这些DLL是用来让这个播放器支持各种不同类型的音频文件的。同样,用Depends打开这些文件,你就会发现这些文件的输出函数表中都包括一个同样的函数:ttpGetSoundAddIn(见图4)。 



  这就是插件的秘密,各种支持插件功能的程序在发布时,都会同时发布一份插件协议,协议中规定了该程序将要调用的插件DLL中必须包含的函数名称及相关的参数规则,然后第三方的插件程序员在编写这个程序的插件时就根据这个插件的标准来编写DLL的输出函数。 
  ①对于插件tt_asf.dll 
  ttplayer.exe(“千千静听”主程序)对tt_asf.dll说:“我要调用你的ttpGetSoundAddIn函数!” 
  tt_asf.dll回答:“OK。” 
  ②如果把不相关的DLL放进AddIn目录 
  ttplayer.exe对未知DLL说:“我要调用你的ttpGetSoundAddIn函数!” 
  tt_asf.dll回答:“那是什么函数?从来没听说过!”

注:本文章只做自己资料积累和交流的目的,若有引用没有注明的地方还请谅解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  vs2010 DLL