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

Windows 動態連結庫 (DLL) 核心原理與進階應用:跨進程數據共享與表單重用

     編輯:關於C++

3 利用 DLL 實現高效數據傳輸

3.1 DLL 中的全域記憶體管理機制

在 Windows 架構下,DLL 本身不擁有其開啟的文件句柄,也不擁有其分配的全域記憶體塊。這些資源的所有權歸屬於直接或間接調用該 DLL 的應用程式進程。當宿主應用程式終止時,系統會自動關閉其擁有的文件並釋放全域記憶體。這意味著若將文件句柄或全域記憶體句柄作為 DLL 的全域變量保存,一旦宿主進程退出,這些變量在 DLL 內部會瞬間變為非法狀態,導致其他正在使用該 DLL 的應用程式發生錯誤。

為避免此問題,最佳實踐是將文件句柄和全域記憶體句柄作為參數傳遞給 DLL 導出函數,由調用方負責其生命週期管理。但在特定場景下,DLL 確需擁有獨立的全域記憶體以實現進程間通訊(IPC)。此時必須使用 GMEM_DDESHARE 屬性分配記憶體,該記憶體塊將持續有效,直到 DLL 顯式釋放或 DLL 卸載為止。這種由 DLL 管理的共享全域記憶體,正是實現應用程式間數據傳輸的關鍵通道。

3.2 基於共享記憶體的應用程式間數據交換實戰

實現步驟如下:

  1. 編寫一個 DLL,在初始化時分配一塊帶 GMEM_DDESHARE 標志的全域記憶體。
  2. 服務端(生產者)調用 DLL 導出函數,獲取記憶體句柄並寫入數據。
  3. 客戶端(消費者)同樣調用 DLL 獲取句柄,從共享記憶體讀取數據。

3.2.1 共享記憶體 DLL 核心代碼實現

該 DLL 需導出一個函數返回全域記憶體句柄,並在 DLL 進程附加時分配記憶體:

var
  hMem: THandle;

function GetGlobalMem: THandle; export;
begin
  Result := hMem;
end;

begin
  const BufferSize = 4096; // 預定義常數
  hMem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, BufferSize);
  if hMem = 0 then
    MessageDlg('Could not allocate shared memory', mtWarning, [mbOK], 0);
end.

GlobalAlloc 的分配標志組合 GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT 確保記憶體可移動、可跨進程共享且初始化為零。值得注意的是,帶 GMEM_DDESHARE 的記憶體在擁有模塊卸載時會自動釋放,無需顯式調用 GlobalFree。

3.2.2 服務端寫入數據邏輯

服務端需鎖定記憶體獲取指針,寫入後立即解鎖:

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;

3.2.3 客戶端讀取數據邏輯

客戶端代碼幾乎鏡像服務端,僅將寫入操作改為讀取:

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;

4 利用 DLL 實現表單重用:跨語言 UI 組件封裝

Delphi DLL 支持將設計好的表單封裝為可重用組件,這是其獨特優勢。封裝後的表單不僅可在 Delphi 專案中復用,更可被 C++Builder、Visual Basic 等異構語言直接調用。單個包含表單的 DLL 約帶 100KB VCL 運行庫開銷,將多個表單編譯進同一 DLL 可最大化共享此開銷。

4.1 表單重用 DLL 開發標準流程

  1. 在 IDE 中設計目標表單及其邏輯代碼。
  2. 編寫導出函數/過程,在其中實例化並顯示表單(通常使用 ShowModal)。
  3. 修改專案文件:將 program 改為 library;移除 uses 中的 Forms 單元;清空 begin...end 主程式碼塊;添加 exports 子句導出函數名。
  4. 編譯生成 .dll 文件。
  5. 在目標應用程式中通過靜態或動態鏈接調用導出函數。

4.2 實戰案例:密碼設置與驗證表單庫

本案例構建 PassForm.dll,包含兩個表單:TSetPassWordForm(密碼設置)與 TGetPassWordForm(密碼驗證),並分別導出 SetPassWord、GetPassWord 函數。

4.2.1 核心表單類設計

type
  TSetPassWordForm = class(TForm)
    Label1: TLabel;
    Edit1: TEdit;
    OKBtn, CancelBtn: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
  private
    Verified: Boolean;
  public
    PassWord: PChar;
  end;

FormCreate 初始化狀態,禁用確定按鈕直到雙次輸入一致。Edit1KeyPress 處理雙重驗證邏輯:首次回車記錄密碼並提示確認,二次回車比對通過後啟用確定按鈕。

4.2.2 導出函數實現

function SetPassWord(PWord: PChar): Boolean;
var
  SetPassWordForm: TSetPassWordForm;
begin
  Result := False;
  SetPassWordForm := TSetPassWordForm.Create(Application);
  try
    with SetPassWordForm do
      if ShowModal = mrOK then
      begin
        StrCopy(PWord, StrUpper(PassWord));
        Result := True;
      end;
  finally
    SetPassWordForm.Free;
  end;
end;

function GetPassWord(Password: PChar): Boolean;
var
  GetPasswordForm: TGetPassWordForm;
begin
  Result := False;
  GetPasswordForm := TGetPassWordForm.Create(Application);
  try
    with GetPasswordForm do
      if ShowModal = mrOK then
        if UpperCase(Edit1.Text) = StrPas(StrUpper(Password)) then
          Result := True
        else
          MessageDlg('Invalid Password', mtWarning, [mbOK], 0);
  finally
    GetPasswordForm.Free;
  end;
end;

專案文件導出聲明:

library PassForm;
uses
  GetPass in 'GETPASS.PAS' {PasswordForm},
  Setpass in 'SETPASS.PAS' {SetPassWordForm};
exports
  GetPassword, SetPassWord;
begin
end.

4.2.3 異構語言調用示例

Delphi 調用: 在 implementation 區聲明 external 'c:\dlls\PassForm',按鈕事件中分配緩衝區調用導出函數。

Visual Basic 6.0 調用: 使用 Declare Function 引入 DLL,參數類型映射為 ByVal ... As String,邏輯與 Delphi 版本完全對應,驗證了 DLL 的跨語言通用性。

4.3 小結

動態連結庫是 Windows 程式模組化的基石。Delphi 在 DLL 開發上提供了極具生產力的表單重用機制,配合其語言無關的二進制兼容性,使開發者能構建跨工具、跨時期的組件資產庫,大幅提升軟體工程的復用效率與維護性。

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