You have encountered the joy of a control (ComboBox) having focus for a event message(MouseWheel) that you would prefer to have sent to its parent instead. In this case, the ComboBox has also has predefined function associated with the MouseWheel (it moves the selected item up/down the item list). I have modified your code to deal with this by allowing the message to pass to the control if the the pointer is positioned over it or to send the message to the control's parent (hard coded to be the Panel) if it pointer is not over the control. I tried to comment it enough to follow, but if you have any questions, feel free to ask.
Imports System.Runtime.InteropServices
Public Class Form1
Inherits System.Windows.Forms.Form
' Implement IMessageFilter so that we can intercept the scroll message
Implements IMessageFilter
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.Panel1 = New PanelWithExposedWndProc ' **** note change
Me.SuspendLayout()
'
'Panel1
'
Me.Panel1.Anchor = CType((System.Windows.Forms.AnchorStyles.Left Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
Me.Panel1.AutoScroll = True
Me.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
Me.Panel1.Location = New System.Drawing.Point(0, 0)
Me.Panel1.Name = "Panel1"
Me.Panel1.Size = New System.Drawing.Size(353, 408)
Me.Panel1.TabIndex = 0
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(353, 408)
Me.Controls.Add(Me.Panel1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
Public Sub New()
InitializeComponent()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
'on load add to Panel1 few comboboxes
Dim i As Integer
Dim YPosition As Integer = 0
For i = 0 To 35
Dim Combo As New System.Windows.Forms.ComboBox()
Combo.Items.AddRange(New Object() {"First", "Second", "Third"})
Combo.Location = New System.Drawing.Point(55, 95)
Combo.Size = New System.Drawing.Size(121, 21)
Combo.SelectedIndex = 0
Combo.Location = New Point(5, YPosition)
Me.Panel1.Controls.Add(Combo)
YPosition += Combo.Height + 15
Next
End Sub
'Friend WithEvents Panel1 As System.Windows.Forms.Panel
' Use the sub classed panel instead, need this to send it the scroll message
Friend WithEvents Panel1 As PanelWithExposedWndProc
Private Const WM_MOUSEWHEEL As Int32 = &H20A
Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
If m.Msg = WM_MOUSEWHEEL Then
' Get then control that message is directed to from the handle
Dim c As Control = Control.FromChildHandle(m.HWnd)
If c IsNot Nothing AndAlso c.Parent IsNot Nothing And c.Parent Is Panel1 Then
' The control in Focus is parented to Panel1
' Determine if the mouse pointer is currently over the control receiving the
' mouse wheel message
' 1st extract the mouse position from LParam
Dim MouseLocation As New Point(m.LParam.ToInt32() And &HFFFF, m.LParam.ToInt32() >> 16)
If Not c.ClientRectangle.Contains(c.PointToClient(MouseLocation)) Then
' pointer is not over the control, so block the message from going to the control in focus
' and resend the message to Panel1 so that it scrolls
m.HWnd = Panel1.Handle
Panel1.ProcessMessage(m)
Return True ' returning True blocks the message
End If
End If
End If
End Function
Private Sub Form1_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
' Message Filter is application wide, so only apply when this form is active
Application.AddMessageFilter(Me)
End Sub
Private Sub Form1_Deactivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate
' Message Filter is application wide, so only apply when this form is active
' Since this form has been deactivate, remove the filter
Application.RemoveMessageFilter(Me)
End Sub
End Class
Public Class PanelWithExposedWndProc
Inherits Panel
' This method just exposes the protected WndProc method
Friend Sub ProcessMessage(ByVal msg As Message)
Me.WndProc(msg)
End Sub
End Class