For React Native.
From: Zhiyi Zhang zzhang@codeweavers.com
The tests are mainly to show that SendMessageCallbackA/W() with NULL callback pointer and callback data being 1 causes message to be posted to window, even when the window is created in the same thread. --- dlls/user32/tests/msg.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 80d900baa1c..1c2d61c7781 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -16499,6 +16499,12 @@ static void test_EndDialog(void) UnregisterClassA(cls.lpszClassName, cls.hInstance); }
+static const struct message WmUserSeq[] = +{ + { WM_USER, sent }, + { 0 } +}; + static void test_nullCallback(void) { HWND hwnd; @@ -16507,8 +16513,39 @@ static void test_nullCallback(void) 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create overlapped window\n");
- SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0); + /* NULL callback and data being 0 */ + flush_sequence(); + SendMessageCallbackA(hwnd, WM_USER, 0, 0, NULL, 0); + ok_sequence(WmUserSeq, "WM_USER with NULL callback", FALSE); + + flush_sequence(); + SendMessageCallbackW(hwnd, WM_USER, 0, 0, NULL, 0); + ok_sequence(WmUserSeq, "WM_USER with NULL callback", FALSE); + + /* NULL callback and data being 1. The result suggests that the message is posted to the window */ + flush_sequence(); + SendMessageCallbackA(hwnd, WM_USER, 0, 0, NULL, 1); + ok_sequence(WmEmptySeq, "WM_USER with NULL callback", TRUE); flush_events(); + ok_sequence(WmUserSeq, "WM_USER with NULL callback after flushing events", TRUE); + + /* NULL callback and data being 1. The result suggests that the message is posted to the window */ + flush_sequence(); + SendMessageCallbackW(hwnd, WM_USER, 0, 0, NULL, 1); + ok_sequence(WmEmptySeq, "WM_USER with NULL callback", TRUE); + flush_events(); + ok_sequence(WmUserSeq, "WM_USER with NULL callback after flushing events", TRUE); + + /* NULL callback and data being 2 */ + flush_sequence(); + SendMessageCallbackA(hwnd, WM_USER, 0, 0, NULL, 2); + ok_sequence(WmUserSeq, "WM_USER with NULL callback", FALSE); + + /* NULL callback and data being 2 */ + flush_sequence(); + SendMessageCallbackW(hwnd, WM_USER, 0, 0, NULL, 2); + ok_sequence(WmUserSeq, "WM_USER with NULL callback", FALSE); + DestroyWindow(hwnd); }
From: Zhiyi Zhang zzhang@codeweavers.com
This is an undocumented behavior needed by React Native apps, based on Nikolay's findings. --- dlls/user32/message.c | 7 +++++++ dlls/user32/tests/msg.c | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 205d3e01c02..3b541959faf 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -640,6 +640,9 @@ BOOL WINAPI SendMessageCallbackA( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa { struct send_message_callback_params params = { .callback = callback, .data = data };
+ if (!callback && data == 1) + return PostMessageA( hwnd, msg, wparam, lparam ); + if (!WIN_IsCurrentThread( hwnd ) && !map_wparam_AtoW( msg, &wparam, WMCHAR_MAP_SENDMESSAGE )) return FALSE;
@@ -654,6 +657,10 @@ BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa SENDASYNCPROC callback, ULONG_PTR data ) { struct send_message_callback_params params = { .callback = callback, .data = data }; + + if (!callback && data == 1) + return PostMessageW( hwnd, msg, wparam, lparam ); + return NtUserMessageCall( hwnd, msg, wparam, lparam, ¶ms, NtUserSendMessageCallback, FALSE ); }
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 1c2d61c7781..9089e96aa84 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -16525,16 +16525,16 @@ static void test_nullCallback(void) /* NULL callback and data being 1. The result suggests that the message is posted to the window */ flush_sequence(); SendMessageCallbackA(hwnd, WM_USER, 0, 0, NULL, 1); - ok_sequence(WmEmptySeq, "WM_USER with NULL callback", TRUE); + ok_sequence(WmEmptySeq, "WM_USER with NULL callback", FALSE); flush_events(); - ok_sequence(WmUserSeq, "WM_USER with NULL callback after flushing events", TRUE); + ok_sequence(WmUserSeq, "WM_USER with NULL callback after flushing events", FALSE);
/* NULL callback and data being 1. The result suggests that the message is posted to the window */ flush_sequence(); SendMessageCallbackW(hwnd, WM_USER, 0, 0, NULL, 1); - ok_sequence(WmEmptySeq, "WM_USER with NULL callback", TRUE); + ok_sequence(WmEmptySeq, "WM_USER with NULL callback", FALSE); flush_events(); - ok_sequence(WmUserSeq, "WM_USER with NULL callback after flushing events", TRUE); + ok_sequence(WmUserSeq, "WM_USER with NULL callback after flushing events", FALSE);
/* NULL callback and data being 2 */ flush_sequence();
What's the reason for adding duplicate tests?
Also, it would be interesting to test the queue status.
On Mon Aug 4 07:36:35 2025 +0000, Dmitry Timoshkov wrote:
What's the reason for adding duplicate tests?
Both SendMessageCallbackA() and SendMessageCallbackW() are being tested. The main purpose is to test an undocumented behavior, so we need to know that it's not limited only to the A/W() variant.
On Mon Aug 4 07:36:35 2025 +0000, Dmitry Timoshkov wrote:
Also, it would be interesting to test the queue status.
Could you please elaborate on the queue status you would like me to test? I've added the message sequence tests.
On Mon Aug 4 07:36:35 2025 +0000, Zhiyi Zhang wrote:
Could you please elaborate on the queue status you would like me to test? I've added the message sequence tests.
The queue status would confirm that the message is supposed to be posted and not sent.
On Mon Aug 4 07:36:34 2025 +0000, Zhiyi Zhang wrote:
Both SendMessageCallbackA() and SendMessageCallbackW() are being tested. The main purpose is to test an undocumented behavior, so we need to know that it's not limited only to the A/W() variant.
Thanks. Probably a comment that clarifies that would be helpful.
Also it would be interesting to test return value of SendMessageCallback().