Get a Handle on Window State
If you use windowed forms in Access ("Overlapping Windows" as opposed to "Tabbed Documents"), then you have to be aware of the three possible states of each form or report window: minimized, maximized, or normal (restored).
Access VBA has three corresponding methods to set the window state of a form or report object: DoCmd.Minimize
, DoCmd.Maximize
, and DoCmd.Restore
. What VBA does not have is any built-in way to check the state of a given form or report window. Let's address that.
IsZoomed and IsIconic API calls
Luckily for us, there are two simple Windows API calls that will provide this information. The first, IsZoomed
, will return True if the window handle passed to it belongs to a window that is maximized. The second, IsIconic
, returns True if the passed window handle belongs to a minimized window.
What the heck is a window handle?
A window handle is nothing more than a reliable way to refer to a specific window when communicating with the Windows API. That's obviously a simplification, but for our purposes it will suffice.
The typical naming convention when referring to window handles is hWnd
("h" for handle and "Wnd" for window). Access VBA provides properties that make it easy to retrieve the window handle for the Access application itself (Application.hWndAccessApp
), as well as for form and report objects (e.g., Forms(0).Hwnd
).
On a side note, retrieving the window handle for individual controls--such as text boxes or combo boxes--is not so easy. And, yes, form controls are implemented as "windows." For an example of how some code could be simpler if Access exposed the window handles of form controls, refer to Determining Combobox's Dropped State, by Dev Ashish and Stephen Lebans.
The stackoverflow answer below provides a good explanation of the window handle concept with a bit more technical background.
The Code
'Functions return 1 for true and 0 for false; multiply result by -1 for safer Boolean use
#If VBA7 Then
Private Declare PtrSafe Function IsZoomed Lib "user32" (ByVal hWnd As LongPtr) As Integer
Private Declare PtrSafe Function IsIconic Lib "user32" (ByVal hWnd As LongPtr) As Integer
#Else
Private Declare Function IsZoomed Lib "user32" (ByVal hWnd As Long) As Integer
Private Declare Function IsIconic Lib "user32" (ByVal hWnd As Long) As Integer
#End If
#If VBA7 Then
Function IsMaximized(hWnd As LongPtr) As Boolean
#Else
Function IsMaximized(hWnd As Long) As Boolean
#End If
IsMaximized = IsZoomed(hWnd) * -1
End Function
#If VBA7 Then
Function IsMinimized(hWnd As LongPtr) As Boolean
#Else
Function IsMinimized(hWnd As Long) As Boolean
#End If
IsMinimized = IsIconic(hWnd) * -1
End Function
Multiplying by -1?
Note that in the code above, I'm multiplying the result from the IsZoomed and IsIconic functions by -1. This is not necessary in this context, but it's a good habit to get into.
VBA stores Booleans as 16-bit signed integers. The only "False" value is zero. Anything other than zero is considered "True." Combine that with the fact that And, Or, and Not are bitwise operations, and you have a recipe for some unexpected results:
'This works how you would expect:
?CBool(-1)
True
?CBool(Not -1)
False
'This...probably not so much:
?CBool(1)
True
?CBool(not 1)
True
This topic deserves its own article, but I wanted to provide some brief background to explain this otherwise odd bit of code.
Image by Christoph Schütz from Pixabay
UPDATED [2023-10-26]: Switched arguments from hWnd As Long
to hWnd As LongPtr
in IsMinimized()
and IsMaximized()
functions for VBA7 and later (h/t Xevi Batlle)