BEGIN_MESSAGE_MAP + 專用訊息結構// 自訂訊息 ID
#define WM_MY_OPEN_CMDLINE_FILE (WM_USER + 1) // 命令列檔案傳遞
#define WM_MY_SEARCH_NODE (WM_USER + 2) // 內部搜尋觸發
class TSomeForm : public TForm
{
__published: ...
protected:
// 1. 訊息處理函數宣告(參數採 const 參考或值傳遞)
void __fastcall OpenCmdLineFile(TMessage &Message);
void __fastcall SearchDocumentNode(TMessage &Message);
void __fastcall GetWindowMinMaxInfo(TWMGetMinMaxInfo &Message);
// 2. 訊息映射表
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_MY_OPEN_CMDLINE_FILE, TMessage, OpenCmdLineFile)
MESSAGE_HANDLER(WM_MY_SEARCH_NODE, TMessage, SearchDocumentNode)
MESSAGE_HANDLER(WM_GETMINMAXINFO, TWMGetMinMaxInfo, GetWindowMinMaxInfo)
END_MESSAGE_MAP(TForm)
public:
__fastcall TSomeForm(TComponent* Owner);
};
// 1. 處理命令列檔案傳遞 (LPARAM 傳遞 char*)
void __fastcall TSomeForm::OpenCmdLineFile(TMessage &Message)
{
LPSTR lpCmdLine = (LPSTR)Message.LParam; // 取得指標
HandleCmdLineFile(lpCmdLine); // 交由業務函數
}
// 2. 觸發搜尋 (無額外參數)
void __fastcall TSomeForm::SearchDocumentNode(TMessage &Message)
{
SearchNode(); // 直接呼叫
}
// 3. 設定視窗最小尺寸 (系統訊息,專用結構)
void __fastcall TSomeForm::GetWindowMinMaxInfo(TWMGetMinMaxInfo &Message)
{
MINMAXINFO *mmi = Message.MinMaxInfo;
mmi->ptMinTrackSize.x = 400;
mmi->ptMinTrackSize.y = 300;
}
參考 $(BCB)\Include\Vcl\Messages.hpp 中的定義風格:
// 範例:帶兩個整數參數的自訂訊息
struct TMySearchMsg : public TMessage
{
int NodeId;
int FilterType;
};
// 發送端
TMySearchMsg msg;
msg.Msg = WM_MY_SEARCH_NODE;
msg.NodeId = 123;
msg.FilterType = 2;
PostMessage(TargetWnd, WM_MY_SEARCH_NODE, (WPARAM)&msg, 0); // 指標傳遞
// 接收端映射
MESSAGE_HANDLER(WM_MY_SEARCH_NODE, TMySearchMsg, OnMySearch)
void __fastcall TForm1::OnMySearch(TMySearchMsg &Msg)
{
// 直接存取 Msg.NodeId, Msg.FilterType
DoSearch(Msg.NodeId, Msg.FilterType);
}
場景:使用者雙擊關聯檔案 → 第二個實例啟動 → 傳遞檔案路徑給第一個實例 → 第二個實例退出。
// 全域唯一訊息 ID
UINT WM_MY_INSTANCE_MSG = RegisterWindowMessage("MyApp_InstanceMessage_{GUID}");
// 主表單建構子
__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner)
{
// 掛鉤訊息
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_MY_INSTANCE_MSG, TMessage, OnInstanceMessage)
END_MESSAGE_MAP(TForm)
}
void __fastcall TMainForm::OnInstanceMessage(TMessage &Msg)
{
// LPARAM 傳遞檔案路徑指標 (需共享記憶體或 WM_COPYDATA)
// 此處示範 WM_COPYDATA 更安全
}
WM_COPYDATA// WinMain 入口點檢測
HANDLE hMutex = CreateMutex(NULL, TRUE, "MyApp_SingleInstance_Mutex");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// 找到主視窗
HWND hMain = FindWindow("TMainForm", NULL);
if (hMain) {
COPYDATASTRUCT cds;
cds.dwData = 1; // 命令:開啟檔案
cds.cbData = (lstrlen(lpCmdLine) + 1) * sizeof(TCHAR);
cds.lpData = (void*)lpCmdLine;
SendMessage(hMain, WM_COPYDATA, 0, (LPARAM)&cds);
}
return 0; // 直接退出
}
WM_COPYDATABEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_COPYDATA, TWMCopyData, OnCopyData)
END_MESSAGE_MAP(TForm)
void __fastcall TMainForm::OnCopyData(TWMCopyData &Msg)
{
COPYDATASTRUCT *cds = Msg.CopyDataStruct;
if (cds->dwData == 1) {
String filePath = (TCHAR*)cds->lpData;
OpenFileInEditor(filePath);
BringToFront(); // 激活視窗
}
Msg.Result = 1; // 表示已處理
}
$(BCB)\Include\Vcl\Messages.hpp
// 包含 TMessage, TWMMouse, TWMKey, TWMGetMinMaxInfo, TWMCopyData 等
WM_USER+,跨進程用 RegisterWindowMessage。WParam/LParam,複雜結構用 WM_COPYDATA 或共享記憶體。TMessage 以利映射宏展開。const TMsg& 或 TMsg&,避免拷貝。GetWindowThreadProcessId + 簽名驗證)。
這套模式涵蓋了 90% 的訊息響應需求,從簡單通知到跨進程協作皆適用。