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

DLL 資源存取完全指南:LoadLibrary 取得模組代碼,輕鬆讀取位圖、圖示、選單、字串與對話框

     編輯:組合語言

核心概念:模組代碼 (HINSTANCE) 是鑰匙

所有資源載入 API (LoadBitmap, LoadIcon, LoadMenu, LoadString, DialogBoxParam, CreateDialogParam) 的**第一個參數都是 HINSTANCE hInstance** —— 包含資源的模組代碼。

  • 載入**自身**資源:invoke GetModuleHandle, NULL 取得當前 EXE/DLL 代碼。
  • 載入**外部 DLL** 資源:invoke LoadLibrary, "MyRes.dll" 返回值即為該 DLL 的 HINSTANCE。

一行代碼切換語言包:主程式邏輯不變,LoadLibrary("LangCHT.dll") vs LoadLibrary("LangENU.dll"),後續所有 LoadString/DialogBoxParam 傳入對應代碼即可。

常用資源載入 API 速查

API用途關鍵參數
LoadBitmap(hInst, lpBitmapName)載入位圖資源返回 HBITMAP
LoadIcon(hInst, lpIconName)載入圖示資源返回 HICON
LoadMenu(hInst, lpMenuName)載入選單資源返回 HMENU
LoadString(hInst, uID, lpBuffer, cchBufferMax)載入字串表項目返回複製字元數
DialogBoxParam(hInst, lpTemplate, hWndParent, lpDialogFunc, dwInitParam)建立**模態**對話框需對話框模板資源 ID、回呼程序
CreateDialogParam(hInst, lpTemplate, hWndParent, lpDialogFunc, dwInitParam)建立**非模態**對話框返回 HWND,需訊息迴圈 IsDialogMessage

實作模式:取得 DLL 代碼 -> 載入資源

invoke LoadLibrary, DLL_FILENAME
mov DLL_HANDLE, eax

invoke LoadBitmap, DLL_HANDLE, BITMAP_ID
invoke LoadIcon, DLL_HANDLE, ICON_ID
invoke LoadMenu, DLL_HANDLE, MENU_ID
invoke LoadString, DLL_HANDLE, STRING_ID, addr StrBuffer, sizeof StrBuffer
invoke DialogBoxParam, DLL_HANDLE, DLG_NAME, hParent, DlgProc, lParam

難點突破:對話框回呼程序 (DlgProc) 放在哪裡?

錯誤示範:回呼寫在主程式 (EXE)

; EXE 代碼
DlgProc proc hWnd, uMsg, wParam, lParam
    ; 處理對話框訊息...
    ret
DlgProc endp

; 呼叫 DLL 對話框
invoke DialogBoxParam, DLL_HANDLE, DLG_ID, hWnd, offset DlgProc, 0

問題:若 DLL 是**外掛/擴充模組**,主程式不知其內部邏輯;DLL 更新時主程式需重新編譯;多 DLL 時主程式膨脹。

正確架構:回呼寫在 DLL 內部,導出「啟動器」函式

原則:純資源 DLL (只換文字/圖片) 可共用主程式回呼;**功能性 DLL/外掛,回呼必須內建於 DLL**。

DLL 內部實作 (MyResDll.asm)

; --- 導出函式:LoadDialog ---
LoadDialog proc hInstance:DWORD, hWnd:DWORD, ID:DWORD
    .if ID == 100
        mov eax, offset DlgProc0
    .elseif ID == 101
        mov eax, offset DlgProc1
    .elseif ID == 102
        mov eax, offset DlgProc2
    .elseif ID == 103
        mov eax, offset DlgProc3
    .endif
    invoke DialogBoxParam, hInstance, ID, hWnd, eax, NULL
    ret
LoadDialog endp

; --- 內建回呼程序 ---
DlgProc0 proc ... ; 對話框 100 邏輯 ... ret; endp
DlgProc1 proc ... ; 對話框 101 邏輯 ... ret; endp
DlgProc2 proc ... ; 對話框 102 邏輯 ... ret; endp
DlgProc3 proc ... ; 對話框 103 邏輯 ... ret; endp

模組定義檔導出

EXPORTS
    LoadDialog

主程式呼叫方式 (極簡潔)

; 初始化:只需取得一次 LoadDialog 位址
invoke GetProcAddress, DLL_HANDLE, "LoadDialog"
mov pLoadDialog, eax

; 任意位置需要彈出對話框 101:
push 101
push hWnd
push DLL_HANDLE
call [pLoadDialog]

; 需要對話框 102:
push 102
push hWnd
push DLL_HANDLE
call [pLoadDialog]

優勢總結

方案回呼位置導出需求主程式複雜度適用場景
傳統EXE無 (直接呼叫)高 (每個對話框需知回呼位址)純資源切換 (多語言)
GetProcAddress 每次查DLL每個 DlgProc 皆需導出中 (重複呼叫 GetProcAddress)少量對話框
封裝 LoadDialog (推薦)DLL僅導出 LoadDialog低 (統一入口,ID 驅動)外掛、多對話框、功能性 DLL

資源釋放提醒

  • LoadBitmap/LoadIcon/LoadMenu 返回的代碼,**程式結束前必須呼叫對應 DeleteObject/DestroyIcon/DestroyMenu 釋放**,否則 GDI/USER 物件洩漏。
  • DialogBoxParam 模態對話框結束時自動銷毀內部資源。
  • CreateDialogParam 非模態對話框需自行 DestroyWindow。
  • LoadLibrary 增加參考計數,配對 FreeLibrary 釋放 DLL (資源隨之卸載)。

進階:延遲載入與錯誤處理

invoke LoadLibrary, "Plugin.dll"
.if eax == NULL
    invoke MessageBox, hWnd, "載入外掛失敗!", "錯誤", MB_ICONERROR
    jmp ExitApp
.endif
mov hPlugin, eax
; ... 後續使用 ...
invoke FreeLibrary, hPlugin
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved