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

C++Builder 調用 Delphi VCL 控件:封裝為 DLL 動態庫的完整實踐指南

     編輯:Delphi

前言

C++Builder 與 Delphi 共享 VCL 庫,但直接在 C++ 專案中使用 Delphi 編寫的控件(特別是非可視組件)常遇到鏈接與 RTL 兼容問題。成熟方案是將 Delphi 控件封裝為標準 DLL,C++Builder 通過 implib 生成 .lib 靜態導入庫進行動態調用。本文完整演示從 Delphi 建立 DLL 到 C++Builder 調用的全流程。

架構原理

  1. Delphi 建立 DLL 專案,導出 stdcall 慣例的 C 風格函數(OpenSample、CloseSample、屬性存取函數)。
  2. DLL 內部建立一個繼承自 TComponent 的臨時擁有者類(TTempcomp),解決 VCL 控件需 AOwner 的構造需求。
  3. C++Builder 使用 implib.exe 將 DLL 轉為 .lib,專案加入 .lib,頭文件聲明 extern "C" __declspec(dllimport) 函數原型。

Delphi DLL 端完整代碼

library SampleDLL;

uses
  SysUtils, Classes, Sample; {Sample 為原有控件單元}

type
  {臨時擁有者類,僅提供構造函數}
  TTempcomp = class(TComponent)
  public
    constructor Create1;
  end;

var
  Sample1: TSample;     {原控件實例}
  SaveExit: Pointer;    {保存原 ExitProc}
  temp1: TTempcomp;     {臨時擁有者實例}

constructor TTempcomp.Create1;
begin
  {不調用 inherited Create,避免引入額外依賴}
end;

{=== 導出函數 ===}
function OpenSample: Boolean; stdcall; export;
begin
  {由臨時擁有者建立控件實例}
  Sample1 := TSample.Create(temp1);
  Result := Sample1.Actived; {假設 Actived 為 Boolean 屬性}
end;

procedure CloseSample; stdcall; export;
begin
  Sample1.Free;
end;

function Actived: Boolean; stdcall; export;
begin
  Result := Sample1.Actived;
end;

function Pro1: Integer; stdcall; export;
begin
  Result := Sample1.Pro1;
end;

function Pro2: Integer; stdcall; export;
begin
  Result := Sample1.Pro2;
end;

{=== DLL 入口/退出處理 ===}
procedure libexit; far;
begin
  if Sample1.Actived then
    Sample1.Free;
  ExitProc := SaveExit;
  temp1.Free;
end;

exports
  OpenSample, CloseSample, Actived, Pro1, Pro2;

begin
  temp1 := TTempcomp.Create1;
  SaveExit := ExitProc;
  ExitProc := @libexit;
end.

C++Builder 調用端代碼

1. 生成導入庫

{命令行}
implib SampleDLL.lib SampleDLL.dll
將生成的 SampleDLL.lib 加入 C++Builder 專案(Project → Add to Project)。

2. 頭文件聲明

// SampleDLL.h
extern "C" __declspec(dllimport) bool __stdcall OpenSample(void);
extern "C" __declspec(dllimport) void __stdcall CloseSample(void);
extern "C" __declspec(dllimport) bool __stdcall Actived(void);
extern "C" __declspec(dllimport) int __stdcall Pro1(void);
extern "C" __declspec(dllimport) int __stdcall Pro2(void);

3. 實際調用

#include "SampleDLL.h"

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  if (OpenSample()) {
    bool a = Actived();
    int p1 = Pro1();
    int p2 = Pro2();
    ShowMessage("Delphi 控件屬性讀取成功");
  }
  CloseSample();
}

關鍵技術細節解析

  • 為何需要 TTempcomp? VCL 控件構造函數 constructor Create(AOwner: TComponent) 強制要求擁有者。DLL 無法直接使用 Application(會導致體積膨脹),故建立極簡擁有者類。
  • stdcall 呼叫慣例:確保 C/C++、Delphi、VB 等語言互調用的二進制兼容性。
  • export / __declspec(dllexport):Delphi 用 export,C++ 用 __declspec(dllexport)(構建 DLL 時)與 __declspec(dllimport)(調用時)。
  • ExitProc 掛鉤:保證 DLL 卸載時正確釋放控件與臨時擁有者,防止記憶體洩漏。
  • 適用範圍:僅限非可視控件(TComponent 子類)。可視控件(TControl)涉及視窗句柄、消息泵、父子視窗關係,跨模組極其複雜,不建議此法。

替代方案對比

方案優點缺點適用場景
DLL 封裝 (本文)語言無關、部署獨立、非可視組件完美需手寫導出包裝、可視控件不適用工具類、算法、數據處理組件
C++Builder 直接引用 .pas無包裝層、原生調用RTL 版本強綁定、名稱修飾問題、調試困難同版本 RAD Studio 專案組
COM/ActiveX 封裝標準化、跨進程、語言無關開發複雜、註冊部署、效能開銷企業級組件、跨進程調用
Package (BPL/Runtime Package)共享 VCL RTL、設計時支援版本強綁定、僅限 Delphi/C++Builder 同版本團隊內部組件庫共享

總結

將 Delphi 非可視 VCL 控件封裝為標準 DLL,配合 implib 生成導入庫,是 C++Builder 跨語言復用 Delphi 組件最輕量、穩健的方案。關鍵在於臨時擁有者類解決構造依賴、stdcall 確保二進制兼容、ExitProc 保證資源釋放。

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