Unfortunately, this can't be properly tested because of todo's in the message sequence. The event does show up in response to TPM_SETPOS, at least.
From: Esme Povirk esme@codeweavers.com
--- dlls/comctl32/tests/trackbar.c | 56 +++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-)
diff --git a/dlls/comctl32/tests/trackbar.c b/dlls/comctl32/tests/trackbar.c index a367b7e699c..71c68b2974c 100644 --- a/dlls/comctl32/tests/trackbar.c +++ b/dlls/comctl32/tests/trackbar.c @@ -50,10 +50,56 @@ static LRESULT WINAPI trackbar_no_wmpaint_proc(HWND hwnd, UINT message, WPARAM w
static struct msg_sequence *sequences[NUM_MSG_SEQUENCE];
+static void CALLBACK msg_winevent_proc(HWINEVENTHOOK hevent, + DWORD event, + HWND hwnd, + LONG object_id, + LONG child_id, + DWORD thread_id, + DWORD event_time) +{ + struct message msg = {0}; + char class_name[256]; + + /* ignore window and other system events */ + if (object_id != OBJID_CLIENT) return; + + /* ignore events not from a progress bar control */ + if (!GetClassNameA(hwnd, class_name, ARRAY_SIZE(class_name)) || + strcmp(class_name, TRACKBAR_CLASSA) != 0) + return; + + msg.message = event; + msg.flags = winevent_hook|wparam|lparam; + msg.wParam = object_id; + msg.lParam = child_id; + add_message(sequences, TRACKBAR_SEQ_INDEX, &msg); +} + +static void init_winevent_hook(void) { + hwineventhook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandleA(0), msg_winevent_proc, + 0, GetCurrentThreadId(), WINEVENT_INCONTEXT); + if (!hwineventhook) + win_skip( "no win event hook support\n" ); +} + +static void uninit_winevent_hook(void) { + if (!hwineventhook) + return; + + UnhookWinEvent(hwineventhook); + hwineventhook = 0; +} + static const struct message empty_seq[] = { {0} };
+static const struct message create_trackbar_wnd_seq[] = { + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + {0} +}; + static const struct message parent_create_trackbar_wnd_seq[] = { { WM_NOTIFYFORMAT, sent}, { WM_QUERYUISTATE, sent|optional}, @@ -130,10 +176,14 @@ static const struct message position_test_seq[] = { { TBM_GETPOS, sent}, { TBM_SETPOS, sent|wparam|lparam, TRUE, 5}, { WM_PAINT, sent|defwinproc}, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* v6 only */ + { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { TBM_GETPOS, sent}, { TBM_SETPOS, sent|wparam|lparam, TRUE, 5}, { TBM_SETPOS, sent|wparam|lparam, TRUE, 1000}, { WM_PAINT, sent|defwinproc}, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* v6 only */ + { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { TBM_GETPOS, sent}, { TBM_SETPOS, sent|wparam|lparam, FALSE, 20}, { TBM_GETPOS, sent}, @@ -1355,7 +1405,7 @@ static void test_create(void)
hWndTrackbar = create_trackbar(defaultstyle, hWndParent); ok(hWndTrackbar != NULL, "Expected non NULL value\n"); - ok_sequence(sequences, TRACKBAR_SEQ_INDEX, empty_seq, "create Trackbar Window", FALSE); + ok_sequence(sequences, TRACKBAR_SEQ_INDEX, create_trackbar_wnd_seq, "create Trackbar Window", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_trackbar_wnd_seq, "parent trackbar window", TRUE);
DestroyWindow(hWndTrackbar); @@ -1386,6 +1436,8 @@ START_TEST(trackbar) return; }
+ init_winevent_hook(); + test_create(); test_trackbar_buddy(); test_line_size(); @@ -1420,6 +1472,8 @@ START_TEST(trackbar) test_ignore_selection(); test_initial_state();
+ uninit_winevent_hook(); + unload_v6_module(cookie, ctxt);
DestroyWindow(hWndParent);
From: Esme Povirk esme@codeweavers.com
--- dlls/comctl32/trackbar.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/comctl32/trackbar.c b/dlls/comctl32/trackbar.c index f2cb2a07a8d..461f3f3e437 100644 --- a/dlls/comctl32/trackbar.c +++ b/dlls/comctl32/trackbar.c @@ -1237,6 +1237,8 @@ TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition) { TRACKBAR_UpdateThumb(infoPtr); TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition); + + NotifyWinEvent( EVENT_OBJECT_VALUECHANGE, infoPtr->hwndSelf, OBJID_CLIENT, CHILDID_SELF ); }
return 0;
Nikolay Sivov (@nsivov) commented about dlls/comctl32/trackbar.c:
{ TRACKBAR_UpdateThumb(infoPtr); TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
NotifyWinEvent( EVENT_OBJECT_VALUECHANGE, infoPtr->hwndSelf, OBJID_CLIENT, CHILDID_SELF );
}
return 0;
This is not the only place where the value changes. Also here it's only notified when both changed and invalidated, is this correct?
On Sat May 17 09:21:24 2025 +0000, Nikolay Sivov wrote:
This is not the only place where the value changes. Also here it's only notified when both changed and invalidated, is this correct?
This is what the results on Windows seem to indicate. `position_test_seq` shows a VALUECHANGE event only for the TBM_SETPOS messages that cause a WM_PAINT. `range_test_seq` doesn't show any events even when it causes a repaint, and if I understand it correctly, it should be moving the thumb in some of those cases.
Unfortunately, this seems to be a case where MSAA events are insufficient to follow some changes, and one needs hooks or polling.
This merge request was approved by Nikolay Sivov.