動態連結庫(DLL)在 Delphi 中不僅能封裝函式,更可作為進程間通訊(IPC)的共享記憶體容器,並能承載完整的視窗元件實現跨語言窗體重用。本文涵蓋兩大核心主題:利用 GMEM_DDESHARE 全域記憶體實現應用程式間資料交換,以及窗體重用機制的架構優勢。
Windows 規定:DLL **不擁有** 其開啟的檔案或分配的全域記憶體塊,這些資源屬於**直接或間接呼叫 DLL 的應用程式**。應用程式結束時,系統自動釋放其擁有的資源。因此,檔案句柄與全域記憶體句柄**不應作為 DLL 全域變數**,而應透過函式參數傳遞,由呼叫端應用程式負責生命週期管理。
特例:若 DLL 需持有獨立全域記憶體,必須使用 GMEM_DDESHARE 標旗分配,此類記憶體直到 DLL 顯式釋放或卸載時才失效。
GMEM_MOVEABLE and GMEM_DDESHARE 分配的全域記憶體塊;var hMem: THandle;
function GetGlobalMem: THandle; export;
begin Result := hMem; end;
begin
hMem := GlobalAlloc(GMEM_MOVEABLE and GMEM_DDESHARE, Num);
if hMem = 0 then MessageDlg('Could not allocate memory', mtWarning, [mbOK], 0);
end.
GlobalAlloc 參數詳解:
GMEM_DDESHARE:可跨進程共享(關鍵)。GMEM_MOVEABLE:可移動記憶體(需配合 GlobalLock/Unlock)。GHND = GMEM_MOVEABLE and GMEM_ZEROINIT。分配位元組數必須為 32 的倍數;GMEM_DDESHARE 記憶體無需呼叫 GlobalFree,DLL 卸載時自動釋放。
var hMem: THandle; pMem: PChar;
begin
hMem := GetGlobalMem;
if hMem <> 0 then begin
pMem := GlobalLock(hMem);
if pMem <> nil then begin
StrPCopy(pMem, Memo1.Text); // 寫入
GlobalUnlock(hMem); // 盡早解鎖
end else MessageDlg('Could not Lock memory block', mtWarning, [mbOK], 0);
end;
end;
var hMem: THandle; pMem: PChar;
begin
hMem := GetGlobalMem;
if hMem <> 0 then begin
pMem := GlobalLock(hMem);
if pMem <> nil then begin
Memo1.Text := StrPas(pMem); // 讀取
GlobalUnlock(hMem);
end else MessageDlg('Could not Lock memory block', mtWarning, [mbOK], 0);
end;
end;
核心模式:**Lock → 存取 → Unlock**,且盡早解鎖以利系統記憶體管理。
當需要在不同應用(甚至非 Delphi 應用如 C++、VB)中復用同一個精心設計的窗體時,將其封裝進 DLL 是最佳選擇。
下一章將詳細演示窗體重用 DLL 的完整設計步驟與雙語言(Delphi/VB)呼叫實戰代碼。