C++ dll動態程式庫建置架構筆記(CMake build) -2 如何使用dll程式
這篇介紹如何讀取及使用 C++ 動態程式庫。
我的系統環境:
- Win10
- CMake 3.18.4
- VisualStudio 2019
一、介紹做法
我所知道的有兩種做法:
1.需要header、lib檔
    優點:程式碼較少、不用重寫定義
    缺點:還不知道
2.只需要dll檔
    優點:可在程式執行中期匯入及釋放
      缺點:程式碼較繁瑣、使用的人要知道 dll 裡面的 function 名稱及參數架構
二、說明
作法一、需要header、lib檔
  需要 include
  dll 程式提供給外部使用的 function 定義檔,也就是有加 __declspec(dllexport) 的部分。
  以下是使用上一篇文章所做出來的 dll 程式。
test.cpp
#include <stdio.h>
#include "my_math.h"
int main()
{
    int a = 10;
    int b = 20;
    int res = Add(a,b);
    printf("Add %d\n", res);
    res = Subtraction(a,b);
    printf("Subtraction %d\n", res);
    res = Multiply(a,b);
    printf("Multiply %d\n", res);
    math_class math_cls;
    res = math_cls.Add(a,b);
    printf("math_class Add %d\n", res);
    res = math_cls.Subtraction(a,b);
    printf("math_class Subtraction %d\n", res);
    
    res = math_cls.Multiply(a,b);
    printf("math_class Multiply %d\n", res);
    return 0;
}
CMakeLists.txt
set (THE_MODULE "Dll_1Layer_main")
set (Lib_project "Dll_1Layer_math") # connect Dll_1Layer_math.lib
# include header
INCLUDE_DIRECTORIES(../math/include)
# output Dll_1Layer_main.exe
ADD_EXECUTABLE(${THE_MODULE} test.cpp)
TARGET_LINK_LIBRARIES(${THE_MODULE} ${Lib_project})
TARGET_LINK_LIBRARIES(${THE_MODULE} ${Lib_project})
這行的意思是告訴 CMake 連接 dll 專案"Dll_1Layer_math"。
作法二、只需要dll檔
  這個做法使用 LoadLibraryA()
  匯入 dll 檔,要先定義好 dll 裡面 function 架構,大小寫都不能錯,再讀入這個 function 的 memory
  address,之後才能使用這個 function。
  這個做法使用完要釋放掉,有個優點,能在程式執行中釋放掉 dll 程式,不暫記憶體,但是寫起來很痛苦,程式碼很多。
舉例如下:
function 架構: typedef int(*Add)(int a, int b);
function 架構: typedef int(*Add)(int a, int b);
讀入 memory address:add = (Add)GetProcAddress(hLib, "Add");
釋放掉 dll 程式:FreeLibrary(hLib);
test_withoutLib.cpp
#include <stdio.h>
#include <windows.h>
struct My_math_dll
{
private:
    HMODULE hLib;
    bool enable = false;
public:
    //定義每個 function 原始的架構
    typedef int(*Add)(int a, int b);
    typedef int(*Subtraction)(int a, int b);
    typedef int(*Multiply)(int a, int b);
    typedef int(*Divided)(int a, int b);
    typedef int(*Squared)(int a, int b);
    //宣告 function 在這邊使用時的名稱
    Add add;
    Subtraction subtraction;
    Multiply multiply;
    Divided divided;
    Squared squared;
    ~My_math_dll()
    {
        release();
    }
    int loadAPI()
    {
        // 讀入 dll
        hLib = LoadLibraryA("Dll_1Layer_math.dll");
        
        // If the dll file fails, the memory address will be 0.
        printf_s("Dll_1Layer_math.dll address:%p\n", hLib);
        if (!hLib)
        { 
            printf_s("load Dll_1Layer_math.dll fail!\n");
            return 0;
        }
        // 將每個 function 的 address 讀入
        add = (Add)GetProcAddress(hLib, "Add");
        subtraction = (Subtraction)GetProcAddress(hLib, "Subtraction");
        multiply = (Multiply)GetProcAddress(hLib, "Multiply");
        divided = (Divided)GetProcAddress(hLib, "Divided");
        squared = (Squared)GetProcAddress(hLib, "Squared");
        // Check the memory address obtained by the function API.
        // If the function API fails, the memory address will be 0.
        printf_s("API address: %p %p\n", add, subtraction);
        enable = true;
        return 0;
    }
    void release()
    {
        if (enable)
        {
            FreeLibrary(hLib);
            enable = false;
        }
    }
};
int main()
{
    My_math_dll mydll;
    mydll.loadAPI();
    int a = 10;
    int b = 20;
    int res = mydll.add(a,b);
    printf("Add %d\n", res);
    res = mydll.subtraction(a,b);
    printf("Subtraction %d\n", res);
    res = mydll.multiply(a,b);
    printf("Multiply %d\n", res);
    return 0;
}
CMakeLists.txt
set (THE_MODULE "Dll_1Layer_main_withoutLib")
# output Dll_1Layer_main_withoutLib.exe
ADD_EXECUTABLE(${THE_MODULE} test_withoutLib.cpp)
這就不用連接dll,因為要等程式執行到 LoadLibraryA() 才會匯入dll檔
留言
張貼留言