MFC中應用WM_ENDSESSION,WM_QUERYENDSESSION訊息截獲系統的關機/登出
目的:當用戶登出系統的時候,登出前,讓我的程式執行幾行程式碼(釋放資源/關閉埠之類的)。
思路:就跟把系統登出、重啟和關機的訊息都攔截下來,並銷燬掉,不讓其執行登出、重啟和關機等操作原理是一樣的。因為Windows在登出、重起、關機之前會向每個當前正在執行的應用程式廣播一個訊息WM_QUERYENDSESSION, 其lParam引數可以區分是關機還是登出使用者(登出使用者時lParam是ENDSESSION_LOGOFF)。然後Windows會等到所有的應用程式都對這個訊息返回TRUE才會關機,因此,只要我們的應用程式對這個訊息的處理返回FALSE,Windows就不會關機了。當系統登出的時候,所有非系統級的程式都會被退出,如果想讓自己的程式在登出時仍然可以執行,就將自己的程式做成系統服務程式。
解決途徑:攔截系統廣播出來的WM_ENDSESSION和WM_QUERYENDSESSION訊息。插一句:方法應該不止一種,比如系統鉤子,但是參考網友的解決方案,程式一執行系統就奔潰了。沒想到在MFC裡面非常容易的通過過載WindowProc就可以實現,方法如下。
在MFC中的解決方法:
環境:VS 6.0, XP 32-bit
“檢視”-->"建立類嚮導...",將WindowProc過載。
其函式體如下:
LRESULT CLabRelayDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class // WM_QUERYENDSESSION訊息是Windows向你詢問Windows能否關閉 // WM_ENDSESSION訊息表示提示你Windows即將關閉。 switch(message) { case WM_ENDSESSION: // 把訊息銷燬掉,不讓其正確轉發。 //message = WM_USERMESSAGE_NULL; //turn off the relay if(relayState==RELAY_ON) turnOff(); break ; case WM_QUERYENDSESSION: //登出/關機 //turn off the relay if(relayState==RELAY_ON) turnOff(); break ; } return CDialog::WindowProc(message, wParam, lParam); }
就這樣,系統登出的時候我的函式turnOff();被執行了。
關於lParam引數是通知碼有一些的值:
ENDSESSION_CLOSEAPP
0x00000001
The application is using a file that must be replaced, the system is being serviced, or system resources are exhausted. For more information, see Guidelines for Applications.
ENDSESSION_LOGOFF
0x80000000
非常有幫助的連結: