此文章是接續憐香的"DOS到Win32"系列教程第14篇的後續,閱讀之前推薦查看前續文章
正如憐香所說,命令行參數在Windows中是無處不在的,只是一般感覺不到,雙擊一個txt文件,Windows會啟動記事本程序並把txt的路徑做為參數提供給它,這當然相當的快捷,一般在打開一個文件時會再一次啟動相關聯的程序,但是你會發現很多多文檔(MDI)軟件在運行的情況下不會再次啟動一個新的實例,而是已經運行的程序打開了你再次需要打開的文件,這就是防止程序的多重啟動。
這一篇先講如何防止,下一篇再講如何處理(就是讓已經運行的實例打開下個實例的文件)。
要防止程序多重啟動,有很多的方法,如下:
1.可以使用FindWindow查找程序的標題,此函數成功返回目標窗口句柄,失敗為NULL.
szWindowName db "Hello World!",0
... ...
invoke FindWindow,NULL,offset szWindowName
.if eax!=NULL
invoke WinMain....
.end if
invoke ExitProcess,0
這種方法不是很好,因為會有一些軟件的窗口可能與你的窗口標題同名,注意看上面的FindWindow,參考API手冊發現第一個參數是ClassName,窗口類名除自身實例一般是唯一的,這種方法一般完全可行:
2.使用FindWindow查找程序的窗口類名,函數成功返回目標窗口句柄,失敗為NULL.
szClassName db "WINASM_CLASS!",0
... ...
invoke FindWindow,offset szClassName,NULL
.if eax!=NULL
invoke WinMain....
.end if
invoke ExitProcess,0
但是這種方法缺點就是,當程序沒有標准的窗口或是以對話框為主窗口的程序就不適用了,沒有標准窗口的程序當然沒有類名,而以對話框為主窗口的程序的話也不行,因為默認對話框的類名都是#32768,這個當然無法依此來判斷實例是否已運行.
3.創建一個Mutex(互斥)對象,這是一個系統全局標識,創建後所有的程序都可以訪問到.此函數成功返回Mutex對象的句柄,失敗返回NULL,但是一般都是通過GetLastError獲得錯誤編號進行判斷.
.data
szMutex db "_Me?",0
.data?
hMutex dd ?
hInstance dd ?
.CODE
START:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke
CreateMutex,NULL,TRUE,offset szMutex
mov hMutex,eax
invoke GetLastError 獲得最後發生的錯誤編號
cmp eax,ERROR_ALREADY_EXISTS 已經存在
jz @F
invoke WinMain...
invoke ReleaseMutex,hMutex 只有在正常運行後才釋放Mutex對象
@@:
invoke ExitProcess,0
4.還有其它方法,如在程序啟動時在同目錄或Windows臨時目錄下創建一個文件,退出刪除它,那麼第二個以上的實例運行後首先判斷是否存在這個文件,存在則退出,不存在則啟動,如果一個程序使用到了INI則更方便,和上面說的一樣,在啟動時設置某個鍵,退出時再設為0,第二個以上的實例則以此鍵為"互斥對象"。還有往注冊表中寫一個鍵,方法和上面是一樣的。