• 解説

    AccessのコントロールはVBやVC++など他の言語と違いウィンドウハンドルがありません。
    これはリソースの消費を防ぐためフォーカスがある場合のみウィンドウとして扱い、それ以外はただの画像として表示する技術を使用しているためです。(予想)

    コンボボックスはテキストボックスとリストボックスの2つのウィンドウで構成されています。
    これはAccessでも例外ではありません。
    ただし、Accessでは前述したとおりフォーカスを受け取るまでコントロールはウィンドウとして扱わないようになっています。

    コンボボックスがドロップダウンされているか判断するには、リストボックスが表示されているかされていないかで判断できます。
    Accessでのコンボボックスのリスト部はODComboというウィンドウクラス名で存在し実際のリスト部はその子ウィンドウになっています。
    上記のことからODComboクラスのウィンドウを検索し、その子ウィンドウが表示されている状態であればコンボボックスが開いている状態と判断できます。

    コンボボックス自体の判定はこれで可能ですがコンボボックスと親ウィンドウの関係を判断する方法が今のところ見つかりません。
    とりあえず2つの方法を考えましたが両者ともに欠点があります。
    ・指定した親のウィンドウハンドルとコンボボックスの親のウィンドウハンドルが一致する場合
    ・指定した親のウィンドウとコンボボックスの領域が重なるものを親と判断する場合
    前者はポップアップフォームになっていない場合コンボボックスの親がAccessのウィンドウになってしまいます。
    後者はフォームが重なっている場合でフォーム同士が重なっている場所で、コンボボックスが開かれた場合どちらのコンボボックスかわからなくなります。
    しかし、同時に複数のコンボボックスを開くことは物理的に不可能なので問題ないと思います。

    また、どのコンボボックスがドロップダウンされているかを判定するのはドロップダウンされているウィンドウの座標で判断するしかありません。

  • サンプル

    標準モジュール

    <親ウィンドウの判定方法:指定したウィンドウハンドルと一致する場合>

    Option Compare Database
    Option Explicit
    
        Public Type Type_EnumWindowParameter
            WindowHandle                                As Long
            ComboBoxWindowHandle                        As Long
        End Type
    
        Private Const GW_OWNER                          As Long = 4
        Private Const GW_CHILD                          As Long = 5
    
        Private Declare Function GetWindow Lib "user32" _
                       (ByVal hwnd As Long, _
                        ByVal wCmd As Long) As Long
        Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
                       (ByVal hwnd As Long, _
                        ByVal lpClassName As String, _
                        ByVal nMaxCount As Long) As Long
    
    Public Function EnumWindowProc(ByVal WindowHandle As Long, _
                                   ByRef lParam As Type_EnumWindowParameter) As Long
    
        Dim Buffer                                      As String
    
        Buffer = Space(1024)
    
        Call GetClassName(WindowHandle, Buffer, 1024)
    
        EnumWindowProc = True
    
        If Trim$(Buffer) <> "ODCombo" Then
            Exit Function
        End If
    
        If GetWindow(WindowHandle, GW_OWNER) <> lParam.WindowHandle Then
            Exit Function
        End If
    
        lParam.ComboBoxWindowHandle = GetWindow(WindowHandle, GW_CHILD)
    
        EnumWindowProc = False
    
    End Function
    

    <親ウィンドウの判定方法:コンボボックスウィンドウが指定したウィンドウと重なっている場合>

    Option Compare Database
    Option Explicit
    
        Public Type Type_EnumWindowParameter
            WindowHandle                                As Long
            ComboBoxWindowHandle                        As Long
        End Type
    
        Private Type Type_RECT
            Left                                        As Long
            Top                                         As Long
            Right                                       As Long
            Bottom                                      As Long
        End Type
    
        Private Const GW_OWNER                          As Long = 4
        Private Const GW_CHILD                          As Long = 5
    
        Private Declare Function GetWindow Lib "user32" _
                       (ByVal hwnd As Long, _
                        ByVal wCmd As Long) As Long
        Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
                       (ByVal hwnd As Long, _
                        ByVal lpClassName As String, _
                        ByVal nMaxCount As Long) As Long
        Private Declare Function GetWindowRect Lib "user32" _
                       (ByVal hwnd As Long, _
                        ByRef lpRect As Type_RECT) As Long
        Private Declare Function IntersectRect Lib "user32" _
                       (lpDestRect As Type_RECT, _
                        lpSrc1Rect As Type_RECT, _
                        lpSrc2Rect As Type_RECT) As Long
    
    Public Function EnumWindowProc(ByVal WindowHandle As Long, _
                                   ByRef lParam As Type_EnumWindowParameter) As Long
    
        Dim Buffer                                      As String
    
        Dim WindowRect                                  As Type_RECT
        Dim ComboBoxRect                                As Type_RECT
        Dim WorkRect                                    As Type_RECT
    
        Buffer = Space(1024)
    
        Call GetClassName(WindowHandle, Buffer, 1024)
    
        EnumWindowProc = True
    
        If Trim$(Buffer) <> "ODCombo" Then
            Exit Function
        End If
    
        Call GetWindowRect(lParam.WindowHandle, WindowRect)
        Call GetWindowRect(WindowHandle, ComboBoxRect)
    
        If IntersectRect(WorkRect, WindowRect, ComboBoxRect) = 0 Then
            Exit Function
        End If
    
        lParam.ComboBoxWindowHandle = GetWindow(WindowHandle, GW_CHILD)
    
        EnumWindowProc = False
    
    End Function
    

    フォームのクラスモジュールなど

        Private Declare Function EnumWindows Lib "user32" _
                       (ByVal lpEnumFunc As Long, _
                        ByRef lParam As Type_EnumWindowParameter) As Long
        Private Declare Function IsWindowVisible Lib "user32" _
                       (ByVal hwnd As Long) As Long
    
    Private Function IsDropDown() As Boolean
    
        Dim Parameter                                   As Type_EnumWindowParameter
    
        IsDropDown = False
    
    ' 親ウィンドウの判定方法を「指定したウィンドウハンドルと一致する場合」を使用する
    ' 場合でフォームがポップアップの場合はこちらのパラメータを指定します。
    ' 親ウィンドウの判定方法をコンボボックスウィンドウが指定したウィンドウと
    ' 重なっている場合を使用する場合はこちらのパラメータを指定します。
        Parameter.WindowHandle = Me.hwnd                    
    ' 親ウィンドウの判定方法を「指定したウィンドウハンドルと一致する場合」を使用する
    ' 場合でフォームがポップアップではない場合はこちらのパラメータを指定します。
    '    Parameter.WindowHandle = Application.hWndAccessApp 
    
        If EnumWindows(AddressOf EnumWindowProc, Parameter) <> 0 Then
            Exit Function
        End If
    
        IsDropDown = IsWindowVisible(Parameter.ComboBoxWindowHandle)
    
    End Function
    

    使用方法は

        If IsDropDown = True Then
            'ドロップダウンされている
        Else
            'ドロップダウンされていない
        End If
    

    と、なります。

  • その他

    Access2000以降限定です。
    (EnumWindowsの代わりにFindWindowにすることでAccess97で実行することも出来ますが、親子関係を判断するのにちょっと手間がかかります)
    管理人はAccess97以外所有していないためサンプルファイルの公開はできません。ご了承ください。

    このリスト部のウィンドウは1つのフォームに1つしかないようでフォーム内に複数のコンボボックスが存在している場合は使いまわされているようです。

説明がわからないなどありましたらお問い合わせでお知らせください。

ここに掲載された情報を使用したことによって発生した、いかなる損害に対しても
管理者である雅は一切責任を負いません。