dll文件制作

VC6.0创建非MFC的DLL (2010-01-19 14:13:35)转载▼
标签: 杂谈 分类: MSN搬家
忘了从哪儿转的的,作者多担待吧,呵呵
DLL
动态链接库(dll)是包含共享函数库的二进制文件,可以被 多个应用程序同时使用。建立应用程序的可执行文件时,不必将DLL连接到应用程序中,而是 在运行时动态装载DLL,装载时DLL被映射到调用进程的地址空间中。通常我们在调用DLL时所需的DLL文件必须位于以下三个目录之一:
——(1)Windows的系统目录:\windows\system;
——(2)DOS中path所指出的任何目录;
——(3)程序所在的目录;
DLL中定义有两种函数:导出函数(export function)和内部函数
(internal function),导出函数可以被其他模块调用,内部函数只能在DLL内部使用。

整个过程简单来说就是将其他模块要调用的函数,也就是导出函数,用关键字标识出来,而标识和调用又有不同的方式。
创建Sample.dll
1.在project中选择Win32 Dynamic-LinkLibrary,建立空白项目Sample.dll

2.在dll项目中建立头文件Sample.h
#ifndef _DLL_SAMPLE_H_
#define _DLL_SAMPLE_H_
#include <iostream>

//如果加上dllimport的define,就会报错,原因不明
//#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
//#else
//#define DECLDIR __declspec(dllimport)
//#endif

extern "C"//告诉编译器该部分可以在C/C++中使用。C要大写!!!
{
DECLDIR int Add( int a, int b );
DECLDIR void Function( void );
}
#endif
在VC++中这里有两个方法来导出函数:
(1)、使用__declspec,一个Microsoft定义的关键字。
(2)、创建一个模块定义文件(Module-Definition File即.DEF)。第一种方法稍稍比第二种方法简单些,但两种都工作得很好。
__declspec(dllexport)导出函数符号到在你的DLL中的一个存储类。


不采用__declspec关键字的方式---模块定义文件(.def)
模块定义文件是一个有着.def文件扩展名的文本文件。它被 用于导出一个DLL的函数,和__declspec(dllexport)很相似,但是.def文件并不是Microsoft定义的。一个.def文件中 只有两个必需的部分:LIBRARY 和 EXPORTS。让我们先看一个基本的.def文件稍后我将解析之。
LIBRARY Sample
DESCRIPTION "our simple DLL"
;注解
EXPORTS
Add @1
Function @2
第一行,''LIBRARY''是一个必需的部分。 它告诉链接器(linker)如何命名你的DLL。下面被标识为''DESCRIPTION''的部分并不是必需的,但是我喜欢把它放进去。该语句将字符 串写入 .rdata 节[据 MSDN],它告诉人们谁可能使用这个DLL,这个DLL做什么或它为了什么(存在)。再下面的部分标识为''EXPORTS''是另一个必需的部分; 这个部分使得该函数可以被其它应用程序访问到并且它创建一个导入库。当你生成这个项目时,不仅是一个.dll文件被创建,而且一个文件扩展名为.lib的 导出库也被创建了。除了前面的部分以外,这里还有其它四个部分标识为:NAME, STACKSIZE, SECTIONS, 和 VERSION。我将不再在本文中涉及这些内容,但是如果你在Internet上搜索,我想你将找到一些东西(译注: MSDN2003上对模板定义文件各部分内容有详尽解释,请参阅)。另外,一个分号(;)开始一个注解,如同''//''在C++中一样。
现在你已经创建了你的DLL,你需要学习如何在一个应用程序中使用它了。当这个DLL被生成后,它创建了一个.dll文件和一个.lib文件;这两个都是你需要的。
采用这种方式,在.h文件中就不用再使用关键字__declspec。

3.建立Sample.cpp源文件
#include <iostream>
#include "Sample.h"

//#define DLL_EXPORT
extern "C"
{
DECLDIR int Add( int a, int b )
{
return( a + b );
}
DECLDIR void Function( void )
{
std::cout << "DLL Called!" << std::endl;
}
}
也就是定义DLL中的两个函数,他们就是可能被调用的。

4.编译cpp文件,然后Build Sample.dll

5.调用Sample.dll

