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

C++Builder 呼叫 Delphi VCL 元件:DLL 封裝跨語言互操作實戰

     編輯:VC 教學

背景與痛點

Delphi 擁有龐大的第三方 VCL 元件生態,而 C++Builder 雖共享 VCL 框架,但編譯後的 `.bpl`/`.dcu` 無法直接在 C++ 專案中連結(名稱修飾、例外處理、RTTI 差異)。重寫元件成本高、維護難。本文示範 「Delphi 封裝 DLL → C++Builder 動態載入」 模式,實現非視覺元件的跨語言復用。

架構概覽

+------------------+       C 介面匯出       +------------------+
|  Delphi DLL      |  <------------------->  |  C++Builder EXE  |
|  (VCL 元件實體)  |   純扁平 API            |  (呼叫端)        |
+------------------+                       +------------------+
        ▲                                         ▲
        │  建立/銷毀元件實例                       │  持有 opaque handle
        │  封裝屬性/方法為函數                     │  透過函數指標操作

一、Delphi 端 DLL 製作步驟

1. 建立 DLL 專案

File → New → DLL Project,命名 SampleDLL。

2. 定義元件包裝類別

unit SampleWrap;

interface
uses Classes, SysUtils;

type
  TSampleComp = class(TComponent)
  private
    FActive: Boolean;
    FPro1, FPro2: Integer;
  published
    property Active: Boolean read FActive write FActive;
    property Pro1: Integer read FPro1 write FPro1;
    property Pro2: Integer read FPro2 write FPro2;
  end;

// 匯出函數宣告
function  OpenSample: LongBool; stdcall;
procedure CloseSample; stdcall;
function  GetActive: LongBool; stdcall;
procedure SetActive(Value: LongBool); stdcall;
function  GetPro1: Integer; stdcall;
procedure SetPro1(Value: Integer); stdcall;
function  GetPro2: Integer; stdcall;
procedure SetPro2(Value: Integer); stdcall;

exports
  OpenSample, CloseSample,
  GetActive, SetActive,
  GetPro1, SetPro1,
  GetPro2, SetPro2;

implementation

var
  GInstance: TSampleComp = nil;

function OpenSample: LongBool;
begin
  if GInstance = nil then GInstance := TSampleComp.Create(nil);
  Result := True;
end;

procedure CloseSample;
begin
  FreeAndNil(GInstance);
end;

function GetActive: LongBool; begin Result := GInstance.Active; end;
procedure SetActive(Value: LongBool); begin GInstance.Active := Value; end;
function GetPro1: Integer; begin Result := GInstance.Pro1; end;
procedure SetPro1(Value: Integer); begin GInstance.Pro1 := Value; end;
function GetPro2: Integer; begin Result := GInstance.Pro2; end;
procedure SetPro2(Value: Integer); begin GInstance.Pro2 := Value; end;

end.

3. 編譯產出 SampleDLL.dll 並用 implib 產生 .lib

implib SampleDLL.lib SampleDLL.dll

二、C++Builder 端使用步驟

1. 專案加入 .lib

Project → Add to Project → 選擇 SampleDLL.lib。

2. 宣告外部函數 (Header)

// SampleDLL.h
extern "C" {
    __declspec(dllimport) bool __stdcall OpenSample(void);
    __declspec(dllimport) void __stdcall CloseSample(void);
    __declspec(dllimport) bool __stdcall GetActive(void);
    __declspec(dllimport) void __stdcall SetActive(bool);
    __declspec(dllimport) int  __stdcall GetPro1(void);
    __declspec(dllimport) void __stdcall SetPro1(int);
    __declspec(dllimport) int  __stdcall GetPro2(void);
    __declspec(dllimport) void __stdcall SetPro2(int);
}

3. 呼叫範例

#include "SampleDLL.h"

void __fastcall TForm1::Button1Click(TObject *Sender) {
    if (!OpenSample()) { ShowMessage("DLL 初始化失敗"); return; }

    SetActive(true);
    SetPro1(123);
    SetPro2(456);

    ShowMessage(Format("Active=%d, Pro1=%d, Pro2=%d",
        ARRAYOFCONST((GetActive(), GetPro1(), GetPro2()))));

    CloseSample();
}

三、關鍵技術點與避坑指南

議題解決方案
字串傳遞匯出介面僅用 PAnsiChar/PWideChar + 長度,或 WideString (BStr);避免 AnsiString 跨界
例外處理DLL 內部 try/except 捕獲所有異常,轉為錯誤碼返回;絕不讓 Delphi 例外逃出 DLL
記憶體管理Delphi 端 ShareMem 或統一用 GetMem/FreeMem;C++ 端不直接 delete Delphi 物件
執行緒安全全域實例 GInstance 僅單執行緒適用;多執行緒需改為 TThreadLocal 或連線池模式
視覺元件限制本模式不適用視覺控制項(需 Parent/Handle/訊息迴環);視覺元件請改用 Package (.bpl) 共享 VCL 或 ActiveX/COM 封裝

四、現代替代方案簡評

  • C++Builder 10.4+ Clang 編譯器:支援直接連結 Delphi `.dcu`/`.bpl`(需啟用 Delphi Personality),逐步取代 DLL 封裝。
  • COM / ActiveX:標準化、語言中立、支援視覺元件,但開發門檻較高。
  • REST / gRPC 微服務:跨進程、跨語言、跨網路,適合大型系統解耦。

五、總結

「Delphi DLL + C 介面 + C++Builder 動態載入」是歷史專案快速復用 Delphi 非視覺邏輯的經典捷徑。核心在於 扁平化 API 設計、嚴格例外隔離、明確所有權語義。若專案已遷移至現代 C++Builder 版本,優先評估原生 Delphi Personality 整合,減少維護負擔。

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