Access provides us with the DropDown method to force a combobox to
display it's associated listbox from code. However, there is no corressponding
property that can tell us whether a combo is currently open or not.
There are two ways to determine a combobox's Dropped state from code. One method
relies on the Windows class names of several Access owned windows, and the other, provided
by Stephen Lebans, uses
screen coordinates to get to the combobox.
Both these samples are included in the CheckComboDrop.zip
(Access 97 mdb). Please
note that the same techniques, with different class names, will work from VB as well,
allowing us to avoid using GetComboBoxInfo, which is available only on Win98 and
Win2000.
1) Detecting combo state via class name
Private Declare Function apiGetClassName Lib "user32" _
Alias "GetClassNameA" _
(ByVal hwnd As Long, _
ByVal lpClassname As String, _
ByVal nMaxCount As Long) _
As Long
Private Declare Function apiGetParent Lib "user32" _
Alias "GetParent" _
(ByVal hwnd As Long) _
As Long
Private Declare Function apiGetWindowLong Lib "user32" _
Alias "GetWindowLongA" _
(ByVal hwnd As Long, _
ByVal nIndex As Long) _
As Long
Private Declare Function apiFindWindow Lib "user32" _
Alias "FindWindowA" _
(ByVal lpClassname As String, _
ByVal lpWindowName As String) _
As Long
Private Declare Function apiGetWindow Lib "user32" _
Alias "GetWindow" _
(ByVal hwnd As Long, _
ByVal wCmd As Long) _
As Long
Private Const ACC_CBX_LISTBOX_CLASS = "OGrid"
Private Const ACC_MAIN_CLASS = "OMain"
Private Const ACC_CBX_LISTBOX_PARENT_CLASS = "ODCombo"
Private Const ACC_FORM_CLIENT_CLASS = "OFormSub"
Private Const ACC_CBX_EDIT_CLASS = "OKttbx"
Private Const VB_CBX_LISTBOX_PARENT_CLASS = "#32769" ' // Desktop
Private Const VB_CBX_LISTBOX_CLASS = "ComboLBox"
Private Const GW_CHILD = 5
Private Const GWL_STYLE = (-16)
Private Const WS_VISIBLE = &H10000000
Function fIsComboOpen() As Boolean
Static hwnd As Long
Static hWndCBX_LBX As Long
hwnd = 0: hWndCBX_LBX = 0
hwnd = apiFindWindow(ACC_CBX_LISTBOX_PARENT_CLASS, _
vbNullString)
If apiGetParent(hwnd) = hWndAccessApp Then
hWndCBX_LBX = apiGetWindow(hwnd, GW_CHILD)
If fGetClassName(hWndCBX_LBX) = _
ACC_CBX_LISTBOX_CLASS Then
If apiGetWindowLong(hwnd, GWL_STYLE) And WS_VISIBLE Then
fIsComboOpen = True
End If
End If
End If
End Function
Private Function fGetClassName(hwnd As Long)
Dim strBuffer As String
Dim lngLen As Long
Const MAX_LEN = 255
strBuffer = Space$(MAX_LEN)
lngLen = apiGetClassName(hwnd, strBuffer, MAX_LEN)
If lngLen > 0 Then fGetClassName = Left$(strBuffer, lngLen)
End Function
2) Detecting combo state via coordinates
Private Declare Function MapWindowPoints Lib "user32" _
(ByVal hwndFrom As Long, ByVal hwndTo As Long, _
lppt As Any, ByVal cPoints As Long) As Long
Private Declare Function WindowFromPoint Lib "user32" _
(ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function ChildWindowFromPoint Lib "user32" _
(ByVal hwnd As Long, ByVal xPoint As Long, _
ByVal yPoint As Long) As Long
Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, _
lpPoint As POINTL) As Long
Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, _
lpPoint As POINTL) As Long
Private Declare Function apiCreateIC Lib "gdi32" Alias "CreateICA" _
(ByVal lpDriverName As String, ByVal lpDeviceName As String, _
ByVal lpOutput As String, lpInitData As Any) As Long
Private Declare Function apiDeleteDC Lib "gdi32" Alias "DeleteDC" _
(ByVal hdc As Long) As Long
Private Declare Function apiGetDeviceCaps Lib "gdi32" _
Alias "GetDeviceCaps" (ByVal hdc As Long, _
ByVal nIndex As Long) As Long
Private Const LOGPIXELSX = 88 ' Logical pixels/inch in X
Private Const LOGPIXELSY = 90 ' Logical pixels/inch in Y
Private Type POINTL
X As Long
Y As Long
End Type
Private Sub Detail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Call MyCombo_MouseMove(0, 0, 0, 0)
End Sub
Private Sub MyCombo_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim ComboListhWnd As Long
Dim mypoint As POINTL
Dim lngIC As Long
Dim lngXdpi As Long
Dim lngYdpi As Long
Dim TwipsPerPixelX As Long
Dim TwipsPerPixelY As Long
Dim lngret As Long
lngIC = apiCreateIC("DISPLAY", vbNullString, vbNullString, vbNullString)
If lngIC <> 0 Then
lngXdpi = apiGetDeviceCaps(lngIC, LOGPIXELSX)
lngYdpi = apiGetDeviceCaps(lngIC, LOGPIXELSY)
apiDeleteDC (lngIC)
Else
' Something has gone wrong. Assume an average value.
lngret = MsgBox("Error..invalid Display Device Context..Exiting", vbOKOnly)
Exit Sub
End If
TwipsPerPixelX = 1440 \ lngXdpi
TwipsPerPixelY = 1440 \ lngYdpi
mypoint.X = ((Me.MyCombo.Left + Me.MyCombo.Width) \ 2) \ TwipsPerPixelX
mypoint.Y = (Me.MyCombo.Top + (Me.MyCombo.Height * 2)) \ TwipsPerPixelY
Call ClientToScreen(Me.hwnd, mypoint)
ComboListhWnd = WindowFromPoint(mypoint.X, mypoint.Y)
If ComboListhWnd = Me.hwnd Then
Me.txtAPICombo = "The Combo has NOT Dropped"
Else:
Me.txtAPICombo = "The Combo has Dropped"
End If
End Sub
|