编写DLL时的函数与一般的函数方法基本一样。但要对库中的函数进行必要的声明,以说明哪些函数是可以导出的,哪些函数是不可以导出的。

把DLL中的函数声明为导出函数的方法有两种:

一是使用关键字_declspec(dllexport)来声明。

二是在.def文件中声明。

 

一、使用关键字_declspec(dllexport)来声明导出函数

 

声明函数SayHello为导出函数语句为:int _declspec(dllexport)  SayHello ();

为了使一个用C++语言编写的DLL函数可以在C语言编写的应用程序中使用,在关键字_declspec(dllexport)  之前要附加另一个关键字:extern “C”,以通知编译器采用C链接方式。

 

 

例子:(用vs2008写的例子)

新建一个工程。

选择Win32 Project,工程名字为1_DLLDemo。确定。

 

选择DLL其它默认。

 

在文件1_DLLDemo.cpp编写代码如下:

 

extern "C" __declspec(dllexport) void SayHello()
{
    ::MessageBoxW(NULL, L"Hello", L"fangyukuan", MB_OK);
}

按F7编译即可。

 

再新建一个测试工程。这里简单一点,新建一个控制台工程就可以了。

选择Win32 console Application,其它全部默认。

 

 

编写如下代码:

#include "stdafx.h"
#include "stdlib.h"      // for system("pause");
#include "windows.h"
#include <iostream>
using namespace std;
 
typedef void (SAYHELLO)();  // 定义一个这种类型的函数指针
 
int _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE hDllInst;
 
    // 这里为dll的路径,因为现在exe和dll在同一个目录下,所以只写名字即可
    hDllInst=LoadLibrary(L"1_DLLDemo.dll");      
    if(NULL == hDllInst)
    {
       cout << "加载dll失败" << endl;
    }
    else
    {
       SAYHELLO * lpproc =(SAYHELLO *)GetProcAddress(hDllInst,"SayHello");
       if(NULL != lpproc)
           (*lpproc)();
 
       FreeLibrary(hDllInst);
    }
 
    system("pause");
    return 0;
}

按F7编译。再按F5运行。结果如下。

 

 

二、使用def文件声明导出函数

def文件又叫做模块定义文件,这是一个用于描述DLL属性的文本文件,每个def文件一般要包括以下模块定义语句:

A)       LIBRARY语句,指出DLL的名字,链接器将把这个名字放到DLL库中。

B)       EXPORTS语句,列出库中导出函数的名称及导出函数的序号(可选)。

C)       DISCRIPION语句,该语句用来描述DLL的用途等说明。

可以在def文件分号“;”后面书写注释语句。

 

在创建DLL时,编译链接器将要使用def文件创建两个文件:一个导出文件(.EXP)和一个导入库文件(.LIB),然后使用导出文件再创建DLL文件。

 

外部应用程序使用的文件是导入库文件和DLL文件。由于在导入库文件中存放了外部应用程序可导入的DLL导出函数名称列表,因此外部应用程序需要把它连接在应用程序中,才能以它为索引到DLL中去找到要调用的导出函数。也就是说,导入库文件相当于是DLL可提供的服务项目表。

 

例子:(用vs2008写的例子)

方法同上面一样新建一个DLL工程。

在文件2_DLLDemo.cpp编写代码如下:

void SayHello()
{
    ::MessageBoxW(NULL, L"2_DLLDemo::Hello", L"fangyukuan", MB_OK);
}

然后再新建一个def文件。

在工程右键->add->New Item…

 

 

在def文件编写如下代码:

LIBRARY    "2_DLLDemo"     //貌似可以随意取名
EXPORTS
    SayHello

 

用DEF从DLL导出一个函数,或用__declspec(dllexport)指令从DLL中导出一类,简单而经常使用的。这里向大家介绍一种用DEF文件从DLL导出一个类的方法:

    1.打开VC6.0,新建一个"Win32 Dynamic-Link Library"工程,假设叫DefClass
,在“Dll kind”选择界面中选择“A simple dll project”。

    2.新建一个文件,命名为DefClass.def,先暂时输入下面的内容,并加入工程。

LIBRARY DefClass
   EXPORTS

    3.向工程中加入一个类CMath,并添加一个Add方法,使之看起来如下:
 

class CMath 
  {
  public:
             int Add(int a,in b);
             CMath();
             virtual ~CMath();
  };  它的实现,你想如何由你决定,我做例子中,Add返回 return a+b。
Generate mapfile。

    5.Rebuild all工程。

    6.在VC中打开Debug或Release的*.map文件(如果你工程名这DefClass,那就是DelClass.map)。

    7.找到Math.obj,比如:

0001:00000080       ??0CMath@@QAE@XZ           10001080 f   Math.obj
 0001:000000c0       ??_ECMath@@UAEPAXI@Z       100010c0 f i Math.obj
 0001:000000c0       ??_GCMath@@UAEPAXI@Z       100010c0 f i Math.obj
 0001:00000130       ??1CMath@@UAE@XZ           10001130 f   Math.obj
 0001:00000170       ?Add@CMath@@QAEHHH@Z       10001170 f   Math.obj

    8.把1,4,5行的第2列拷贝到DefClass.Def文件中,使之成为下面的样子(序号自己指定)

LIBRARY DefClass
 EXPORTS 
        ??0CMath@@QAE@XZ                         @1
       ??1CMath@@UAE@XZ               @2
      ?Add@CMath@@QAEHHH@Z     @3

    9.保存所有文件,再执行Rebuild All。

    如果一切正常,那你的DLL中的类已经以序号导出的了。这时再往CMath中加函数,如上从map文件中找到函数的标识符,并在def文件中加一项,分配一个序号给它。只要保持以前的导出序号不变,用新编译生成的DLL替换先前的DLL,以前的客户程序仍然可以正常运行。