1. 程式人生 > >MFC中應用WM_ENDSESSION,WM_QUERYENDSESSION訊息截獲系統的關機/登出

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

非常有幫助的連結: