1. 程式人生 > >VS2010 中編寫動態庫和呼叫動態庫

VS2010 中編寫動態庫和呼叫動態庫

https://www.cnblogs.com/zhengfa-af/p/8108187.html

https://blog.csdn.net/qq_22642239/article/details/80451299

VS2010 中編寫動態庫和呼叫動態庫

百度查了一下在VS中編寫動態庫的方法,親測有效。

(1)啟動VS2010》檔案》新建》專案,按下圖進行選擇填寫,選擇Win32控制檯應用程式或Win32專案都可以

本文選擇的是Win32專案----選擇DLL

預編譯頭作用:VS 預設情況下會建立並使用預編譯標頭檔案(也就是自動建立 StdAfx.h 和 StdAfx.cpp 這兩個檔案),以便在編譯時加快編譯速度,預編譯器將它編譯後,會生成一                                     個 Pre-compiled header ,也就是 pch 檔案,這樣下次就可以直接使用這裡已經編譯好了的程式碼了。

建立成功後,在解決方案中找到【標頭檔案】然後右擊選擇【新增】》【新建項】,建立標頭檔案

DLLTest.h

extern "C" _declspec(dllexport) int __stdcall add_a_b_c(int a, int b, int c);
extern "C" _declspec(dllexport) int __stdcall sub_a_b(int a, int b);
//_declspec(dllexport) int __stdcall test1(int a, int b, int c);
//_declspec(dllexport) int __stdcall test2(int a, int b);

/*
注意:__stdcall定義匯出函式入口點呼叫約定為_stdcall
           extern "C"說明匯出函式使用C編譯器,則函式名遵循C編譯器的函式名修飾規則,不加extern "C"說明使用C++編譯器的函式名修飾 規則,兩種規則區別如下:
         (1)C編譯器的函式名修飾規則 
                  對於__stdcall呼叫約定,編譯器和連結器會在輸出函式名前加上一個下劃線字首,函式名後面加上一個“@”符號和其引數的位元組數,例如

[email protected]
                  __cdecl呼叫約定僅在輸出函式名前加上一個下劃線字首,例如_functionname。
                  __fastcall呼叫約定在輸出函式名前加上一個“@”符號,後面也是一個“@”符號和其引數的位元組數,例如@[email protected]
          (2)C++編譯器的函式名修飾規則
                   C++的函式名修飾規則有些複雜,但是資訊更充分,通過分析修飾名不僅能夠知道函式的呼叫方式,返回值型別,甚至引數個數、引數型別。
                   不管__cdecl,__fastcall還是__stdcall呼叫方式,函式修飾都是以一個“?”開始,後面緊跟函式的名字,再後面是引數表的開始標識和按照引數型別代號拼出的引數表。
                   對於__stdcall方式,引數表的開始標識是“@@YG”,
                   對於__cdecl方式則是“@@YA”,
                   對於__fastcall方式則是“@@YI”。
                   引數的具體含義見上篇部落格【VS2015用C++建立的動態庫匯出函式名亂碼原因分析】。
                   */

在DLLTest.cpp寫入如下程式碼:

// DLLTest.cpp : 定義 DLL 應用程式的匯出函式。
//

#include "stdafx.h"
#include "DLLTest.h"

int __stdcall add_a_b_c(int a, int b, int c)
{
    return a+b+c;
}

int __stdcall sub_a_b(int a, int b)
{
    if(a > b)
        return a-b;
    else
        return 0;
}

此時生成的DLL ,通過過depends 工具,打開發現函式名如下:(引圖)

在E列,為C,表示extern “C” 編譯所得; 為C++ 表示採用C++編譯器 編譯所得

但兩種方式下生成的DLL所包含的函式名,有點怪異,(.h標頭檔案的作用僅僅能匯出動態庫、明確編譯連結方式及確定入口點約定,還一個重要作用是打包給開發者,使其瞭解動態庫匯出的函式及對應的的引數)為了看起來正常點,在解決方案中找到【原始檔】右擊選擇【新增】》【新建項】》def檔案

LIBRARY

EXPORTS
add_a_b_c @ 1
sub_a_b @ 2

 

使用def檔案的意義:將編譯器生成的函式修飾去掉,用更加自然、更加容易理解、更加容易記憶的名字來命名函式,而不是一串人一看就嚇一跳的修飾名字

最後專案中包含的檔案如下:

DLLTest.cpp, DLLTest.h, DLLTest.def 

debug 狀態下生成的DLL較大,

Release 狀態下生成的DLL 較小

原因:可能是因為 debug 要呼叫很多檔案,所以較大,而release 則直接生成固化得二進位制碼,需要的東西比較少

 

呼叫上述生成的DLL:

載入這個dll有兩種方法,一種是隱式動態連結,一種是顯示動態連結

隱式動態連結

新建一個win32控制檯程式,生成剛剛寫的dll,將TestDll.lib,TestDll.dll,TestDll.h複製到該控制檯程式的資料夾下,然後新增下面的程式碼

#include "stdafx.h"
#include <iostream>
#include "DLLTest.h"

using namespace std;
#pragma comment(lib, "DLLTest")
int _tmain(int argc, _TCHAR* argv[])
{
    int a, b, c, result;
    a = 1;
    b = 2; 
    c = 3;
    result = add_a_b_c(a, b,c);
    cout << " a = " << a << endl;
    cout << " b = " << b << endl;
    cout << " c = " << c << endl;
    cout << " a + b + c = " << result << endl;
    return 0;
}
 

#pragma comment(lib,”TestDll”)語句表示要連線到TestDll.lib庫,使用隱式動態連結需要指明庫所在的位置(本例中在當前資料夾下),靜態變異也會使可執行檔案的體積變大 
測試結果 

顯示呼叫,參考本文開頭兩個連結