|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Subclassing Routines WM_ACTIVATEAPP: Detect Application Activation State |
||
Posted: | Saturday June 7, 1998 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB5, VB6 | |
Developed with: | VB6, Windows 98 | |
OS restrictions: | None | |
Author: | VBnet - Randy Birch | |
Prerequisites |
VB5 or VB6. |
|
In
some situations, developers may need to know when their application has gained or lost focus to another Windows application. While the Form
Activate and Deactivate methods are suitable for determining when one form in a Visual Basic app has gained or lost focus to another form in
the same application,
these events provide no means to detect when the user has switched from or to their application from another Windows app (including the
start menu or other system item). By means of a simple subclassing routine, you can trap the Windows messages which are normally excluded from
your application's view and use these to determine any change in status to the application.
The method below creates a subclassed form which traps any WM_ACTIVATEAPP message sent to the window. Normally eaten by Visual Basic, the LoWord of the message's wParam member contains the status flag indicating whether the window has been activated or deactivated. The MSDN states that when focus changes between two totally different applications, a WM_ACTIVATEAPP message is sent to the windows. This I can confirm. The MSDN also implies that a WM_ACTIVATE message is also sent when any other window is activated, but in testing with VB WM_ACTIVATE actually never fired. The demo changes the colour of the form as a sign of success in trapping the messages. In the illustration, a grey form indicates the WM_ACTIVATEAPP was received with a WA_INACTIVE status flag, meaning focus was switched away from the project app (in this case to notepad). The form's colour is changed back to salmon when the application receives WM_ACTIVATEAPP and the WA_ACTIVE status flag, indicating the app regained focus. In addition to the colour changes, the application's current activation state is reflected in the app's titlebar caption. |
BAS Module Code |
Place the following code into the general declarations area of a bas module: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Declare Function SetWindowLong Lib "user32" _ Alias "SetWindowLongA" _ (ByVal hwnd As Long, _ ByVal nIndex As Long, _ ByVal wNewWord As Long) As Long Public 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 As Long = (-4) Public Const WM_ACTIVATE As Long = &H6 Public Const WM_ACTIVATEAPP As Long = &H1C Public Const WA_INACTIVE As Long = 0 Public Const WA_ACTIVE As Long = 1 Public Const WA_CLICKACTIVE As Long = 2 'defWindowProc: Variable to hold the ID of the ' default window message processing ' procedure. Returned by SetWindowLong. Public defWindowProc As Long Public Function WindowProc(ByVal hwnd As Long, _ ByVal uMsg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long 'window message procedure On Error Resume Next Select Case hwnd 'If the handle returned is to our form, 'call a form-specific message handler 'to deal with the notifications. If it 'is a general system message, pass it 'on to the default window procedure. Case Form1.hwnd 'form-specific handler Select Case uMsg Case WM_ACTIVATEAPP Select Case LoWord(wParam) Case WA_INACTIVE: Form1.BackColor = &H8000000F Form1.Caption = "Inactive fired - App lost focus" Case WA_ACTIVE: Form1.BackColor = &H8080FF Form1.Caption = "Active fired - App has focus" End Select Case Else 'if subclassing has been activated, pass 'messages to the default message handler 'If it hasn't, then the default handler 'will take care of them by default. WindowProc = CallWindowProc(defWindowProc, _ hwnd, _ uMsg, _ wParam, _ lParam) Exit Function End Select Case Else 'this takes care of messages when the 'handle specified is not that of the form WindowProc = CallWindowProc(defWindowProc, _ hwnd, _ uMsg, _ wParam, _ lParam) End Select End Function Public Sub UnSubClass(hwnd As Long) 'restore the default message handling 'before exiting If defWindowProc Then SetWindowLong hwnd, GWL_WNDPROC, defWindowProc defWindowProc = 0 End If End Sub Public Sub SubClass(hwnd As Long) 'assign our own window message 'procedure (WindowProc) On Error Resume Next defWindowProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc) End Sub Public Function LoWord(dw As Long) As Integer If dw And &H8000& Then LoWord = &H8000& Or (dw And &H7FFF&) Else LoWord = dw And &HFFFF& End If End Function |
Form Code |
Add a single command button (Command1) to a form. Add the following code: |
|
Option Explicit Private Sub Command1_Click() Unload Me End Sub Private Sub Form_Load() 'prepare to receive the activation events Call SubClass(Form1.hwnd) 'use colours and caption to enable easy 'recognition of the activation changes Form1.BackColor = &H8080FF Form1.Caption = "Monitoring - App now has focus" End Sub Private Sub Form_Unload(Cancel As Integer) 'you must call this before ending 'to avoid a GPF! Call UnSubClass(Form1.hwnd) End Sub |
Comments |
Save then run the project. The form on startup will be
pink with the 'waiting' caption. Open or click any other window ... the form colour will change to the buttonface colour, and the caption
indicates an inactivation received. Reactivating the window by clicking, alt+tab'bing, using the taskbar or using task manager will
cause the app to return to its pink colour with the caption reading 'Activated'.
Before running, assure your form name has been changed to Form1, and when ending, use the command button .. never use the VB stop button when a form is subclassed! |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |