Quote Originally Posted by LaVolpe View Post
Just because I love puzzles, this is a good solution, but has one drawback addressed at bottom of this post.

The fix is to locate the menu immediately, test whether the mouse X,Y coords are within the window bounds, and testing if the menu is visible or not. Seems to work really well for mouse "hover" over a menu selection.
Code:
Option Explicit
Private Declare Function GetCursorPos Lib "user32.dll" (ByRef lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32.dll" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hWnd As Long, ByRef lpRect As RECT) As Long
Private Declare Function ScreenToClient Lib "user32.dll" (ByVal hWnd As Long, ByRef lpPoint As POINTAPI) As Long
Private Declare Function IsWindowVisible Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Type POINTAPI
    X As Long
    Y As Long
End Type
Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private myMenuHwnd As Long

Private Sub mnuMain_Click()
    ' when menu opens, start timer
    Me.Caption = "Waiting for menu selection" ' testing purposes
    DoEvents ' should allow menu to appear
    myMenuHwnd = FindWindow("#32768", vbNullString)
    Timer1.Tag = "-1"
    Timer1.Interval = 100
    Timer1.Enabled = True
End Sub

Private Sub Timer1_Timer()
    Dim mPT As POINTAPI, sBuffer As String
    Dim wRect As RECT, mIndex As Long
    Dim nrMenuItems As Long
    
    GetCursorPos mPT
    If myMenuHwnd = 0& Then
        myMenuHwnd = WindowFromPoint(mPT.X, mPT.Y)
        sBuffer = String$(6, vbNullChar)
        Call GetClassName(myMenuHwnd, sBuffer, 7)
        If sBuffer <> "#32768" Then myMenuHwnd = 0&
    ElseIf IsWindowVisible(myMenuHwnd) = 0& Then
        Me.Caption = "Menu closed" ' testing purposes
        Timer1.Enabled = False
        myMenuHwnd = 0&
    End If
    If myMenuHwnd Then
        GetWindowRect myMenuHwnd, wRect
        If mPT.Y > wRect.Top And mPT.Y < wRect.Bottom Then
            If mPT.X > wRect.Left And mPT.X < wRect.Right Then
                ScreenToClient myMenuHwnd, mPT
                nrMenuItems = 3 ' I only used 3 for my test
                mIndex = mPT.Y \ ((wRect.Bottom - wRect.Top) \ nrMenuItems)
                If mIndex <> Val(Timer1.Tag) Then
                    Timer1.Tag = mIndex
                    Me.Caption = "over menu item " & mIndex + 1 ' testing purposes
                End If
            End If
        End If
    End If
End Sub
Downside. Does not deal with user moving up/down menu items via the keyboard. Can be overcome with a keybd hook (like subclassing) or another timer testing keyboard for strokes (GetAsyncKeyState API for example)
Edited:
Other potential issues if they apply:
1. If menu is large and eventually scrolls; all bets are off and will require a lot more work
2. If menu opens any contained submenus; needs more work to stop timer when submenu opens & restart timer when submenu closes

Subclassing is the correct way to do what you want and all issues will be overcome; but as mentioned before, subclassing requires some practice and has zero-tolerance for errors. Makeshift workarounds rarely work as well, can be buggy, and often are less efficient than the "correct" way. Just FYI.
I do have submenus, but for now i am showing a picture only when hovering over the main menu items. I can post the form with the images if you would like to see.

Many Thanks for your help and every one elses help.

Code:
If mIndex <> Val(Timer1.Tag) Then
                    Timer1.Tag = mIndex
                    Me.Caption = "over menu item " & mIndex + 1 ' testing purposes
                    If mIndex = 0 Then
                    Image1.Visible = True
                    Else: Image1.Visible = False
                    End If
                    If mIndex = 1 Then
                    Image2.Visible = True
                    Else: Image2.Visible = False
                    End If
                End If