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)無所謂。

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