首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

打造可擴充應用程式:使用 DLL 實作外掛架構完整教學

     編輯:關於VC++

前言

現代應用程式常需支援第三方擴充功能(外掛/插件)。本文示範如何設計一套基於 DLL 的外掛架構:定義標準介面、主程式動態載入/管理外掛、外掛實作介面並匯出建立函式,達成「主程式不修改即可新增功能」的目標。

架構設計

  1. 介面定義 (共用標頭檔):純虛擬基底類別,定義外掛必須實作的方法。
  2. 外掛 DLL:實作介面,匯出 Plug_CreateObject 工廠函式。
  3. 主程式:掃描目錄、LoadLibrary/GetProcAddress 載入 DLL、呼叫工廠函式取得介面指標、管理外掛生命週期。

核心程式碼

1. 介面定義 (PlugBase.h)

#pragma once
#include 

class CPlugBase
{
public:
    virtual ~CPlugBase() {}
    // 取得外掛圖示(主程式顯示於工具列/選單)
    virtual HICON GetIcon() = 0;
    // 外掛核心功能
    virtual void Hello(int k) = 0;
    // 釋放資源(主程式卸載時呼叫)
    virtual void Release() = 0;
};

// 外掛工廠函式原型
typedef BOOL (*PFN_CREATE_PLUG)(void** ppObj);

2. 外掛 DLL 實作範例 (MyPlug.cpp)

#include "PlugBase.h"

class CMyPlug : public CPlugBase
{
public:
    HICON GetIcon() override { return LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1)); }
    void Hello(int k) override { MessageBox(NULL, L"Hello from Plug 1!", L"Plug", MB_OK); }
    void Release() override { delete this; }
};

extern "C" __declspec(dllexport) BOOL Plug_CreateObject(void** ppObj)
{
    *ppObj = new CMyPlug();
    return *ppObj != NULL;
}

3. 主程式載入邏輯 (MainApp.cpp)

#include "PlugBase.h"
#include 
#include 
#include 

struct PlugInfo
{
    HMODULE hDll;
    CPlugBase* pPlug;
};

std::vector g_plugs;

BOOL LoadPlug(const wchar_t* dllPath)
{
    HMODULE hDll = LoadLibrary(dllPath);
    if (!hDll) return FALSE;

    auto pfnCreate = (PFN_CREATE_PLUG)GetProcAddress(hDll, "Plug_CreateObject");
    if (!pfnCreate) { FreeLibrary(hDll); return FALSE; }

    void* pObj = nullptr;
    if (!pfnCreate(&pObj) || !pObj) { FreeLibrary(hDll); return FALSE; }

    CPlugBase* pPlug = static_cast(pObj);
    g_plugs.push_back({ hDll, pPlug });
    return TRUE;
}

void UnloadAllPlugs()
{
    for (auto& info : g_plugs)
    {
        if (info.pPlug) info.pPlug->Release();
        if (info.hDll) FreeLibrary(info.hDll);
    }
    g_plugs.clear();
}

// 介面調用範例
void InvokePlugHello(int index, int param)
{
    if (index >= 0 && index < g_plugs.size() && g_plugs[index].pPlug)
        g_plugs[index].pPlug->Hello(param);
}

持久化外掛清單

主程式啟動時讀取設定檔(Registry/INI/JSON),載入記錄的 DLL 路徑;使用者透過 UI 新增外掛時,將路徑寫入設定檔,下次自動載入。

進階議題

主題說明
版本相容介面加入版本號,Plug_CreateObject 回傳版本資訊,主程式檢查相容性。
錯誤處理載入失敗時記錄日誌、顯示友善訊息、不讓單一外掛 crash 整個主程式(可考慮隔離進程)。
資源管理外掛自行管理 GDI 物件、執行緒、記憶體,Release() 確保清理。
安全性簽章驗證 DLL、沙箱機制、限制外掛權限。
跨語言介面改用 C 風格函式指標或 COM,支援 C#、Python 等語言撰寫外掛。

建置與測試環境

  • VC6 + SP5 + Platform SDK 2001.11 (原文環境)
  • 現代環境:Visual Studio 2019/2022,目標 Windows 10/11,相同原理適用。

總結

DLL 外掛架構核心在於介面契約與動態載入。主程式僅依賴抽象介面,外掛獨立編譯部署,實現開放封閉原則(OCP)。掌握此模式,即可為應用程式賦予無限擴充潛力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved