visor studio 2013创建DLL

创建动态链接库 (DLL) 项目

                 -------参考MSDNRepeaterbin的专栏

 

  1. 在菜单栏上,选择“文件”“新建“项目”
  2. 在“新建项目”对话框左窗格中,展开“已安装”、“模板”、“Visual C++”,然后选择“Win32”。
  3. 在中间窗格中,选择“Win32 控制台应用程序”
  4. 在“名称”框中为项目指定名称,例如,MathFuncsDll。 在“解决方案名称”框中为解决方案指定一个名称,例如 DynamicLibrary。 选择“确定”按钮。
  5. “Win32 应用程序向导”对话框的“概述”页上,选择“下一步”按钮。
  6. 在“应用程序设置”页上的“应用程序类型”下,选择“DLL”。
  7. 选择“完成”按钮创建项目。

向动态链接库添加类

  1. 若要为新类创建头文件,在菜单栏上依次选择“项目”、“添加新项...”。 在“添加新项”对话框中,在左窗格的“Visual C++”下,选择“代码”。 在中心窗格中,选择“头文件 (.h)”。 为头文件指定一个名称,例如 MathFuncsDll.h,然后选择“添加”按钮。 将显示一个空白头文件。
  2. 添加下列代码至头文件的开头:
    1. 添加下列代码至头文件的开头:

        // MathFuncsDll.h

 
#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif

 

  1. 在MathFuncsDll.h中,添加一个名为“MyMathFuncs”的基础类,以执行常见的算术运算,如加、减、乘和除。 代码应类似如下:
namespace MathFuncs
{
    // This class is exported from the MathFuncsDll.dll
    class MyMathFuncs
    {
    public: 
        // Returns a + b
        static MATHFUNCSDLL_API double Add(double a, double b); 
 
        // Returns a - b
        static MATHFUNCSDLL_API double Subtract(double a, double b); 
 
        // Returns a * b
        static MATHFUNCSDLL_API double Multiply(double a, double b); 
 
        // Returns a / b
        // Throws const std::invalid_argument& if b is 0
        static MATHFUNCSDLL_API double Divide(double a, double b); 
    };
}
  1.  当定义了 MATHFUNCSDLL_EXPORTS 符号时,MATHFUNCSDLL_API 符号将在此代码中的成员函数声明中设置 __declspec(dllexport) 修饰符。 此修饰符使函数能作为 DLL 导出,以供其他应用程序调用。 当 MATHFUNCSDLL_EXPORTS 未定义时,MATHFUNCSDLL_API 会在成员函数声明中定义 __declspec(dllimport) 修饰符。 此修饰符能够使编译器优化从 DLL 导入的用于其他应用程序的函数。 默认情况下,生成 MathFuncsDll 项目时会定义 MATHFUNCSDLL_EXPORTS。在“解决方案资源管理器”的“MathFuncsDll”项目中,在“源文件”文件夹中,打开“MathFuncsDll.cpp”。
  2. 在“解决方案资源管理器”的“MathFuncsDll”项目中,在“源文件”文件夹中,(存在)打开或(不存在)添加“MathFuncsDll.cpp”、

// MathFuncsDll.cpp : Defines the exported functions for the DLLapplication.

#include "stdafx.h"

#include "MathFuncsDll.h"
#include <stdexcept>
 
using namespace std;
 
namespace MathFuncs
{
    double MyMathFuncs::Add(double a, double b)
    {
        return a + b;
    }
 
    double MyMathFuncs::Subtract(double a, double b)
    {
        return a - b;
    }
 
    double MyMathFuncs::Multiply(double a, double b)
    {
        return a * b;
    }
 
    double MyMathFuncs::Divide(double a, double b)
    {
        if (b == 0)
        {
            throw invalid_argument("b cannot be zero!");
        }
 
        return a / b;
    }
}
 

备注:导出函数常用方式:

1,使用DEF文件从DLL中导出

.def 文件必须至少包含下列模块定义语句:

文件中的第一个语句必须是 LIBRARY 语句。 此语句将 .def 文件标识为属于 DLL LIBRARY 语句的后面是 DLL 的名称。 链接器将此名称放到 DLL 的导入库中。

EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。 通过在函数名的后面加上 @ 符和一个数字,给函数分配序号值。 当指定序号值时,序号值的范围必须是从 1 到N,其中 N 是 DLL 导出函数的个数。

LIBRARY   BTREE
EXPORTS
Insert   @1
Delete   @2
Member   @3
Min   @4
 

2,使用__declspec(dllexport) 从DLL 导出

可以使用 __declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。 __declspec(dllexport) 会将导出指令添加到对象文件中,因此不需要使用 .def 文件。

若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。

__declspec(dllexport) void __cdecl Function1(void);
 

若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,

class__declspec(dllexport) CExampleExport

{ ... classdefinition ... };

 

我们常用的导出定义:

#ifdef _EXPORTING

#defineAPI_DECLSPEC    __declspec(dllexport)

#else

#defineAPI_DECLSPEC    __declspec(dllimport)

#endif

class API_DECLSPECCBtt

{

public:

       CBtt(void);

       ~CBtt(void);

public:

       CString m_str;

       static int GetValue()

       {

              return m_nValue;

       }

private:

       static int m_nValue;

};

注:单独使用__declspec(dllexport)已经可以实现DLL中库函数的导出,不使用 __declspec(dllimport)也能正确编译代码,但使用 __declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport)才能导入 DLL 中使用的变量。

 __declspec(dllimport)的实际用处:

SIMPLEDLL_EXPORT
SimpleDLLClass.h

#ifdefSIMPLEDLL_EXPORT

#define DLL_EXPORT__declspec(dllexport)

#else

#define DLL_EXPORT

#endif

 

class DLL_EXPORTSimpleDLLClass

{

public:

 SimpleDLLClass();

 virtual ~SimpleDLLClass();

 

 virtual getValue() { return m_nValue;};

private:

 int m_nValue;

};

SimpleDLLClass.cpp

#include"SimpleDLLClass.h"

 

SimpleDLLClass::SimpleDLLClass()

{

 m_nValue=0;

}

 

SimpleDLLClass::~SimpleDLLClass()

{

}

然后你再使用这个DLL类,在你的项目中include SimpleDLLClass.h时,你的项目不用定义 SIMPLEDLL_EXPORT 所以,DLL_EXPORT 就不会存在了,这个时候,不会遇到问题。这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。但,我们改一下SimpleDLLClass,把它的m_nValue改成static,然后在cpp文件中加一行
int SimpleDLLClass::m_nValue=0;

 改完之后,再去LINK一下,你的APP,看结果如何,结果是LINK告诉你找不到这个m_nValue

改一下SimpleDLLClass.h

#ifdefSIMPLEDLL_EXPORT

#define DLL_EXPORT__declspec(dllexport)

#else

#define DLL_EXPORT__declspec(dllimport)

#endif

再LINK,一切正常。原来dllimport是为了更好的处理类中的静态成员变量的,如果没有静态成员变量,那么这个__declspec(dllimport)无所谓。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章