1.为什么使用DLL?

我们知道提高开发效率的一个很重要的途径就是代码复用,我们经常将一些常用的功能构造成相对独立的模块,并在之后的项目重复使用,代码复用的方式有两种:

  • 白盒复用:如ATL、MFC等,它们都以源代码的形式发布,源代码完全暴露给了程序员。

白盒复用的缺点比较多,暴露源码不说,容易与我们自己的代码产生命名冲突,还有就是更新功能比较麻烦。

  • 黑盒复用:如Dll,静态链接,com组件等。与白盒复用相比,dll黑盒复用的优势就很明显,dll是二进制文件,

因此隐藏了源代码,如果采用“显式调用,一般就能避免命名冲突;.dll文件相对独立的存在,因此更新功能模块是可行的。

2.如何创建一个DLL项目?

用vs2012创建一个新的Win32 应用控制台程序,名字取为math,要勾选dll选项。

如图:

VS2012 创建和使用DLL_C++ DLL

然后新建mymath.h和mymath.cpp文件。
mymath.h如下:

#pragma once  
  
#ifdef MATH_EXPORTS  
#define MATH_API __declspec(dllexport)  
#else  
#define MATH_API __declspec(dllimport)  
#endif  
  
namespace shun  
{  
    class MATH_API Cmath {              //类  
    public:  
        int add(int a,int b);  
    };  
  
    extern "C" MATH_API float pi;           //变量  
  
    extern "C" MATH_API int getMax(int &,int &);    //函数  
}

mymath.cpp如下:

#include "stdafx.h"  
#include "mymath.h"  
  
namespace shun  
{  
    float pi=3.1415;            //变量  
  
    int getMax(int& a, int& b) //函数  
    {  
        return a > b ? a : b;  
    }  
  
    int Cmath::add(int a,int b)         //类方法  
    {  
        return a + b;  
    }  
}

然后生成解决方案,编译成功后可以在debug文件夹下发现math.dll和math.lib文件。
至此,我们已经成功创建一个dll项目了。



3.如何隐式引用一个DLL项目?

隐式调用三要素,.h文件 ,.dll文件,.lib文件,缺一不可。
隐式调用的好处是可以像调用本地函数一样方便。


3.1如果项目和dll项目在同一个解决方案

为此我们新建一个win32控制台的空项目,取名useMath,然后引用dll步骤如下:

  1. 项目->属性->通用属性->框架和引用->添加新引用->勾选math项目->确定

  2. 项目->属性->配置属性->VC++目录->包含目录->添加mymath.h所在的目录


然后添加一个test.cpp文件,输入如下:

#include <iostream>    
#include "mymath.h"  
  
using namespace std;    
  
int main(char argc, char**argv)    
{    
    int a = 1, b = 2;  
  
    //类的使用  
    shun::Cmath cm;  
    cout<<cm.add(1,2)<<endl;   
    //变量  
    cout<<shun::pi<<endl;  
    //函数  
    cout<<shun::getMax(a,b);    
    getchar();    
    return 0;    
}

3.2如果项目和dll项目不在同一个解决方案呢?

为此,我们先打开一个新的vs2012,新建一个win32控制台的空项目,取名useMath,然后引用dll步骤如下:

  1. 项目->属性->配置属性->VC++ 目录-> 在“包含目录”里添加头文件mymath.h所在的目录 

  2. 项目->属性->配置属性->VC++ 目录-> 在“库目录”里添加头文件math.lib所在的目录 

  3. 项目->属性->配置属性->链接器->输入-> 在“附加依赖项”里添加“math.lib”(若有多个 lib 则以空格隔开)

  4. 将dll项目下的debug文件中的math.dll复制到当前项目的debug文件夹中

新建然后添加一个test.cpp文件,输入如下:(和之前一样)

#include <iostream>    
#include "mymath.h"  
  
using namespace std;    
  
int main(char argc, char**argv)    
{    
    int a = 1, b = 2;  
  
    //类的使用  
    shun::Cmath cm;  
    cout<<cm.add(1,2)<<endl;   
    //变量  
    cout<<shun::pi<<endl;  
    //函数  
    cout<<shun::getMax(a,b);    
    getchar();    
    return 0;    
}
4.如何显示调用dll项目?

显示调用只需要一个dll文件。显示调用好处是模块相对独立,更新非常方便。不好的地方是使用起来稍微复杂。
同之前一样,我们新建一个win32控制台项目,然后将math.dll放入debug文件夹中,

因为需要使用到windows api,所以要引入windows.h头文件。

添加test.cpp如下:

#include <windows.h>  
#include <iostream>  
using namespace std;  
  
typedef int (*Func)(int &, int &);  
  
int main(int argc, char *argv[])  
{  
    int a = 5, b = 10;  
    HMODULE hDll = LoadLibrary("math.dll");  
    if (hDll != NULL)  
    {  
        Func getMax = (Func)GetProcAddress(hDll, "getMax"); //函数  
        if (getMax != NULL)  
        {  
            cout<<getMax(a, b)<<endl;  
        }  
        float* pPi = (float*)GetProcAddress(hDll,"pi");     //变量  
        if(pPi != NULL)  
        {  
            cout<<*pPi<<endl;  
        }  
  
        FreeLibrary(hDll);  
    }  
    getchar();  
}

如果对于函数指针不太熟悉的话可以点这里:函数指针总结


如果要显示调用类的方法的话,可以在dll中写一个函数,由这个函数去调用,比如像这样子:

//.h文件  
extern "C" MATH_API int add_Interface(int &,int &); //函数  
//.cpp文件  
int add_Interface(int &a,int &b)  
{  
    Cmath cm;  
    return cm.add(a,b);  
}

然后像上面调用函数一样调用add_Interface。




5.extern "C"作用


我们知道,extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称。
比如:

void foo( int x, int y );

该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同)。

所以我们可以在函数前使用extern "C"来告诉编译器要采用c编译的方式,而不是c++编译的方式。


转载 : http://blog.csdn.net/shun_fzll/article/details/39078971