將圖示、游標、位圖、聲音、自訂資料等資源編譯進執行檔,可實現單一檔案部署、防止資源遺失、提升載入速度。本文詳細說明 C++Builder 中 .rc 資源腳本撰寫、BRCC32 編譯、專案連結、以及運行時載入各類資源的標準 API 用法。
建立純文字檔 MyRes.rc,格式:
# 資源名稱/ID 資源類型 檔案路徑
MyAppIcon ICON "Res\\App.ico"
CursorZoomIn CURSOR "Res\\ZoomIn.cur"
CursorZoomOut CURSOR "Res\\ZoomOut.cur"
BmpPrintType BITMAP "Res\\PrintType.bmp"
BmpArrowUp BITMAP "Res\\ArrowUp.bmp"
BmpArrowDown BITMAP "Res\\ArrowDown.bmp"
SndHint WAVE "Res\\Hint.wav"
ExeUnzip RCDATA "Res\\Unzip.exe" # 自訂二進位資料用 RCDATA
101)ICON, CURSOR, BITMAP, WAVE, RCDATA, RT_RCDATA 等
# 命令列
BRCC32 MyRes.rc
# 輸出 MyRes.res
# BRCC32 位於 $(BCB)\Bin\
# 也可在 IDE: Project → Add to Project 直接加入 .rc,IDE 自動調用 BRCC32
// 主專案 .cpp (如 Main.cpp)
#include
#pragma hdrstop
USERES("MyRes.res"); // 連結資源檔
// 或
#pragma resource "MyRes.res"
#pragma package(smart_init)
// Unit1.cpp
#pragma resource "*.dfm"
#pragma resource "MyRes.res" // 額外連結
// 或
#pragma package(smart_init)
Graphics::TBitmap* bmp = new Graphics::TBitmap();
bmp->LoadFromResourceName((unsigned)HInstance, "BmpPrintType");
// 使用: Canvas->Draw(x, y, bmp); 或 Image1->Picture->Assign(bmp);
delete bmp;
#include // 需連結 winmm.lib
#pragma comment(lib, "winmm.lib")
// 同步播放 (阻塞)
PlaySound("SndHint", HInstance, SND_RESOURCE | SND_SYNC);
// 非同步播放 (不阻塞)
PlaySound("SndHint", HInstance, SND_RESOURCE | SND_ASYNC);
// 停止播放
PlaySound(NULL, 0, 0);
// 定義自訂游標常數 (避開系統負數常數)
const TCursor crZoomIn = 100;
const TCursor crZoomOut = 101;
// 載入並註冊
Screen->Cursors[crZoomIn] = LoadCursor(HInstance, "CursorZoomIn");
Screen->Cursors[crZoomOut] = LoadCursor(HInstance, "CursorZoomOut");
// 套用至控件
PaintBox1->Cursor = crZoomIn;
Application->ProcessMessages(); // 確保立即生效
// 載入圖示控制代碼
HICON hIcon = LoadIcon(HInstance, "MyAppIcon");
// 或指定尺寸
HICON hIconLarge = LoadImage(HInstance, "MyAppIcon", IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
HICON hIconSmall = LoadImage(HInstance, "MyAppIcon", IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
// 設定表單/應用程式圖示
Form1->Icon->Handle = hIcon; // 表單標題列
Application->Icon->Handle = hIcon; // 工作列/切換視窗
HRSRC hRes = FindResource(HInstance, "ExeUnzip", RT_RCDATA);
if (hRes)
{
HGLOBAL hGlob = LoadResource(HInstance, hRes);
DWORD size = SizeofResource(HInstance, hRes);
LPVOID pData = LockResource(hGlob);
// 寫入暫存檔執行
char tempPath[MAX_PATH];
GetTempPath(MAX_PATH, tempPath);
strcat(tempPath, "unzip.exe");
HANDLE hFile = CreateFile(tempPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
DWORD written;
WriteFile(hFile, pData, size, &written, NULL);
CloseHandle(hFile);
// 執行...
// 結束後刪除
DeleteFile(tempPath);
}
| 資源類型 | 載入 API | VCL 封裝 | 常用旗標 |
|---|---|---|---|
| ICON | LoadIcon, LoadImage | TIcon::LoadFromResourceName | LR_DEFAULTSIZE, LR_DEFAULTCOLOR |
| CURSOR | LoadCursor, LoadImage | Screen->Cursors[] | LR_DEFAULTSIZE |
| BITMAP | LoadBitmap, LoadImage | TBitmap::LoadFromResourceName | LR_CREATEDIBSECTION |
| WAVE | PlaySound | 無 (直接 API) | SND_RESOURCE, SND_ASYNC, SND_LOOP |
| RCDATA | FindResource, LoadResource, LockResource | 無 | RT_RCDATA |
| STRING | LoadString | 無 | - |
| MENU | LoadMenu | TMainMenu/TMenuItem | - |
| DIALOG | CreateDialog, DialogBox | TForm (DFM) | - |
LoadFromResourceName、FindResource 皆區分大小寫,.rc 定義與呼叫必須完全一致。HInstance (全域變數);DLL 專案用 HInstance 或 GetModuleHandle("MyDll.dll")。LoadResource/LockResource 取得的指標不可手動 Free,系統在模組卸載時自動回收。LoadIcon/LoadCursor/LoadBitmap 返回的控制代碼需配對 DestroyIcon/DestroyCursor/DeleteObject (但 VCL 封裝類別會自動管理)。| 現象 | 原因 | 解決 |
|---|---|---|
| LoadFromResourceName 返回空/失敗 | 資源名稱大小寫不符、未連結 .res、資源類型錯誤 | 檢查 .rc 定義、專案 USERES、資源類型拼寫 |
| 游標不顯示/顯示為預設 | 自訂常數衝突、未註冊至 Screen->Cursors、控件 Cursor 未設定 | 用 >0 常數、確認 Screen->Cursors[idx] 非 0、PaintBox->Cursor=idx |
| PlaySound 無聲音 | 未連結 winmm.lib、資源類型非 WAVE、檔案非標準 PCM WAV | #pragma comment(lib,"winmm.lib")、.rc 用 WAVE、確認 44.1kHz/16bit/單聲道 |
| 圖示模糊/尺寸錯誤 | LoadIcon 僅載入 32x32、.ico 內無所需尺寸 | 用 LoadImage 指定尺寸、確認 .ico 含 16/32/48/256 尺寸 |