新建一个DLL类型的应用程序,如:myDll.cpp

#include <windows.h>
#include <iostream>
extern "C" int _declspec(dllexport) DllAdd(int a, int b)
{
    return  a + b;
}

extern "C"
在 DLL的设计中中,,如果使用C++开发,通常在导出函数的定义中使用extern "C",为什么呢?因为当用户使用"运行时动态链接"的时候将使用GetProcAddress函数得到导出函数的地址,该函数是通过导出函数的函数名定位导出函数的,而C++编译器因为函数重载的原因会对开发者定义的函数名进行修饰,导致导出表中的函数名通常不是开发者使用的函数名,比如函数 ExportedFn可能被修饰成??ExportedFn@QAEX 。所以使用extern "C"通知编译器按照C的格式进行编译,而不是使用C++的方法进行编译。使用VS提供的一个工具Dependency Walker可以查看DLL的导出函数。

_declspec
http://support.microsoft.com/kb/132044

新建一个win32控制台应用程序,如:TestDll.cpp

// TestDll.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
typedef int (*FUNC)(int , int );
int _tmain(int argc, _TCHAR* argv[])
{
    FUNC fun;
    int a = 0, b = 0, c = 0;
    HMODULE m_hModule = ::LoadLibrary(L"..//Debug//myDll.dll");
    if (!m_hModule)
    {
        printf("加载DLL文件失败!/n");
    }
    else
    {
        fun = (FUNC)GetProcAddress(m_hModule, "DllAdd");
        printf("请输入两个数:");
        scanf("%d%d", &a, &b);
        c = fun(a, b);
        printf("%d + %d = %d/n", a, b, c);
    }
    FreeLibrary(m_hModule);
    system("pause");
    return 0;
}
  • typedef int (*FUNC)(int , int)

    函数指针,用以指向DLL中的函数, 返回值、参数个数要与其匹配

  • LoadLibrary(...)

    载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源。

  • GetProcAddress(...)

    检索指定的动态链接库(DLL)中的输出库函数地址。

  • FreeLibrary(...)

    释放指定的动态链接库,它们早先是用LoadLibrary API函数装载的。

上面是DLL的显示调用,看起来比较麻烦但是它只要一个dll文件就可以了;

下面是DLL的隐式调用, 用起来比较简单但是它需要三个文件:.h, .lib, .dll。 新建一个dll工程,注意工程属性->Preprocessor里面会有个_USRDLL宏
如下代码:

// dlltest.h
#ifndef _DLL_TEST_H_
#define _DLL_TEST_H_

#ifdef _USRDLL
 #define DLLTEST_API __declspec(dllexport)
#else
 #define DLLTEST_API __declspec(dllimport)
#endif

DLLTEST_API int Sum(int x, int y);

class DLLTEST_API Coord
{
public:
    Coord(int x, int y);
    void Print();

private:
    int x_, y_;
};

#endif // _DLL_TEST_H_
// dlltest.cpp
#include "dlltest.h"
#include <iostream>

int Sum(int x, int y)
{
    return x+y;
}

Coord::Coord(int x, int y)
 : x_(x), y_(y)
{
}

void Coord::Print()
{
    std::cout << "x = " << x_ << ", y = " << y_ << std::endl;
}

编译会生成dlltest.lib和dlltest.dll

测试DLL

  • 首先,在用的时候包含dlltest.h头文件,测试程序C/C++->Additional Include Directories里面指定dlltest.h目录;
  • 其次,Linker->Additional Library Directories里面指定dlltest.lib目录,以及 Linker->Input->Additional Dependencies里面填写dlltest.lib,这样就可以通过编译;
  • 最后,要运行还需要dlltest.dll文件,将其文件放在与测试程序exe同一目录下即可(当然系统目录下也可以只要exe运行时可以找到)。

这是apr里面的一个例子:

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the SAMPLEDLL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// SAMPLEDLL_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef SAMPLEDLL_EXPORTS
#define SAMPLEDLL_API __declspec(dllexport)
#else
#define SAMPLEDLL_API __declspec(dllimport)
#endif

// This class is exported from the SampleDLL.dll
class SAMPLEDLL_API CSampleDLL {
public:
    CSampleDLL(void);
    // TODO: add your methods here.
};

extern SAMPLEDLL_API int nSampleDLL;

SAMPLEDLL_API int fnSampleDLL(void);
// SampleDLL.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "SampleDLL.h"

BOOL APIENTRY DllMain( HANDLE 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;
}


// This is an example of an exported variable
SAMPLEDLL_API int nSampleDLL=0;

// This is an example of an exported function.
SAMPLEDLL_API int fnSampleDLL(void)
{
    return 42;
}

// This is the constructor of a class that has been exported.
// see SampleDLL.h for the class definition
CSampleDLL::CSampleDLL()
{ 
    return; 
}
聊天