This article was previously published under Q102552
The scroll bar continuously scrolls even after you release the left mouse button. The type of scroll bar is irrelevant to this problem,that is, the same problem occurs regardless of whether the scroll baris part of the window or is a scroll bar control.
This problem occurs usually when a message retrieval loop is executedas the result of actions taken for scrolling upon receiving one of thescroll bar notification messages.
When scrolling, an internal message retrieval loop is started inWindows. The task of this message loop is to keep track of scrollingand to send the appropriate scroll bar notification messages,WM_HSCROLL and WM_VSCROLL. Scrolling is terminated once WM_LBUTTONUPis received. If another message loop is started during scrolling, theWM_LBUTTONUP is retrieved by that message loop, and because anapplication does not have access to the scroll bar's internal messageretrieval loop, WM_LBUTTONUP cannot be dispatched correctly.Therefore, the WM_LBUTTONUP is never received by the internal messageretriever, and scrolling is never ended.
The application that is scrolling does not have to retrieve messagesexplicitly to cause this problem. Calling any of the followingfunctions or processing any message that has a message retrieval loop,while scrolling, can cause the WM_LBUTTONUP to be lost. The functionslisted below fall into this category:
While Scrolling, the WM_LBUTTONUP message should not be retrieved fromthe queue by any message retrieval loop other than the scroll bar'sinternal one.
An application may come across this problem as follows:
An application implements a message retrieval loop to implement background processing, for example, background processing while performing a time consuming paint.
An application implements a message retrieval loop to implement communication with another application or DLL. For example, in order to scroll, the application needs to receive data from elsewhere.
Two possible workarounds are listed below. The first workaround isused by many exiting applications and by Windows; however, under rarecircumstances the first workaround may not be a feasible one. In thiscase, the second workaround may be used. However, if possible, pleasetry to avoid implementing message retrieval completely whilescrolling.
Use timer-message-based processing. Break down the complicated processing into smaller tasks and keep track of where each task starts and ends, then perform each task based on a timer message. When all components of the processing are complete, kill the timer. See below for an example of this workaround.
Implement a message retrieval loop, but make sure WM_LBUTTONUP is not retrieved by it. This can be accomplished by using filters. See below for some examples of this workaround.
Example demonstrating Workaround 1
An application has a complex paint procedure. Calling ScrollWindow(), toscroll, generates paint messages. Background processing takes placewhile painting.
When you receive the WM_PAINT message do the following:
Copy the invalidated rect to a global rect variable (for example, grcPaint) to be used in step 2. The global rect grcPaint would be a union of the previously obtained rect (grcPaint) and the new invalidated rect (ps.rcPaint). The code for this will resemble the following:
RECT grcPaint; // Should be initialized before getting the // first paint message. : : UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
Call ValidateRect() with ps.rcPaint.
Set a Timer.
This way, no more WM_PAINT messages are generated, because there are no invalid regions, and a timer is set up, which will generate WM_TIMER messages.
Upon receiving a WM_TIMER message, check the global rect variable; if it is not empty, take a section and paint it. Then adjust the global rect variable so it no longer includes the painted region.
Once the global rect variable is empty then kill the timer.
Example demonstrating Workaround 2
An application needs to obtain some data through DDE or some othermechanism from another application, which is then displayed in thewindow. In order to scroll, the application needs to request and thenobtain the data from a server application.
There are three different filters that can be used to set up aPeekMessage() and get the information. The filters can be set up byusing the uFilterFirst and uFilterLast parameters of PeekMessage().uFilterFirst specifies the fist message in the range to be checked anduFilterLast specifies the last message in the range to be checked.
Check and retrieve only the related message(s) for obtaining the needed data.
Check for WM_LBUTTONUP without removing it form the queue; if it is in the queue, break. Otherwise, retrieve and dispatch all messages.
Retrieve all messages less than WM_LBUTTONUP and greater than WM_LBUTTONUP, but do not retrieve WM_LBUTTONUP.
Steps to reproduce the problem
The following is the sequence of events leading to the loss ofthe WM_LBUTTONUP message:
Click the scroll bar using the mouse.
Step 1 generates a WM_NCLBUTTONDOWN message.
Step 2 causes a Windows internal message loop to be started. This message loop looks for scroll-bar-related messages. The purpose of this message loop is to generate appropriate WM_HSCROLL or WM_VSCROLL messages. The message loop and scrolling terminates once WM_LBUTTONUP is received.
When receiving the WM_HSCROLL or WM_VSCROLL message, the application either gets into a message retrieval loop directly or calls functions which result in retrieval of messages.
WM_LBUTTONUP is removed from the queue by the message loop mentioned in step 4. WM_LBUTTONUP is then dispatched.
As result of step 5 WM_LBUTTONUP message is dispatched elsewhere and the internal message retrieval loop, mentioned in step 3 never receives it. The message loop in step 3 is looking for the WM_LBUTTONUP to stop scrolling. Because it is not received, the scroll bar continues scrolling.