VC2008动态链接库项目文件分析研究

转自:http://anony3721.blog.163.com/blog/static/5119742010102692514827/

 

当我们使用VS.Net 2008开发自己的Win32动态链接库时,我们会发现,当我们通过向导生成Win32项目时

,我们不选用空项目,而勾选导出一些符号时,我们会发现我们的项目生成的文件和过去版本的向导生成

的文件内容发生了变化。
例如我们输入TestingStructClassInDll项目名称,就会生成:
头文件:stdafx.h、targetver.h和TestingStructClassInDll.h三个头文件;
实现文件:dllmain.cpp、stdafx.cpp和TestingStructClassInDll.cpp三个实现文件。
我们可以看到:在dllmain.cpp文件中是如下内容
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
  break;
 }
 return TRUE;
}
相信,IT业界人士对这个函数都很熟悉,它是dll开发的入口点函数,每个dll文件都必须有它(除了纯资

源dll)。
我们继续看一下所包含的头文件:stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头中排除极少使用的资料
// Windows 头文件:
#include <windows.h>

 

// TODO: 在此处引用程序需要的其他头文件
可以看出,这两个文件和我们过去的dll文件内容差不多一致。
而stdafx.cpp文件如下:
// stdafx.cpp : 只包括标准包含文件的源文件
// TestingStructClassInDll.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用

另外,这里有个文件:targetver.h
#pragma once

// 以下宏定义要求的最低平台。要求的最低平台
// 是具有运行应用程序所需功能的 Windows、Internet Explorer 等产品的
// 最早版本。通过在指定版本及更低版本的平台上启用所有可用的功能,宏可以
// 正常工作。

// 如果必须要针对低于以下指定版本的平台,请修改下列定义。
// 有关不同平台对应值的最新信息,请参考 MSDN。
#ifndef WINVER                          // 指定要求的最低平台是 Windows Vista。
#define WINVER 0x0600           // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

#ifndef _WIN32_WINNT            // 指定要求的最低平台是 Windows Vista。
#define _WIN32_WINNT 0x0600     // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

#ifndef _WIN32_WINDOWS          // 指定要求的最低平台是 Windows 98。
#define _WIN32_WINDOWS 0x0410 // 将此值更改为适当的值,以适用于 Windows Me 或更高版本。
#endif

#ifndef _WIN32_IE                       // 指定要求的最低平台是 Internet Explorer 7.0。
#define _WIN32_IE 0x0700        // 将此值更改为相应的值,以适用于 IE 的其他版本。
#endif
我们可以看到这是一个有关于平台的文件,如果要让我们的dll适应各种平台,只需要修改对应的值即可

★其实我们最关心的问题是现在文件的变化。因此我们要重点研究的文件,是根据我们的项目名称成生的

一组头文件和实现文件:TestingStructClassInDll.h和TestingStructClassInDll.cpp。
首先我们观察一下.h文件:
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 TESTINGSTRUCTCLASSINDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// TESTINGSTRUCTCLASSINDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef TESTINGSTRUCTCLASSINDLL_EXPORTS
#define TESTINGSTRUCTCLASSINDLL_API __declspec(dllexport)
#else
#define TESTINGSTRUCTCLASSINDLL_API __declspec(dllimport)
#endif

// 此类是从 TestingStructClassInDll.dll 导出的
class TESTINGSTRUCTCLASSINDLL_API CTestingStructClassInDll {
public:
 CTestingStructClassInDll(void);
 // TODO: 在此添加您的方法。
};

extern TESTINGSTRUCTCLASSINDLL_API int nTestingStructClassInDll;

TESTINGSTRUCTCLASSINDLL_API int fnTestingStructClassInDll(void);

我们很容易发现:#ifdef...#define...#else...#define...#endif语句,它给我们的动态链接库定义了

一个输入输出符号,并且在我们的项目名称后面加上了_API后缀,Visual C++ 用 __declspec

(dllimport) 和 __declspec(dllexport) 取代以前在 16 位版的 Visual C++ 中使用的 __export 关键

字。

我们可以看到注释语句:我们从我们在.dll文件中导出了一个类,而在声明这个类的时候,我们必须将我

们定义的输放输出符号放在我们的类前面。而为了和C版本的兼容,我们引用了外部关键字extern,同时

,将它作为一个整型值导出该类。另外导出了一个整型函数fnTestingStructClassInDll。
接下来让我们来看一下实现文件部分:.cpp文件
// TestingStructClassInDll.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "TestingStructClassInDll.h"


// 这是导出变量的一个示例
TESTINGSTRUCTCLASSINDLL_API int nTestingStructClassInDll=0;

// 这是导出函数的一个示例。
TESTINGSTRUCTCLASSINDLL_API int fnTestingStructClassInDll(void)
{
 return 42;
}

// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 TestingStructClassInDll.h
CTestingStructClassInDll::CTestingStructClassInDll()
{
 return;
}
通过观察我们可以发现,这里主要是包含"stdafx.h"和自身头文件,当导出变量时,通过我们的自定义输

入输出符号加上我们的变量即可;当要导出函数时,我们也只需要先引用我们的输入输出符号,然后再书

写相关的导出函数;而类自身的函数,我们依然采取以前的方式进行即可。
理解了以上的变化,有利于我们更完善的写我们自己的动态链接库。
通过Dependency Walker我们可以观察到我们生成的动态链接库导出了以下函数:
Ordinal      Hint          Function                                             
1 (0x0001)   0 (0x0000)    CTestingStructClassInDll::CTestingStructClassInDll(void)
2 (0x0002)   1 (0x0001)    class CTestingStructClassInDll & CTestingStructClassInDll::
                           operator= (class CTestingStructClassInDll const &)
3 (0x0003)   2 (0x0002)    struct _Meimei & _Meimei::operator=(struct _Meimei const &)
4 (0x0004)   3 (0x0003)    int fnTestingStructClassInDll(void)
5 (0x0005)   4 (0x0004)    int nTestingStructClassInDll
当然,depends还可以得到dll的Entry Point,以及模块的文件时间戳、链接时间戳、文件大小、文件的

访问属性、链接校验地址、真实校验地址、CPU类型、子系统类型、符号、参考基地址等等信息。
这里我们看到了在TestingStructClassInDll.h头文件中加入的一个自定义结构,用于导出:
//此结构是在项目中导出的
typedef struct TESTINGSTRUCTCLASSINDLL_API _Meimei
{
 int Num;
 char Name;
}Meimei;
有了以上完整的分析,相信我们对VC2008动态链接库项目有了更深一步的理解了!对比可以令一切更加一目了然!

你可能感兴趣的:(windows,api,struct,dll,internet,平台)