| Delphi | C++ | 備註 |
| Integer | int / long | 32 位元有號 |
| Boolean | bool / BOOL | |
| Char / AnsiChar | char | |
| PChar | char* / const char* | 字串指標,注意記憶體歸屬 |
| Double | double | |
| Currency | 無直接對應 | 避免作為共享參數 |
| String | 不可直接共享 | 改用 PChar + 長度參數 |
| Set/Record | 不可直接共享 | 改用結構體/位元遮罩 |
| var 參數 | 參考 (T&) | 輸出/輸入輸出參數 |
| out 參數 | 指標 (T*) | 純輸出參數 |
4. 宣告範例
// C++ 標頭檔
extern "C" int __stdcall AddNumbers(int a, int b);
extern "C" void __stdcall GetString(char* buffer, int maxLen);
// Delphi 單元
function AddNumbers(a, b: Integer): Integer; stdcall;
procedure GetString(buffer: PChar; maxLen: Integer); stdcall;
二、程式碼連結方式
1. 靜態連結(.obj)
- 適用:C++ 程式碼量小、無 C 執行庫相依
- Delphi 單元加入
{$L CppModule.obj} 指令
- 連結階段將 .obj 合併至單一 EXE
// Delphi
function TestFunc: Integer; stdcall; {$L TestFunc.obj}
2. 動態連結(DLL)
- 適用:C++ 程式碼龐大、使用 C RTL、獨立子系統
- C++ 匯出:
__declspec(dllexport) int __stdcall Func()
- Delphi 匯入:
function Func: Integer; stdcall; external 'MyDll.dll';
// C++ DLL
#define EXPORT_API __declspec(dllexport)
EXPORT_API int __stdcall AddNumbers(int a, int b) { return a+b; }
// Delphi
function AddNumbers(a, b: Integer): Integer; stdcall; external 'MathDll.dll';
三、物件共享:介面導向設計
核心原則:共享介面(純虛擬類別),隱藏實作細節。分為物件層級共享(既有實例)與類別層級共享(建立新實例、繼承)。
1. C++ 共享 Delphi 物件
步驟 1:定義共享介面(Delphi 側)
type
// 共享介面:所有方法必須 virtual; abstract; stdcall
ISharedObject = interface
procedure Proc1(x: Integer); stdcall;
function Func1(x: Integer): PChar; stdcall;
procedure Free; stdcall; // 釋放自身
end;
// 實作類別:繼承共享介面
TSharedObject = class(TInterfacedObject, ISharedObject)
procedure Proc1(x: Integer); stdcall;
function Func1(x: Integer): PChar; stdcall;
procedure Free; stdcall;
end;
步驟 2:提供工廠函數(Delphi DLL 匯出)
function CreateSharedObject: ISharedObject; stdcall; export;
begin
Result := TSharedObject.Create;
end;
exports CreateSharedObject;
步驟 3:C++ 端對應宣告與使用
// C++ 介面定義(純虛擬類別)
class ISharedObject {
public:
virtual void __stdcall Proc1(int x) = 0;
virtual char* __stdcall Func1(int x) = 0;
virtual void __stdcall Free() = 0;
virtual ~ISharedObject() {}
};
// 匯入工廠函數
extern "C" ISharedObject* __stdcall CreateSharedObject();
// 使用範例
void UseSharedObject() {
ISharedObject* obj = CreateSharedObject(); // 取得介面指標
obj->Proc1(10);
char* str = obj->Func1(0);
// ...
obj->Free(); // 必須呼叫釋放,不可 delete
}
2. Delphi 共享 C++ 物件
步驟 1:C++ 定義共享介面與實作
// 共享介面
class ISharedObject {
public:
virtual void __stdcall Proc1(int x) = 0;
virtual char* __stdcall Func1(int x) = 0;
virtual void __stdcall Free() = 0;
virtual ~ISharedObject() {}
};
// 實作類別
class TSharedObject : public ISharedObject {
public:
void __stdcall Proc1(int x) override { /* ... */ }
char* __stdcall Func1(int x) override { return "Hello"; }
void __stdcall Free() override { delete this; } // 自刪
};
// 工廠函數匯出
extern "C" __declspec(dllexport) ISharedObject* __stdcall CreateSharedObject() {
return new TSharedObject();
}
步驟 2:Delphi 端宣告與使用
type
ISharedObject = interface
procedure Proc1(x: Integer); stdcall;
function Func1(x: Integer): PChar; stdcall;
procedure Free; stdcall;
end;
function CreateSharedObject: ISharedObject; stdcall; external 'CppDll.dll';
procedure UseIt;
var
Obj: ISharedObject;
begin
Obj := CreateSharedObject;
Obj.Proc1(10);
ShowMessage(Obj.Func1(0));
Obj.Free; // 呼叫釋放
end;
四、關鍵注意事項總結
| 議題 | 規範 |
| 呼叫慣例 | 雙方強制 stdcall |
| C++ 名稱修飾 | 共享函數/工廠函數加 extern "C" |
| 共享介面方法 | 全部 virtual + =0 (C++) / virtual; abstract (Delphi) + stdcall |
| 字串傳遞 | 使用 PChar / char*,明確約定緩衝區大小與記憶體釋放責任 |
| 物件生命週期 | 提供 Free 方法由建立端釋放,嚴禁跨語言 delete/Free |
| 例外處理 | 介面方法不拋出例外,改用錯誤碼或 HRESULT 回傳 |
| VCL 物件共享 | 需在 DLL 中啟用 VCL,並注意 Application 物件同步 |
五、現代替代方案
- COM/ActiveX:標準化二進位介面,支援跨語言、跨進程、參考計數
- C++Builder 封裝為 BPL:執行階段套件,Delphi 可直接引用
- REST/gRPC:跨進程、跨機器、跨語言的服務導向替代方案
- 上一篇文章: C++ Builder 程式自我重啟的簡潔實作方法
- 下一篇文章: C++ Builder 程式設計指南(二):常用元件屬性、事件與實作範例
Copyright ©
程式碼之家 All Rights Reserved