在關機或Logff前訊息的攔截 來源:cww 如果我們關機或Logoff時,我們的程式有時會因而無法按正常程序結束,一般我們會在 Form的Unload中一段程式結束時要做什麼事,但是,如果使用者直接用開始功能表的關 機,會使UnLoad的部份沒有做到,我們現在就想辦法來攔截關機(或Logoff)時的訊息。 一般來說,關機或Logff後,Windows會傳依序送出WM_QUERYENDSESSION的訊息給每個 Process,如果中間有一個Process不能順利結束(例如:Word修改後未存檔,而出現是 否存檔,但我們按取消),這時該訊息執行的結果會傳回False(0),這時Windows也就 不再繼續送WM_QUERYENDSESSION給下一個Proccess。反之,如果所有的Process都可以 順利結束(也就是每個送出的WM_QUERYENDSESSION都傳回True),那才代表可以順利結束。 不管WM_QUERYENDSESSION最後的結果是可以順利結束或不能順利結束,Windows會再送 一個WM_ENDSESSION的訊息給所有的Process,而wParam的內容便是指出是否可以順利 結束(True表可以,False表不行,在vb中則Check wParam = 0 表False ,<> 0表True) ,說到這裡大概就知道該如何做啦,程式如下:
'以下在Form Private Sub Form_Load() Dim ret As Long '記錄原本的Window Procedure的位址 preWinProc = GetWindowLong(Me.hwnd, GWL_WNDPROC) '設定form的window Procedure到wndproc ret = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf wndproc) End Sub Private Sub Form_Unload(Cancel As Integer) Dim ret As Long '取消Message的截取,而使之又只送往原來的Window Procedure ret = SetWindowLong(Me.hwnd, GWL_WNDPROC, preWinProc) '這裡只是要看看用關機的方式結束程式時,會不會執行到這裡 Dim fno As Long fno = FreeFile Open "c:\tt2" For Append As fno Print #fno, "ccc" + vbCrLf Close #fno End Sub |
Option Explicit Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long) As Long Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _ (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long Public Const GWL_WNDPROC = (-4) Public Const WM_ENDSESSION = &H16 Public Const WM_QUERYENDSESSION = &H11 Public preWinProc As Long Public Function wndproc(ByVal hwnd As Long, ByVal Msg As Long, _ ByVal wParam As Long, ByVal lParam As Long) As Long If Msg = WM_QUERYENDSESSION Then Debug.Print "QryEnd", wParam, lParam Else If Msg = WM_ENDSESSION Then If wParam <> 0 Then '代表將順利關機或LogOff,這時便得做正常結束程式的動作 Dim fno As Long Open "c:\ttt" For Output As #1 Print #1, "hahcccc5" Close #1 End If End If End If '將之送往原來的Window Procedure wndproc = CallWindowProc(preWinProc, hwnd, Msg, wParam, lParam) End Function |