Indicates the type of messages found in the calling thread's message queue.

Code:
    Const QS_KEY As Int32 = 1
    Const QS_MOUSEMOVE As Int32 = 2
    Const QS_MOUSEBUTTON As Int32 = 4
    Const QS_POSTMESSAGE As Int32 = 8
    Const QS_TIMER As Int32 = 16
    Const QS_PAINT As Int32 = 32
    Const QS_SENDMESSAGE As Int32 = 64
    Const QS_HOTKEY As Int32 = 128
    Const QS_ALLPOSTMESSAGE As Int32 = 256
    Const QS_MOUSE As Int32 = (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
    Const QS_INPUT As Int32 = (QS_MOUSE Or QS_KEY)
    Const QS_ALLEVENTS As Int32 = (QS_INPUT Or QS_POSTMESSAGE Or QS_TIMER Or QS_PAINT Or QS_HOTKEY)
    Const QS_ALLINPUT As Int32 = (QS_SENDMESSAGE Or QS_PAINT Or QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or QS_KEY)
    Private Declare Function apiGetQueueStatus Lib "user32" Alias "GetQueueStatus" (ByVal fuFlags As Int32) As Int32
    Private bCancel As Boolean = False
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Button1.Text = "Start loop"
        Button2.Text = "Stop loop"
    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Do
            If apiGetQueueStatus(QS_ALLINPUT) <> 0 Then Application.DoEvents() 'Message in the queue will be flushed
            If bCancel = True Then Exit Do
        Loop
        MessageBox.Show("Done")
    End Sub
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        bCancel = True
    End Sub