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

C++Builder 建立與使用 DLL 完全指南:靜態連結、動態載入與專案設定

     編輯:關於C++

動態連結庫(DLL)是 Windows 程式設計實現模組化、程式碼重用、跨語言互操作的核心機制。本文針對 C++Builder 環境,系統說明 DLL 專案建立、匯出函數宣告、呼叫慣例選擇、靜態連結(Import Library)與動態載入(LoadLibrary/GetProcAddress) 兩種使用方式,並釐清專案選項對執行階段套件相依性的影響。

一、建立 DLL 專案

  1. File → New → DLL Wizard,產生最小框架:
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) {
    return 1; // TRUE 表示初始化成功
}
//---------------------------------------------------------------------------
// 使用者自訂匯出函數寫在這裡
  1. 匯出函數宣告:採用 extern "C" __declspec(dllexport) 防止 C++ 名稱修飾,並明確指定呼叫慣例。
// MyDll.h
#ifdef MYDLL_EXPORTS
#define MYDLL_API extern "C" __declspec(dllexport)
#else
#define MYDLL_API extern "C" __declspec(dllimport)
#endif

MYDLL_API int __stdcall Add(int a, int b);
MYDLL_API void __stdcall GetVersion(char* buf, int len);

// MyDll.cpp
#include "MyDll.h"
MYDLL_API int __stdcall Add(int a, int b) { return a + b; }
MYDLL_API void __stdcall GetVersion(char* buf, int len) {
    strncpy(buf, "1.0.0", len); buf[len-1] = '\0';
}

呼叫慣例對照表

關鍵字參數傳遞堆疊清理適用場景
__cdecl右向左壓棧呼叫者C/C++ 預設、可變參數
__stdcall右向左壓棧被呼叫者Win32 API、COM、跨語言(VB、C#、Delphi)
__fastcall前兩參數用暫存器 (EAX, EDX)被呼叫者Borland 內部優化、非公開介面
__pascal左向右壓棧被呼叫者舊版 Windows API、已淘汰

建議:公開介面統一使用 __stdcall 確保跨編譯器/語言相容。

二、專案選項:消除執行階段套件相依

預設專案會連結動態 RTL 與執行階段套件,導致 DLL 必須部署 rtlxx.bpl、vclxx.bpl 等巨大檔案。必須關閉:

  • Project → Options → Packages:取消勾選 Build with runtime packages
  • Project → Options → Linker:取消勾選 Use dynamic RTL

編譯後產出獨立 MyDll.dll + MyDll.lib(Import Library),單檔部署零相依。

三、使用方式一:靜態連結(Import Library)

  1. 專案管理器 Add → 選擇 MyDll.lib
  2. 主程式包含 MyDll.h(或手寫 dllimport 宣告)
  3. 直接呼叫:int sum = Add(3, 5);

優點:語法簡潔、編譯期型別檢查、除錯支援完整。缺點:啟動時必須找到 DLL,否則載入失敗。

四、使用方式二:動態載入(Run-time Dynamic Linking)

typedef int (__stdcall *PFN_Add)(int, int);
typedef void (__stdcall *PFN_GetVersion)(char*, int);

HINSTANCE hDll = LoadLibrary(_T("MyDll.dll"));
if (!hDll) { ShowMessage("載入失敗"); return; }

PFN_Add pAdd = (PFN_Add)GetProcAddress(hDll, "Add");
PFN_GetVersion pVer = (PFN_GetVersion)GetProcAddress(hDll, "GetVersion");

if (pAdd && pVer) {
    int sum = pAdd(10, 20);
    char ver[32]; pVer(ver, sizeof(ver));
    ShowMessage(AnsiString("Sum=") + sum + ", Ver=" + ver);
}
FreeLibrary(hDll);

優點:可延遲載入、支援外掛架構、DLL 不存在不會阻塞主程式啟動。缺點:需手寫函數指標、失去編譯期檢查、錯誤易發生於拼字。

五、輔助工具:implib 與 tlib

  • 若只有 .dll 無 .lib:implib MyDll.lib MyDll.dll 產生 Import Library
  • 列出 DLL 匯出符號:tdump -oi MyDll.dll 或 tlib MyDll.lib, MyDll.lst

六、常見問題與最佳實踐

七、總結

C++Builder 開發 DLL 核心在於:專案選項關閉動態 RTL/套件、統一 extern "C" __stdcall 匯出、視部署需求選擇靜態/動態載入。掌握這三點,即可輕鬆構建高相容、易部署的原生模組。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因對策
Linker 錯誤 "Unresolved external"未加入 .lib 或宣告與定義呼叫慣例不符檢查專案管理器、統一 __stdcall
執行期 "Entry Point Not Found"C++ 名稱修飾導致匯出名稱不符強制 extern "C"、用 tdump 驗證匯出名
跨 DLL 記憶體管理崩潰各自擁有獨立堆疊,new/delete 不可跨界提供 DllFreeMem 或使用共用記憶體管理器
VCL 物件跨 DLL 傳遞類別身分識別依賴 RTTI,動態套件模式下才安全介面傳遞 HWND/HANDLE/POD 結構,避免傳 VCL 物件