VBA code a combo box on a User form

HunterN

Active Member
Joined
Mar 19, 2002
Messages
479
Hi,

I have a userform that has combo boxes and text boxes on it. The combo box that displays the 'Years', from 1994 thru 2012, appears just fine with a vertical scroll bar on the right. I was wondering if there is a way to be able to use the mouse scroll wheel to move up and down when I have the focus on the 'Years' combo box?

Thanks for any comment here!

Nancy
 

Excel Facts

Back into an answer in Excel
Use Data, What-If Analysis, Goal Seek to find the correct input cell value to reach a desired result
Hi Nancy,

I have seen this question posted here and elsewhere many times before but I have never seen a solution . I have been experimenting with some Windows Hooking recently and I managed to come up with what seems to be a reliable solution. I have tested it and works beautifully.

Ok..., place a ComboBox (ComboBox1) in a Worksheet ( Sheet1) and poulate it with some Data.




Add this Code to the WorkSheet Module :

Code:
Private Sub ComboBox1_GotFocus()

    'Store the first TopIndex Value
    intTopIndex = ComboBox1.TopIndex
    Hook_Mouse

End Sub

Private Sub ComboBox1_LostFocus()

    UnHook_Mouse

End Sub



Add a Standard Module and place this in it :

Code:
Option Explicit

Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function GetForegroundWindow Lib "user32" () As Long

Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)

Declare Function SetWindowsHookEx Lib _
"user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
ByVal hmod As Long, ByVal dwThreadId As Long) As Long

Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long

Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long

Type POINTAPI
  X As Long
  Y As Long
End Type

Type MSLLHOOKSTRUCT 'Will Hold the lParam struct Data
    pt As POINTAPI
    mouseData As Long ' Holds Forward\Bacward flag
    flags As Long
    time As Long
    dwExtraInfo As Long
End Type

Const HC_ACTION = 0
Const WH_MOUSE_LL = 14
Const WM_MOUSEWHEEL = &H20A

Dim hhkLowLevelMouse, lngInitialColor As Long
Dim udtlParamStuct As MSLLHOOKSTRUCT
Public intTopIndex As Integer

'==========================================================================
'\\Copy the Data from lParam of the Hook Procedure argument to our Struct
Function GetHookStruct(ByVal lParam As Long) As MSLLHOOKSTRUCT

   CopyMemory VarPtr(udtlParamStuct), lParam, LenB(udtlParamStuct)
   
   GetHookStruct = udtlParamStuct
   
End Function

'===========================================================================
Function LowLevelMouseProc _
(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    'Avoid XL crashing if RunTime error occurs due to Mouse fast movement
    On Error Resume Next

'    \\ Unhook & get out in case the application is deactivated
    If GetForegroundWindow <> FindWindow("XLMAIN", Application.Caption) Then
            Sheets("Sheet1").ComboBox1.TopLeftCell.Select
            UnHook_Mouse
            Exit Function
    End If

    If (nCode = HC_ACTION) Then
    
        If wParam = WM_MOUSEWHEEL Then
        
                '\\ Don't process Default WM_MOUSEWHEEL Window message
                LowLevelMouseProc = True
            
                '\\ Change Sheet&\DropDown names as required
                With Sheets("Sheet1").ComboBox1

            
              '\\ if rolling forward increase Top index by 1 to cause an Up Scroll
                If GetHookStruct(lParam).mouseData > 0 Then
                
                    .TopIndex = intTopIndex - 1
                
                    '\\ Store new TopIndex value
                    intTopIndex = .TopIndex
                
                Else '\\ if rolling backward decrease Top index by 1 to cause _
                '\\a Down Scroll
                
                    .TopIndex = intTopIndex + 1
                    
                    '\\ Store new TopIndex value
                    intTopIndex = .TopIndex
                
                End If
                
           End With

        End If
        
        Exit Function
    
    End If

    LowLevelMouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function

'=======================================================================
Sub Hook_Mouse()

hhkLowLevelMouse = SetWindowsHookEx _
(WH_MOUSE_LL, AddressOf LowLevelMouseProc, Application.Hinstance, 0)

End Sub

'========================================================================
Sub UnHook_Mouse()

    If hhkLowLevelMouse <> 0 Then UnhookWindowsHookEx hhkLowLevelMouse

End Sub


You will need to adapt the code for your UserForm.

Caution Note: :eek: This code uses a Windows Hook which makes it potentially dangerous. Please, save your Data before you Run or Edit the code.



Regards.
 
Upvote 0
I tried to use this code in Excel 2000 and if failed with "Object does not support this property or method." on this line
Code:
hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, AddressOf LowLevelMouseProc, Application.Hinstance, 0)
because Hinstance is not supported.

I am trying to use a UserForm with a ComboBox, any help appreciated. Thanks...
 
Upvote 0
[SOLVED] VBA code a combo box on a User form

