증상
마우스 왼쪽 단추를 놓은 후에도 스크롤 막대는 계속 스크롤됩니다. 스크롤 막대의 유형은이 문제와 관련이 없으며, 스크롤 막대가 창의 일부 인지 스크롤 막대 컨트롤에 관계 없이 같은 문제가 발생 합니다.
원인
이 문제는 스크롤 막대 알림 메시지 중 하나를 받을 때 스크롤에 수행 된 작업의 결과로 인해 메시지 검색 루프가 실행 되는 경우 일반적으로 발생 합니다. 스크롤할 때 Windows에서 내부 메시지 검색 루프가 시작 됩니다. 이 메시지 루프의 작업은 스크롤을 추적 하 고 적절 한 스크롤 막대 알림 메시지, WM_HSCROLL 및 WM_VSCROLL을 전송 하는 것입니다. WM_LBUTTONUP 수신 되 면 스크롤이 종료 됩니다. 스크롤 하는 동안 다른 메시지 루프가 시작 되 면 해당 메시지 루프에서 WM_LBUTTONUP를 검색 하 고, 응용 프로그램에 스크롤 막대의 내부 메시지 검색 루프에 대 한 액세스 권한이 없으므로 WM_LBUTTONUP 올바르게 디스패치 되지 않습니다. 따라서 내부 메시지 검색기에서 WM_LBUTTONUP를 받을 수 없으며 스크롤이 종료 되지 않습니다. 스크롤 하는 응용 프로그램은이 문제를 발생 시킬 수 있도록 메시지를 명시적으로 검색할 필요가 없습니다. 스크롤 하는 동안 다음 함수 중 하나를 호출 하거나 메시지 검색 루프를 포함 하는 메시지를 처리 하면 WM_LBUTTONUP 손실 될 수 있습니다. 아래 나열 된 함수는이 범주에 속합니다.
DialogBox() DialogBoxIndirect() DialogBoxIndirectParam() DialogBoxParam() GetMessage() MessageBox() PeekMessage()
해결 방법
스크롤 하는 동안 스크롤 막대의 내부와 다른 메시지 검색 루프를 통해 큐에서 WM_LBUTTONUP 메시지를 검색 하지 않아야 합니다. 이 문제는 다음과 같이 응용 프로그램에서 발생할 수 있습니다.
-
응용 프로그램은 백그라운드 처리를 구현 하는 메시지 검색 루프 (예: 시간이 오래 걸리는 그리기를 수행 하는 백그라운드 처리)를 구현 합니다.
-
응용 프로그램은 메시지 검색 루프를 구현 하 여 다른 응용 프로그램 또는 DLL과의 통신을 구현 합니다. 예를 들어, 스크롤을 위해 응용 프로그램은 다른 곳에서 데이터를 받아야 합니다.
가능 해결 방법
두 가지 해결 방법이 아래에 나열 되어 있습니다. 첫 번째 해결 방법은 종료 하는 여러 응용 프로그램 및 Windows에서 사용 합니다. 그러나 드문 경우에는 첫 번째 해결 방법이 적절 하지 않을 수 있습니다. 이 경우 두 번째 해결 방법을 사용할 수 있습니다. 그러나 가능 하다 면 스크롤 하는 동안 메시지 검색을 완전히 구현 하지 않도록 하십시오.
-
타이머 메시지 기반 처리를 사용 합니다. 복잡 한 처리를 더 작은 작업으로 나누고 각 작업이 시작 되 고 끝나는 위치를 추적 한 다음 타이머 메시지에 따라 각 작업을 수행 합니다. 처리의 모든 구성 요소가 완료 되 면 타이머를 중단 합니다. 이 해결 방법의 예제는 아래를 참조 하세요.
-
메시지 검색 루프를 구현 하지만, WM_LBUTTONUP이를 통해 검색 되지 않도록 해야 합니다. 필터를 사용 하 여이 작업을 수행할 수 있습니다. 이 해결 방법의 몇 가지 예를 보려면 다음을 참조 하세요.
해결 방법 1을 보여 주는 예제
응용 프로그램에는 복잡 한 그리기 프로시저가 있습니다. ScrollWindow ()를 호출 하 여 스크롤하려면 paint 메시지를 생성 합니다. 백그라운드 처리는 그리기 중에 발생 합니다.
-
WM_PAINT 메시지가 나타나면 다음을 수행 합니다.
-
BeginPaint ()로 전화를 겁니다.
-
무효화 된 rect를 2 단계에서 사용 되는 전역 rect 변수 (예: grcPaint)에 복사 합니다. 전역 rect grcPaint는 이전에 가져온 rect (grcPaint) 및 새로운 무효화 된 rect (.ps Paint)의 합집합입니다. 이 작업을 수행 하는 코드는 다음과 유사 합니다.
RECT grcPaint; // Should be initialized before getting the // first paint message. : : UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
-
.Ps 그림판을 사용 하 여 ValidateRect ()를 호출 합니다.
-
EndPaint ()로 전화를 겁니다.
-
타이머를 설정 합니다.
이렇게 하면 잘못 된 영역이 없고 타이머가 설정 되어 WM_TIMER 메시지가 생성 되므로이 방법으로 WM_PAINT 메시지가 더 이상 생성 되지 않습니다.
-
-
WM_TIMER 메시지가 수신 되 면 전역 rect 변수를 확인 합니다. 비어 있지 않으면 섹션을 가져와 그립니다. 그런 다음 해당 전역 rect 변수를 조정 하 여 그려지는 영역을 더 이상 포함 하지 않도록 합니다.
-
전역 rect 변수가 비어 있으면 타이머를 중단 합니다.
해결 방법 2를 보여 주는 예제
응용 프로그램은 다른 응용 프로그램에서 DDE 또는 다른 메커니즘을 통해 일부 데이터를 가져와야 하며, 그 다음 창에 표시 됩니다. 스크롤을 위해 응용 프로그램에서 서버 응용 프로그램을 요청한 다음 데이터를 가져와야 합니다. PeekMessage ()를 설정 하 고 정보를 가져오는 데 사용할 수 있는 세 가지 다른 필터가 있습니다. PeekMessage ()의 uFilterFirst 및 Ufilterfirst 매개 변수를 사용 하 여 필터를 설정할 수 있습니다. uFilterFirst는 범위에서 검사할 펀치 메시지를 지정 하 고 Ufilterfirst는 검사할 범위의 마지막 메시지를 지정 합니다.
-
필요한 데이터를 얻기 위한 관련 메시지만 확인 하 고 검색 합니다.
-
대기열을 제거 하지 않고 WM_LBUTTONUP를 확인 합니다. 큐에 있으면 중단 합니다. 그렇지 않으면 모든 메시지를 검색 하 고 발송 합니다.
-
WM_LBUTTONUP 보다 작고 WM_LBUTTONUP 보다는 크지만 WM_LBUTTONUP는 검색 하지 않는 모든 메시지를 검색 합니다.
추가 정보
문제를 재현하는 방법
다음은 WM_LBUTTONUP 메시지의 손실에 대 한 이벤트의 순서입니다.
-
마우스를 사용 하 여 스크롤 막대를 클릭 합니다.
-
1 단계에서는 WM_NCLBUTTONDOWN 메시지가 생성 됩니다.
-
2 단계를 수행 하면 Windows 내부 메시지 루프가 시작 됩니다. 이 메시지 루프는 스크롤 막대 관련 메시지를 찾습니다. 이 메시지 루프의 목적은 적절 한 WM_HSCROLL 또는 WM_VSCROLL 메시지를 생성 하는 것입니다. WM_LBUTTONUP 수신 되 면 메시지 루프와 스크롤이 종료 됩니다.
-
WM_HSCROLL 또는 WM_VSCROLL 메시지를 수신 하는 경우 응용 프로그램에서 직접 메시지 검색 루프에 도달 하거나 메시지를 검색 하는 함수를 호출 합니다.
-
WM_LBUTTONUP는 4 단계에서 설명한 메시지 루프로 대기열에서 제거 됩니다. 그런 다음 WM_LBUTTONUP이 발송 됩니다.
-
WM_LBUTTONUP 5 단계의 결과로 메시지가 다른 곳에서 발송 되 고 3 단계에서 언급 한 내부 메시지 검색 루프는이를 받지 않습니다. 3 단계의 메시지 루프는 스크롤을 중지할 WM_LBUTTONUP을 찾습니다. 이 (가) 수신 되지 않으므로 스크롤 막대가 계속 스크롤을 수행 합니다.