隐式链接
这里有两个方法来载入一个DLL;一个方法是捷径另一个则相比要复杂些。捷径是只链接到你.lib 文件并将.dll文件置入你的新项目的路径中去。因此,创建一个新的空的Win32控制台项目并添加一个源文件。将你做的DLL放入你的新项目相同的目录下。

//testDll.cpp
#include <iostream.h>
#include <windows.h>
#include "Sample.h"
#pragma comment(lib, "Sample.lib") //Sample.lib在编译过程可以不放在与testDll.cpp,可是有时候又必须放在相同目录下编译。。。囧。。。
//相同的目录下
int main()
{
Function();
std::cout << Add(32, 58) << "\n";
system("pause");
return(1);
}

编译链接后,将Sample.dll放在和testDll相同的目录下运行即可。

显示链接
难点的加载DLL的方法是有稍微有点复杂的。你将需要函数指针和一些Windows函数。但是,通过这种载入DLL的方法,你不需要DLL的.lib或头文件,而只需要DLL。下面列出一些代码。
#include <iostream>
#include <windows.h>


typedef int (*AddFunc)(int,int);
typedef void (*FunctionFunc)();

int main()
{
AddFunc _AddFunc;
FunctionFunc _FunctionFunc;
HINSTANCE hInstLibrary = LoadLibrary("Sample.dll");
if (hInstLibrary == NULL)
{
FreeLibrary(hInstLibrary);
}
_AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");

_FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary, "Function");
if ((_AddFunc == NULL) || (_FunctionFunc == NULL))
{
FreeLibrary(hInstLibrary);
}
std::cout << _AddFunc(23, 43) << std::endl;
_FunctionFunc();
std::cin.get();
FreeLibrary(hInstLibrary);
return(1);
}

首先你会注意到:这里包括进了文件“windows.h” 同时移走了“Sample.h”。原因很简单:因为windows.h包含了一些Windows函数,当然你现在将只需要其中几个而已。它也包含了一些将 会用到的Windows特定变量。你可以去掉DLL的头文件(Sample.h)因为-如我前面所说-当你使用这个方法载入DLL时你并不需要它。
下面你会看到:以下面形式的一小块古灵精怪的代码:
typedef int (*AddFunc)(int,int);

typedef void (*FunctionFunc)();

这是函数指针。因为这是一个关于DLL的自学指 南,深入探究函数指针超出了本指南的范围;因此,现在我们只把它们当作DLL包含的函数的别名。我喜欢在尾部用“Func”命名之。(int,int)部 分是这个函数的参数部分,比如,Add函数要获得两个整数;因此,你需要它们(译注:指(int,int)部分)作为函数指针的参数。Function函 数没有参数,因此你让它为空。main()部分中的前面两行是声明函数指针以使得你可以认为它们等同于DLL内部的函数。我只是喜欢预先定义它们。
HINSTANCE是一个Windows数据类 型:是一个实例的句柄;在此情况下,这个实例将是这个DLL。你可以通过使用函数LoadLibrary()获得DLL的实例,它获得一个名称作为参数。 在调用LoadLibrary函数后,你必需查看一下函数返回是否成功。你可以通过检查HINSTANCE是否等于NULL(在Windows.h中定义 为0或Windows.h包含的一个头文件)来查看其是否成功。如果其等于NULL,该句柄将是无效的,并且你必需释放这个库。换句话说,你必需释放 DLL获得的内存。如果函数返回成功,你的HINSTANCE就包含了指向DLL的句柄。
一旦你获得了指向DLL的句柄,你现在可以从 DLL中重新获得函数。为了这样作,你必须使用函数GetProcAddress(),它将DLL的句柄(你可以使用HINSTANCE)和函数的名称作 为参数。你可以让函数指针获得由GetProcAddress()返回的值,同时你必需将GetProcAddress()转换为那个函数定义的函数指 针。举个例子,对于Add()函数,你必需将GetProcAddress()转换为AddFunc;这就是它知道参数及返回值的原因。现在,最好先确定 函数指针是否等于NULL以及它们拥有DLL的函数。这只是一个简单的if语句;如果其中一个等于NULL,你必需如前所述释放库。
一旦函数指针拥有DLL的函数,你现在就可以使用它们了,但是这里有一个需要注意的地方:你不能使用函数的实际名称;你必需使用函数指针来调用它们。在那以后,所有你需要做的是释放库如此而已
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值