posts - 15, comments - 9, trackbacks - 0, articles - 0

如何创建自己的dll

Posted on 2009-04-28 12:10 沙漠里的海豚 阅读(459) 评论(0)  编辑 收藏 引用 所属分类: c/c++标准
前几天有个朋友问道这个问题,结果因为以前从没搞过这个,对vs2005也不熟悉,竟花了2个小时才搞定,
特地拿来与大家分享,希望能给像我这样的菜鸟们一些帮助,O(∩_∩)O
【第一步】创建自己的dll
1.打开vs2005,选择菜单【File-New-Project】,在弹出对话框中选择[Visual C++]下的[Win32]-[Win32 Console Application],输入工程名后确认。
2.在弹出的对话框中选择[next],在Application Settiongs中选择Application type为Dll,Additional options选择Empty project,然后点Finish。
这时就创建了一个空的可以生成dll文件的工程。
3.在工程中添加一个头文件(这里为dll_test.h),在头文件中写入如下内容:
 1 #ifndef _DLL_TUTORIAL_H
 2 #define _DLL-TUTORIAL_H
 3 
 4 #include<iostream>
 5 
 6 #if defined DLL_EXPORT
 7   #define DECLDIR _declspec(dllexport)
 8 #else
 9   #define DECLDIR _declspec(dllimport)
10 #endif
11 
12 extern "C"
13 {
14   DECLDIR int Add(int a, int b);
15   DECLDIR void Function(void);
16 }
17
18 #endif
这里要说明的是:
在VC中有两个方法来导出dll中定义的函数:
  (1) 使用__declspec,这是一个Microsoft定义的关键字。
  (2) 创建一个模板定义文件(Module-Definition File,即.DEF)。
  第一种方法稍稍比第二种方法简单,在这里我们使用的是第一种方法。
    __declspec(dllexport)函数的作用是导出函数符号到在你的Dll中的一个存储类里去。
当下面一行被定义时我定义DECLDIR宏来运行这个函数。
    #define DLL_EXPORT
在此情况下你将导出函数Add(int a,int b)和Function().
4.创建一个源文件(名字为dll_test.cpp),内容如下:
 
 1 #include <iostream>
 2 #define DLL_EXPORT
 3 #include "dll_test.h"
 4 
 5 extern "C"
 6 {
 7         // 定义了(DLL中的)所有函数
 8     DECLDIR int Add( int a, int b )
 9     {
10         return( a + b );
11     }
12     
13     DECLDIR void Function( void )
14     {
15         std::cout << "DLL Called!" << std::endl;
16     }
17 }
18 
【第二步】使用创建好的DLL
现在已经创建了DLL,那么如何在一个应用程序中使用它呢?
当DLL被生成后,它创建了一个.dll文件和一个.lib,这两个都是使用dll时需要用到的。
在具体介绍之前先看一下dll的链接方式。
(1)隐式连接
这里有两个方法来载入一个DLL,一个方法是只链接到.lib文件,并将.dll文件放到要使用这个DLL的项目路径中。
因此,创建一个新的空的Win32控制台项目并添加一个源文件。将我们创建好的DLL放入与新项目相同的目录下。同时我们还必须链接到dll_test.lib文件。
可以在项目属性中设置,也可以在源程序中用下面的语句来链接:
#pragma comment(lib, "dll_test.lib")
最后,我们还要在新的win32控制台项目中包含前面的dll_test.h头文件。可以把这个头文件放到新建win32控制台项目的目录中然后在程序中加入语句:
#include "dll_test.h"
新项目代码如下:
#include<iostream>
#include "DLLTutorial.h"
int main()
{
  Function();
  std::cout<< Add(32, 56)<< endl;
  return 0;
}
(2)显示链接
稍微复杂一点的加载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("DLL_Tutorial.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头文件,同时去掉了对dll_test.h头文件的包含。原因很简单:因为windows.h包含了一些Windows函数,
它也包含了一些将会用到的Windows特定变量。可以去掉DLL的头文件,因为当使用这个方法载入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的函数,你现在就可以使用它们了,但是这里有一个
需要注意的地方:你不能使用函数的实际名称;你必需使用函数指针来调用它们。在那以后,所有你需要做的是释放库如此而已。
     现在你知道了DLL的一些基本知识。你知道如何创建它们,你也知道如何用两种不同的方法链接它们。这里仍然有更多的东西需要我们学习,但我把它们留给你们自己探索了和更棒的作者来写了。

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理