在開發 Windows 組語程式時,常需防止使用者重複啟動同一程式。若直接讓第二個實例退出,使用者拖曳檔案到程式圖示時會發現檔案無法開啟,體驗極差。本文介紹如何利用 WM_SETTEXT/WM_GETTEXT 訊息,在第二個實例退出前將命令列參數傳遞給第一個實例,實現單一實例且支援檔案關聯。
Windows 在進程結束時會回收該進程擁有的所有資源(動態載入的 DLL 除外)。若第二個實例直接將自身記憶體中的字串指標傳給第一個實例,隨著第二個實例退出,該指標即失效。解決之道是使用 SendMessage 發送 WM_SETTEXT 訊息:系統偵測到此訊息時,會自動建立一個可跨進程共享的記憶體映射檔,將字串內容複製進去,並將映射檔位址作為參數傳遞。接收端收到訊息後,透過 WM_GETTEXT 即可安全讀取字串。
.DATA
szClassName db "WinASM_Class",0
.data?
lpCommandLine DD ?
.CODE
START:
; 取得命令列
invoke GetCommandLine
mov lpCommandLine, eax
; 尋找同類別視窗
invoke FindWindow, offset szClassName, NULL
cmp eax, 0
jnz @F ; 找到則跳轉至傳遞參數
; 第一個實例:正常執行
invoke WinMain, ...
invoke ExitProcess, 0
@@: ; 第二個實例:傳遞參數給第一個實例
invoke SendMessage, eax, WM_SETTEXT, 0, lpCommandLine
invoke ExitProcess, 1 ; 非零返回值表示非正常啟動
.elseif uMsg == WM_SETTEXT
; lParam 指向共享記憶體中的字串
invoke MessageBox, 0, lParam, 0, 0 ; 示範:彈出訊息框顯示參數
; 實際應用可解析 lParam 並呼叫開啟檔案流程
編譯後執行第一個實例,再以命令列參數啟動第二個實例(例如 MyApp.exe "C:\test.txt"),即可見第一個實例彈出訊息框顯示 C:\test.txt。此技巧廣泛應用於編輯器、檢視器等需支援檔案拖曳開啟的工具程式。
WM_SETTEXT/WM_GETTEXT 實現跨進程字串傳遞,避免指標失效。