Finally got the answer, for a combobox or listbox place the following code in your form code:
Code:
'------------------ComboBox MouseWheel----------------------------
Private Sub cboSysMetrics_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    'Store the first TopIndex Value
    intTopIndex = cboSysMetrics.TopIndex
    Hook_Mouse
End Sub
' Check to see if focus is lost
Private Sub cboSysMetrics_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    UnHook_Mouse
End Sub
Now place the following in a module:
Code:
'-----Allows use of MouseWheel on designated ListBox/ComboBox on a form or, sheet if modified.--------
Option Explicit
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Declare Function GetForegroundWindow Lib "user32" () As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
Declare Function SetWindowsHookEx Lib _
"user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Declare Function GetLastError Lib "kernel32" () As Long ' Used this one to crack the problem.
Type POINTAPI
  X As Long
  Y As Long
End Type
Type MSLLHOOKSTRUCT 'Will Hold the lParam struct Data
    pt As POINTAPI
    mouseData As Long ' Holds Forward\Bacward flag
    flags As Long
    time As Long
    dwExtraInfo As Long
End Type
Const HC_ACTION = 0
Const WH_MOUSE_LL = 14
Const WM_MOUSEWHEEL = &H20A
Public Const GWL_HINSTANCE = (-6)
Dim hhkLowLevelMouse, lngInitialColor As Long
Dim udtlParamStuct As MSLLHOOKSTRUCT
Public intTopIndex As Integer
'==========================================================================
'\\Copy the Data from lParam of the Hook Procedure argument to our Struct
Function GetHookStruct(ByVal lParam As Long) As MSLLHOOKSTRUCT
    ' VarPtr returns address; LenB returns size in bytes.
    CopyMemory VarPtr(udtlParamStuct), lParam, LenB(udtlParamStuct)
    GetHookStruct = udtlParamStuct
End Function
'===========================================================================
Function LowLevelMouseProc _
(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    'Avoid XL crashing if RunTime error occurs due to Mouse fast movement
    On Error Resume Next
'    \\ Unhook & get out in case the application is deactivated
    If GetForegroundWindow <> FindWindow("ThunderDFrame", UserForm1.Caption) Then
'        Sheets("Sheet1").ComboBox1.TopLeftCell.Select
        UnHook_Mouse
        Exit Function
    End If
    If (nCode = HC_ACTION) Then
 
        If wParam = WM_MOUSEWHEEL Then
 
            '\\ Don't process Default WM_MOUSEWHEEL Window message
            LowLevelMouseProc = True
 
            '\\ Change Sheet&\DropDown names as required
            With UserForm1.cboSysMetrics
                '\\ if rolling forward increase Top index by 1 to cause an Up Scroll
                If GetHookStruct(lParam).mouseData > 0 Then
 
                    .TopIndex = intTopIndex - 1
 
                    '\\ Store new TopIndex value
                    intTopIndex = .TopIndex
 
                Else '\\ if rolling backward decrease Top index by 1 to cause _
                '\\a Down Scroll
 
                    .TopIndex = intTopIndex + 1
 
                    '\\ Store new TopIndex value
                    intTopIndex = .TopIndex
 
                End If
           End With
        End If
        Exit Function
    End If
    LowLevelMouseProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function
'=======================================================================
Sub Hook_Mouse()
    ' Statement to maintain the handle of the hook if clicking outside of the control.
    ' There isn't a Hinstance for Application, so used GetWindowLong to get handle.
    If hhkLowLevelMouse < 1 Then hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, AddressOf LowLevelMouseProc, _
        GetWindowLong(FindWindow("ThunderDFrame", UserForm1.Caption), GWL_HINSTANCE), 0)
 
End Sub
 
'========================================================================
Sub UnHook_Mouse()
    If hhkLowLevelMouse <> 0 Then
        UnhookWindowsHookEx hhkLowLevelMouse
        hhkLowLevelMouse = 0
    End If
    MsgBox (GetLastError())
End Sub

The issue was that every time you clicked outside of the control you were hooking, the hook handle changed so that when you tried to exit the form, it had the wrong handle if the control with the hook was not the last thing you clicked on. Therefore, the hook stayed engaged and would crash excel if you were working in the VBE.
 
Upvote 0
Re: [SOLVED] VBA code a combo box on a User form

Hi and thanks to all for the tip. I'm have a problem with the code.

I'm using a 64 bit vba and have changed the Function declarations to "Ptrsafe Function" and also "intTopIndex = cboSysMetrics..TopIndex" to reflect the name of my combobox

I now get a type mismatch with "VarPtr" highlighted in "CopyMemory VarPtr(udtlParamStuct), lParam, LenB(udtlParamStuct)"

Any ideas?

Thanks to all for any kind input.
 
Upvote 0

Forum statistics

Threads
1,215,734
Messages
6,126,542
Members
449,316
Latest member
sravya

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top