mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[USER32_APITEST] Improve MessageStateAnalyzer testcase
CORE-15289, CORE-11700
This commit is contained in:
parent
942b0221e8
commit
c39bf0d54b
2 changed files with 257 additions and 489 deletions
|
@ -64,7 +64,7 @@ add_executable(user32_apitest
|
||||||
|
|
||||||
target_link_libraries(user32_apitest wine ${PSEH_LIB})
|
target_link_libraries(user32_apitest wine ${PSEH_LIB})
|
||||||
set_module_type(user32_apitest win32cui)
|
set_module_type(user32_apitest win32cui)
|
||||||
add_importlibs(user32_apitest advapi32 gdi32 user32 msvcrt kernel32 ntdll)
|
add_importlibs(user32_apitest advapi32 imm32 gdi32 user32 msvcrt kernel32 ntdll)
|
||||||
add_pch(user32_apitest precomp.h "${PCH_SKIP_SOURCE}")
|
add_pch(user32_apitest precomp.h "${PCH_SKIP_SOURCE}")
|
||||||
add_rostests_file(TARGET user32_apitest)
|
add_rostests_file(TARGET user32_apitest)
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,26 @@
|
||||||
* PROJECT: ReactOS API tests
|
* PROJECT: ReactOS API tests
|
||||||
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
|
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
|
||||||
* PURPOSE: debugging and analysis of message states
|
* PURPOSE: debugging and analysis of message states
|
||||||
* COPYRIGHT: Copyright 2019 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
* COPYRIGHT: Copyright 2019-2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
#include "undocuser.h"
|
#include "undocuser.h"
|
||||||
#include "winxx.h"
|
#include "winxx.h"
|
||||||
|
#include <imm.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
#define MAX_MSGS 512
|
||||||
|
|
||||||
|
static MSG s_Msgs[MAX_MSGS];
|
||||||
|
static UINT s_cMsgs = 0;
|
||||||
|
static CHAR s_prefix[16] = "";
|
||||||
|
static HWND s_hMainWnd = NULL;
|
||||||
|
static HWND s_hwndEdit = NULL;
|
||||||
|
static HWND s_hImeWnd = NULL;
|
||||||
|
static WNDPROC s_fnOldEditWndProc = NULL;
|
||||||
|
static WNDPROC s_fnOldImeWndProc = NULL;
|
||||||
|
|
||||||
static void MsgDumpPrintf(LPCSTR fmt, ...)
|
static void MsgDumpPrintf(LPCSTR fmt, ...)
|
||||||
{
|
{
|
||||||
static char s_szText[1024];
|
static char s_szText[1024];
|
||||||
|
@ -20,262 +32,10 @@ static void MsgDumpPrintf(LPCSTR fmt, ...)
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
#define MSGDUMP_TPRINTF MsgDumpPrintf
|
#define MSGDUMP_TPRINTF MsgDumpPrintf
|
||||||
static char s_prefix[16] = "";
|
|
||||||
#define MSGDUMP_PREFIX s_prefix
|
#define MSGDUMP_PREFIX s_prefix
|
||||||
#include "msgdump.h" /* msgdump.h needs MSGDUMP_TPRINTF and MSGDUMP_PREFIX */
|
#include "msgdump.h" /* msgdump.h needs MSGDUMP_TPRINTF and MSGDUMP_PREFIX */
|
||||||
|
|
||||||
typedef enum STAGE_TYPE
|
static void MD_build_prefix(void)
|
||||||
{
|
|
||||||
STAGE_TYPE_SEQUENCE,
|
|
||||||
STAGE_TYPE_COUNTING
|
|
||||||
} STAGE_TYPE;
|
|
||||||
|
|
||||||
typedef struct STAGE
|
|
||||||
{
|
|
||||||
INT nLine;
|
|
||||||
UINT uParentMsg;
|
|
||||||
INT nLevel;
|
|
||||||
STAGE_TYPE nType;
|
|
||||||
INT iFirstAction;
|
|
||||||
INT nCount;
|
|
||||||
UINT uMessages[10];
|
|
||||||
INT iActions[10];
|
|
||||||
INT nCounters[10];
|
|
||||||
} STAGE;
|
|
||||||
|
|
||||||
/* variables */
|
|
||||||
static INT s_iStage;
|
|
||||||
static INT s_iStep;
|
|
||||||
static INT s_nLevel;
|
|
||||||
static BOOL s_bNextStage;
|
|
||||||
static INT s_nCounters[10];
|
|
||||||
static UINT s_msgStack[32];
|
|
||||||
static const STAGE *s_pStages;
|
|
||||||
static INT s_cStages;
|
|
||||||
|
|
||||||
/* macros */
|
|
||||||
#define TIMEOUT_TIMER 999
|
|
||||||
#define TOTAL_TIMEOUT (5 * 1000)
|
|
||||||
#define WIDTH 300
|
|
||||||
#define HEIGHT 200
|
|
||||||
#define PARENT_MSG s_msgStack[s_nLevel - 1]
|
|
||||||
|
|
||||||
static void DoInitialize(const STAGE *pStages, INT cStages)
|
|
||||||
{
|
|
||||||
s_iStage = s_iStep = s_nLevel = 0;
|
|
||||||
s_bNextStage = FALSE;
|
|
||||||
ZeroMemory(s_nCounters, sizeof(s_nCounters));
|
|
||||||
ZeroMemory(s_msgStack, sizeof(s_msgStack));
|
|
||||||
s_pStages = pStages;
|
|
||||||
s_cStages = cStages;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DoFinish(void)
|
|
||||||
{
|
|
||||||
ok_int(s_iStage, s_cStages);
|
|
||||||
if (s_iStage != s_cStages)
|
|
||||||
{
|
|
||||||
skip("Some stage(s) skipped (Step: %d)\n", s_iStep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum ACTION
|
|
||||||
{
|
|
||||||
ACTION_ZERO = 0,
|
|
||||||
ACTION_FIRSTMINMAX,
|
|
||||||
ACTION_NCCREATE,
|
|
||||||
ACTION_SHOW,
|
|
||||||
ACTION_IME_SETCONTEXT_OPEN,
|
|
||||||
ACTION_IME_NOTIFY_OPEN,
|
|
||||||
ACTION_DESTROY,
|
|
||||||
ACTION_IME_SETCONTEXT_CLOSE,
|
|
||||||
ACTION_IME_NOTIFY_CLOSE,
|
|
||||||
ACTION_HIDE,
|
|
||||||
ACTION_DEACTIVATE,
|
|
||||||
ACTION_ACTIVATE
|
|
||||||
} ACTION;
|
|
||||||
|
|
||||||
static void DoAction(HWND hwnd, INT iAction, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
RECT rc;
|
|
||||||
switch (iAction)
|
|
||||||
{
|
|
||||||
case ACTION_ZERO:
|
|
||||||
/* does nothing */
|
|
||||||
break;
|
|
||||||
case ACTION_FIRSTMINMAX:
|
|
||||||
GetWindowRect(hwnd, &rc);
|
|
||||||
ok_long(rc.right - rc.left, 0);
|
|
||||||
ok_long(rc.bottom - rc.top, 0);
|
|
||||||
ok_int(IsWindowVisible(hwnd), FALSE);
|
|
||||||
break;
|
|
||||||
case ACTION_NCCREATE:
|
|
||||||
GetWindowRect(hwnd, &rc);
|
|
||||||
ok_long(rc.right - rc.left, WIDTH);
|
|
||||||
ok_long(rc.bottom - rc.top, HEIGHT);
|
|
||||||
ok_int(IsWindowVisible(hwnd), FALSE);
|
|
||||||
break;
|
|
||||||
case ACTION_SHOW:
|
|
||||||
ShowWindow(hwnd, SW_SHOWNORMAL);
|
|
||||||
break;
|
|
||||||
case ACTION_IME_SETCONTEXT_OPEN:
|
|
||||||
ok(wParam == 1, "Step %d: wParam was %p\n", s_iStep, (void *)wParam);
|
|
||||||
ok(lParam == 0xC000000F, "Step %d: lParam was %p\n", s_iStep, (void *)lParam);
|
|
||||||
break;
|
|
||||||
case ACTION_IME_NOTIFY_OPEN:
|
|
||||||
ok(wParam == 2, "Step %d: wParam was %p\n", s_iStep, (void *)wParam);
|
|
||||||
ok(lParam == 0, "Step %d: lParam was %p\n", s_iStep, (void *)lParam);
|
|
||||||
break;
|
|
||||||
case ACTION_DESTROY:
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
break;
|
|
||||||
case ACTION_IME_SETCONTEXT_CLOSE:
|
|
||||||
ok(wParam == 0, "Step %d: wParam was %p\n", s_iStep, (void *)wParam);
|
|
||||||
ok(lParam == 0xC000000F, "Step %d: lParam was %p\n", s_iStep, (void *)lParam);
|
|
||||||
break;
|
|
||||||
case ACTION_IME_NOTIFY_CLOSE:
|
|
||||||
ok(wParam == 1, "Step %d: wParam was %p\n", s_iStep, (void *)wParam);
|
|
||||||
ok(lParam == 0, "Step %d: lParam was %p\n", s_iStep, (void *)lParam);
|
|
||||||
break;
|
|
||||||
case ACTION_HIDE:
|
|
||||||
ShowWindow(hwnd, SW_HIDE);
|
|
||||||
break;
|
|
||||||
case ACTION_DEACTIVATE:
|
|
||||||
SetForegroundWindow(GetDesktopWindow());
|
|
||||||
break;
|
|
||||||
case ACTION_ACTIVATE:
|
|
||||||
SetForegroundWindow(hwnd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void NextStage(HWND hwnd)
|
|
||||||
{
|
|
||||||
INT i, iAction;
|
|
||||||
const STAGE *pStage = &s_pStages[s_iStage];
|
|
||||||
|
|
||||||
if (pStage->nType == STAGE_TYPE_COUNTING)
|
|
||||||
{
|
|
||||||
/* check counters */
|
|
||||||
for (i = 0; i < pStage->nCount; ++i)
|
|
||||||
{
|
|
||||||
if (pStage->nCounters[i] > 0)
|
|
||||||
{
|
|
||||||
ok(pStage->nCounters[i] == s_nCounters[i],
|
|
||||||
"Line %d: s_nCounters[%d] expected %d but %d.\n",
|
|
||||||
pStage->nLine, i, pStage->nCounters[i], s_nCounters[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* go to next stage */
|
|
||||||
++s_iStage;
|
|
||||||
if (s_iStage >= s_cStages)
|
|
||||||
{
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
trace("Stage %d (Line %d)\n", s_iStage, s_pStages[s_iStage].nLine);
|
|
||||||
|
|
||||||
s_iStep = 0;
|
|
||||||
ZeroMemory(s_nCounters, sizeof(s_nCounters));
|
|
||||||
|
|
||||||
iAction = s_pStages[s_iStage].iFirstAction;
|
|
||||||
if (iAction)
|
|
||||||
PostMessage(hwnd, WM_COMMAND, iAction, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DoStage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
INT i, iAction;
|
|
||||||
const STAGE *pStage;
|
|
||||||
s_bNextStage = FALSE;
|
|
||||||
|
|
||||||
if (s_iStage >= s_cStages)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pStage = &s_pStages[s_iStage];
|
|
||||||
switch (pStage->nType)
|
|
||||||
{
|
|
||||||
case STAGE_TYPE_SEQUENCE:
|
|
||||||
if (pStage->uMessages[s_iStep] == uMsg)
|
|
||||||
{
|
|
||||||
ok_int(1, 1);
|
|
||||||
ok(s_nLevel == pStage->nLevel,
|
|
||||||
"Line %d, Step %d: Level expected %d but %d.\n",
|
|
||||||
pStage->nLine, s_iStep, pStage->nLevel, s_nLevel);
|
|
||||||
ok(PARENT_MSG == pStage->uParentMsg,
|
|
||||||
"Line %d, Step %d: PARENT_MSG expected %u but %u.\n",
|
|
||||||
pStage->nLine, s_iStep, pStage->uParentMsg, PARENT_MSG);
|
|
||||||
|
|
||||||
iAction = pStage->iActions[s_iStep];
|
|
||||||
if (iAction)
|
|
||||||
DoAction(hwnd, iAction, wParam, lParam);
|
|
||||||
|
|
||||||
++s_iStep;
|
|
||||||
if (s_iStep >= pStage->nCount)
|
|
||||||
s_bNextStage = TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STAGE_TYPE_COUNTING:
|
|
||||||
for (i = 0; i < pStage->nCount; ++i)
|
|
||||||
{
|
|
||||||
if (pStage->uMessages[i] == uMsg)
|
|
||||||
{
|
|
||||||
ok_int(1, 1);
|
|
||||||
ok(s_nLevel == pStage->nLevel,
|
|
||||||
"Line %d: Level expected %d but %d.\n",
|
|
||||||
pStage->nLine, pStage->nLevel, s_nLevel);
|
|
||||||
ok(PARENT_MSG == pStage->uParentMsg,
|
|
||||||
"Line %d: PARENT_MSG expected %u but %u.\n",
|
|
||||||
pStage->nLine, pStage->uParentMsg, PARENT_MSG);
|
|
||||||
|
|
||||||
iAction = pStage->iActions[i];
|
|
||||||
if (iAction)
|
|
||||||
DoAction(hwnd, iAction, wParam, lParam);
|
|
||||||
|
|
||||||
++s_nCounters[i];
|
|
||||||
|
|
||||||
if (i == pStage->nCount - 1)
|
|
||||||
s_bNextStage = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_bNextStage)
|
|
||||||
{
|
|
||||||
NextStage(hwnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static LRESULT CALLBACK
|
|
||||||
InnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
switch (uMsg)
|
|
||||||
{
|
|
||||||
case WM_COMMAND:
|
|
||||||
DoAction(hwnd, LOWORD(wParam), 0, 0);
|
|
||||||
break;
|
|
||||||
case WM_TIMER:
|
|
||||||
KillTimer(hwnd, (UINT)wParam);
|
|
||||||
if (wParam == TIMEOUT_TIMER)
|
|
||||||
DestroyWindow(hwnd);
|
|
||||||
break;
|
|
||||||
case WM_DESTROY:
|
|
||||||
PostQuitMessage(0);
|
|
||||||
break;
|
|
||||||
case WM_NCCREATE:
|
|
||||||
SetTimer(hwnd, TIMEOUT_TIMER, TOTAL_TIMEOUT, NULL);
|
|
||||||
/* FALL THROUGH */
|
|
||||||
default:
|
|
||||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DoBuildPrefix(void)
|
|
||||||
{
|
{
|
||||||
DWORD Flags = InSendMessageEx(NULL);
|
DWORD Flags = InSendMessageEx(NULL);
|
||||||
INT i = 0;
|
INT i = 0;
|
||||||
|
@ -296,279 +56,287 @@ static void DoBuildPrefix(void)
|
||||||
s_prefix[i] = 0;
|
s_prefix[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const STAGE s_GeneralStages[] =
|
#define STAGE_1 1
|
||||||
|
#define STAGE_2 2
|
||||||
|
#define STAGE_3 3
|
||||||
|
#define STAGE_4 4
|
||||||
|
#define STAGE_5 5
|
||||||
|
|
||||||
|
static INT findMessage(INT iMsg, HWND hwnd, UINT uMsg)
|
||||||
{
|
{
|
||||||
/* Stage 0 */
|
if (iMsg == -1)
|
||||||
|
iMsg = 0;
|
||||||
|
for (; iMsg < s_cMsgs; ++iMsg)
|
||||||
{
|
{
|
||||||
__LINE__, WM_NULL, 1, STAGE_TYPE_SEQUENCE, 0,
|
if (s_Msgs[iMsg].message == uMsg && s_Msgs[iMsg].hwnd == hwnd)
|
||||||
4,
|
return iMsg;
|
||||||
{ WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, WM_CREATE },
|
}
|
||||||
{ ACTION_FIRSTMINMAX, ACTION_NCCREATE, 0, 0 },
|
return -1;
|
||||||
},
|
}
|
||||||
/* Stage 1 */
|
|
||||||
|
typedef struct TEST_ENTRY
|
||||||
|
{
|
||||||
|
INT line;
|
||||||
|
LPCSTR name;
|
||||||
|
UINT iFound;
|
||||||
|
} TEST_ENTRY, *PTEST_ENTRY;
|
||||||
|
|
||||||
|
static VOID DoAnalyzeEntries(size_t nCount, PTEST_ENTRY pEntries)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < nCount - 1; ++i)
|
||||||
{
|
{
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, ACTION_SHOW,
|
PTEST_ENTRY entry1 = &pEntries[i];
|
||||||
6,
|
PTEST_ENTRY entry2 = &pEntries[i + 1];
|
||||||
{ WM_SHOWWINDOW, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGING,
|
ok(entry1->iFound < entry2->iFound,
|
||||||
WM_ACTIVATEAPP, WM_NCACTIVATE, WM_ACTIVATE },
|
"Line %d: message wrong order (%d >= %d): %s vs %s\n",
|
||||||
},
|
entry1->line, entry1->iFound, entry2->iFound,
|
||||||
|
entry1->name, entry2->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID DoAnalyzeAllMessages(VOID)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
TEST_ENTRY entries1[] =
|
||||||
{
|
{
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, ACTION_DESTROY,
|
{ __LINE__, "WM_NCCREATE", findMessage(0, s_hMainWnd, WM_NCCREATE) },
|
||||||
6,
|
{ __LINE__, "WM_NCCALCSIZE", findMessage(0, s_hMainWnd, WM_NCCALCSIZE) },
|
||||||
{ WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED, WM_NCACTIVATE,
|
{ __LINE__, "WM_CREATE", findMessage(0, s_hMainWnd, WM_CREATE) },
|
||||||
WM_ACTIVATE, WM_ACTIVATEAPP, WM_KILLFOCUS },
|
{ __LINE__, "WM_PARENTNOTIFY", findMessage(0, s_hMainWnd, WM_PARENTNOTIFY) },
|
||||||
},
|
{ __LINE__, "WM_WINDOWPOSCHANGING", findMessage(0, s_hMainWnd, WM_WINDOWPOSCHANGING) },
|
||||||
|
{ __LINE__, "WM_ACTIVATEAPP", findMessage(0, s_hMainWnd, WM_ACTIVATEAPP) },
|
||||||
|
{ __LINE__, "WM_NCACTIVATE", findMessage(0, s_hMainWnd, WM_NCACTIVATE) },
|
||||||
|
{ __LINE__, "WM_ACTIVATE", findMessage(0, s_hMainWnd, WM_ACTIVATE) },
|
||||||
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(0, s_hMainWnd, WM_IME_SETCONTEXT) },
|
||||||
|
{ __LINE__, "WM_IME_NOTIFY", findMessage(0, s_hMainWnd, WM_IME_NOTIFY) },
|
||||||
|
{ __LINE__, "WM_SETFOCUS", findMessage(0, s_hMainWnd, WM_SETFOCUS) },
|
||||||
|
{ __LINE__, "WM_KILLFOCUS", findMessage(0, s_hMainWnd, WM_KILLFOCUS) },
|
||||||
|
};
|
||||||
|
INT iFound1 = entries1[_countof(entries1) - 1].iFound;
|
||||||
|
TEST_ENTRY entries2[] =
|
||||||
{
|
{
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, 0,
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hMainWnd, WM_IME_SETCONTEXT) },
|
||||||
2,
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hwndEdit, WM_IME_SETCONTEXT) },
|
||||||
{ WM_DESTROY, WM_NCDESTROY },
|
{ __LINE__, "WM_SETFOCUS", findMessage(iFound1, s_hwndEdit, WM_SETFOCUS) },
|
||||||
},
|
{ __LINE__, "WM_SHOWWINDOW", findMessage(iFound1, s_hMainWnd, WM_SHOWWINDOW) },
|
||||||
};
|
{ __LINE__, "WM_WINDOWPOSCHANGING", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGING) },
|
||||||
|
{ __LINE__, "WM_NCPAINT", findMessage(iFound1, s_hMainWnd, WM_NCPAINT) },
|
||||||
|
{ __LINE__, "WM_ERASEBKGND", findMessage(iFound1, s_hMainWnd, WM_ERASEBKGND) },
|
||||||
|
{ __LINE__, "WM_WINDOWPOSCHANGED", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGED) },
|
||||||
|
{ __LINE__, "WM_SIZE", findMessage(iFound1, s_hMainWnd, WM_SIZE) },
|
||||||
|
{ __LINE__, "WM_MOVE", findMessage(iFound1, s_hMainWnd, WM_MOVE) },
|
||||||
|
};
|
||||||
|
INT iFound2 = entries2[_countof(entries2) - 1].iFound;
|
||||||
|
TEST_ENTRY entries3[] =
|
||||||
|
{
|
||||||
|
{ __LINE__, "WM_IME_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_IME_KEYDOWN) },
|
||||||
|
{ __LINE__, "WM_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_KEYDOWN) },
|
||||||
|
{ __LINE__, "WM_IME_KEYUP", findMessage(iFound2, s_hwndEdit, WM_IME_KEYUP) },
|
||||||
|
{ __LINE__, "WM_CHAR", findMessage(iFound2, s_hwndEdit, WM_CHAR) },
|
||||||
|
{ __LINE__, "WM_IME_CHAR", findMessage(iFound2, s_hwndEdit, WM_IME_CHAR) },
|
||||||
|
};
|
||||||
|
INT iFound3 = entries3[_countof(entries3) - 1].iFound;
|
||||||
|
TEST_ENTRY entries4[] =
|
||||||
|
{
|
||||||
|
{ __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hwndEdit, WM_IME_NOTIFY) },
|
||||||
|
{ __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hImeWnd, WM_IME_NOTIFY) },
|
||||||
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hwndEdit, WM_IME_SETCONTEXT) },
|
||||||
|
{ __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hImeWnd, WM_IME_SETCONTEXT) },
|
||||||
|
};
|
||||||
|
INT iFound4 = entries4[_countof(entries4) - 1].iFound;
|
||||||
|
TEST_ENTRY entries5[] =
|
||||||
|
{
|
||||||
|
{ __LINE__, "WM_DESTROY", findMessage(iFound4, s_hMainWnd, WM_DESTROY) },
|
||||||
|
{ __LINE__, "WM_DESTROY", findMessage(iFound4, s_hwndEdit, WM_DESTROY) },
|
||||||
|
{ __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hwndEdit, WM_NCDESTROY) },
|
||||||
|
{ __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hMainWnd, WM_NCDESTROY) },
|
||||||
|
};
|
||||||
|
DoAnalyzeEntries(_countof(entries1), entries1);
|
||||||
|
DoAnalyzeEntries(_countof(entries2), entries2);
|
||||||
|
DoAnalyzeEntries(_countof(entries3), entries3);
|
||||||
|
//DoAnalyzeEntries(_countof(entries4), entries4); // No order
|
||||||
|
DoAnalyzeEntries(_countof(entries5), entries5);
|
||||||
|
|
||||||
|
ok(iFound1 < entries2[0].iFound, "%d vs %d\n", iFound1, entries2[0].iFound);
|
||||||
|
ok(iFound2 < entries3[0].iFound, "%d vs %d\n", iFound2, entries3[0].iFound);
|
||||||
|
ok(iFound3 < entries4[0].iFound, "%d vs %d\n", iFound3, entries4[0].iFound);
|
||||||
|
ok(iFound4 < entries5[0].iFound, "%d vs %d\n", iFound4, entries5[0].iFound);
|
||||||
|
|
||||||
|
for (i = 0; i < _countof(entries4); ++i)
|
||||||
|
{
|
||||||
|
ok(entries4[i].iFound != -1, "entries4[%d].iFound was -1\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static LRESULT CALLBACK
|
static LRESULT CALLBACK
|
||||||
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
LRESULT lResult;
|
LRESULT ret;
|
||||||
|
MSG msg = { hwnd, uMsg, wParam, lParam };
|
||||||
|
|
||||||
/* Skip asynchronous WM_TIMER messages */
|
/* Build s_prefix */
|
||||||
if (uMsg == WM_TIMER) return InnerWindowProc(hwnd, uMsg, wParam, lParam);
|
MD_build_prefix();
|
||||||
|
|
||||||
/* build s_prefix */
|
|
||||||
DoBuildPrefix();
|
|
||||||
|
|
||||||
/* message dump */
|
/* message dump */
|
||||||
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
||||||
|
|
||||||
++s_nLevel;
|
/* Add message */
|
||||||
s_msgStack[s_nLevel] = uMsg;
|
s_Msgs[s_cMsgs++] = msg;
|
||||||
{
|
|
||||||
/* do inner task */
|
/* Do inner task */
|
||||||
DoStage(hwnd, uMsg, wParam, lParam);
|
ret = CallWindowProc(s_fnOldEditWndProc, hwnd, uMsg, wParam, lParam);
|
||||||
lResult = InnerWindowProc(hwnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
--s_nLevel;
|
|
||||||
|
|
||||||
/* message return */
|
/* message return */
|
||||||
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
||||||
MD_msgresult(hwnd, uMsg, wParam, lParam, lResult);
|
MD_msgresult(hwnd, uMsg, wParam, lParam, ret);
|
||||||
return lResult;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void General_DoTest(void)
|
static LRESULT CALLBACK
|
||||||
|
ImeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
WNDCLASSA wc;
|
LRESULT ret;
|
||||||
HWND hwnd;
|
MSG msg = { hwnd, uMsg, wParam, lParam };
|
||||||
MSG msg;
|
|
||||||
static const char s_szName[] = "MessageStateAnalyzerGeneral";
|
|
||||||
|
|
||||||
trace("General_DoTest\n");
|
/* Build s_prefix */
|
||||||
DoInitialize(s_GeneralStages, ARRAYSIZE(s_GeneralStages));
|
MD_build_prefix();
|
||||||
|
|
||||||
/* register window class */
|
/* message dump */
|
||||||
ZeroMemory(&wc, sizeof(wc));
|
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
||||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
|
||||||
wc.lpfnWndProc = WindowProc;
|
|
||||||
wc.hInstance = GetModuleHandleA(NULL);
|
|
||||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
||||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
|
||||||
wc.lpszClassName = s_szName;
|
|
||||||
if (!RegisterClassA(&wc))
|
|
||||||
{
|
|
||||||
skip("RegisterClassW failed.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create a window */
|
/* Add message */
|
||||||
hwnd = CreateWindowA(s_szName, s_szName, WS_OVERLAPPEDWINDOW,
|
s_Msgs[s_cMsgs++] = msg;
|
||||||
0, 0, WIDTH, HEIGHT, NULL, NULL,
|
|
||||||
GetModuleHandleW(NULL), NULL);
|
|
||||||
if (!hwnd)
|
|
||||||
{
|
|
||||||
skip("CreateWindowW failed.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* message loop */
|
/* Do inner task */
|
||||||
while (GetMessageA(&msg, NULL, 0, 0))
|
ret = CallWindowProc(s_fnOldImeWndProc, hwnd, uMsg, wParam, lParam);
|
||||||
{
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessageA(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
ok_int(UnregisterClassA(s_szName, GetModuleHandleA(NULL)), TRUE);
|
/* message return */
|
||||||
|
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
||||||
|
MD_msgresult(hwnd, uMsg, wParam, lParam, ret);
|
||||||
|
|
||||||
DoFinish();
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const STAGE s_IMEStages[] =
|
static LRESULT CALLBACK
|
||||||
|
InnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
/* Stage 0 */
|
switch (uMsg)
|
||||||
{
|
{
|
||||||
__LINE__, WM_NULL, 1, STAGE_TYPE_SEQUENCE, 0,
|
case WM_NCCREATE:
|
||||||
4,
|
s_hMainWnd = hwnd;
|
||||||
{ WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, WM_CREATE },
|
trace("s_hMainWnd: %p\n", s_hMainWnd);
|
||||||
{ ACTION_FIRSTMINMAX, ACTION_NCCREATE, 0, 0 },
|
break;
|
||||||
},
|
case WM_CREATE:
|
||||||
/* Stage 1 */
|
s_hwndEdit = CreateWindowW(L"EDIT", NULL, WS_CHILD | WS_VISIBLE,
|
||||||
// show
|
0, 0, 100, 20, hwnd, NULL, GetModuleHandleW(NULL), NULL);
|
||||||
{
|
ok(s_hwndEdit != NULL, "s_hwndEdit was NULL\n");
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, ACTION_SHOW,
|
trace("s_hwndEdit: %p\n", s_hwndEdit);
|
||||||
6,
|
s_fnOldEditWndProc =
|
||||||
{ WM_SHOWWINDOW, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGING,
|
(WNDPROC)SetWindowLongPtrW(s_hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditWindowProc);
|
||||||
WM_ACTIVATEAPP, WM_NCACTIVATE, WM_ACTIVATE },
|
SetFocus(s_hwndEdit);
|
||||||
},
|
PostMessageW(hwnd, WM_COMMAND, STAGE_1, 0);
|
||||||
{
|
break;
|
||||||
__LINE__, WM_ACTIVATE, 3, STAGE_TYPE_SEQUENCE, 0,
|
case WM_COMMAND:
|
||||||
1,
|
switch (LOWORD(wParam))
|
||||||
{ WM_IME_SETCONTEXT },
|
{
|
||||||
{ ACTION_IME_SETCONTEXT_OPEN },
|
case STAGE_1:
|
||||||
},
|
s_hImeWnd = ImmGetDefaultIMEWnd(hwnd);
|
||||||
{
|
ok(s_hImeWnd != NULL, "s_hImeWnd was NULL\n");
|
||||||
__LINE__, WM_IME_SETCONTEXT, 4, STAGE_TYPE_SEQUENCE, 0,
|
trace("s_hImeWnd: %p\n", s_hImeWnd );
|
||||||
1,
|
s_fnOldImeWndProc = (WNDPROC)SetWindowLongPtrW(s_hImeWnd, GWLP_WNDPROC,
|
||||||
{ WM_IME_NOTIFY },
|
(LONG_PTR)ImeWindowProc);
|
||||||
{ ACTION_IME_NOTIFY_OPEN },
|
PostMessageW(hwnd, WM_COMMAND, STAGE_2, 0);
|
||||||
},
|
break;
|
||||||
// hide
|
case STAGE_2:
|
||||||
{
|
PostMessageW(s_hwndEdit, WM_IME_KEYDOWN, 'A', 0);
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, ACTION_HIDE,
|
PostMessageW(hwnd, WM_COMMAND, STAGE_3, 0);
|
||||||
8,
|
break;
|
||||||
{ WM_SHOWWINDOW, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED,
|
case STAGE_3:
|
||||||
WM_NCACTIVATE, WM_ACTIVATE, WM_ACTIVATEAPP, WM_KILLFOCUS,
|
PostMessageW(s_hwndEdit, WM_IME_KEYUP, 'A', 0);
|
||||||
WM_IME_SETCONTEXT },
|
PostMessageW(hwnd, WM_COMMAND, STAGE_4, 0);
|
||||||
{ 0, 0, 0, 0, 0, 0, 0, ACTION_IME_SETCONTEXT_CLOSE }
|
break;
|
||||||
},
|
case STAGE_4:
|
||||||
{
|
PostMessageW(s_hwndEdit, WM_IME_CHAR, 'A', 0);
|
||||||
__LINE__, WM_IME_SETCONTEXT, 3, STAGE_TYPE_SEQUENCE, 0,
|
PostMessageW(hwnd, WM_COMMAND, STAGE_5, 0);
|
||||||
1,
|
break;
|
||||||
{ WM_IME_NOTIFY },
|
case STAGE_5:
|
||||||
{ ACTION_IME_NOTIFY_CLOSE }
|
PostMessageW(hwnd, WM_CLOSE, 0, 0);
|
||||||
},
|
break;
|
||||||
// show again
|
}
|
||||||
{
|
break;
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, 3,
|
case WM_DESTROY:
|
||||||
6,
|
PostQuitMessage(0);
|
||||||
{ WM_SHOWWINDOW, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGING,
|
break;
|
||||||
WM_ACTIVATEAPP, WM_NCACTIVATE, WM_ACTIVATE },
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_ACTIVATE, 3, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_SETCONTEXT },
|
|
||||||
{ ACTION_IME_SETCONTEXT_OPEN },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_IME_SETCONTEXT, 4, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_NOTIFY },
|
|
||||||
{ ACTION_IME_NOTIFY_OPEN },
|
|
||||||
},
|
|
||||||
// deactivate
|
|
||||||
{
|
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, ACTION_DEACTIVATE,
|
|
||||||
4,
|
|
||||||
{ WM_NCACTIVATE, WM_ACTIVATE, WM_ACTIVATEAPP, WM_KILLFOCUS },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_SETCONTEXT },
|
|
||||||
{ ACTION_IME_SETCONTEXT_CLOSE }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_IME_SETCONTEXT, 3, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_NOTIFY },
|
|
||||||
{ ACTION_IME_NOTIFY_CLOSE }
|
|
||||||
},
|
|
||||||
// activate
|
|
||||||
{
|
|
||||||
__LINE__, WM_ACTIVATE, 3, STAGE_TYPE_SEQUENCE, ACTION_ACTIVATE,
|
|
||||||
1,
|
|
||||||
{ WM_IME_SETCONTEXT },
|
|
||||||
{ ACTION_IME_SETCONTEXT_OPEN }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_IME_SETCONTEXT, 4, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_NOTIFY },
|
|
||||||
{ ACTION_IME_NOTIFY_OPEN },
|
|
||||||
},
|
|
||||||
// destroy
|
|
||||||
{
|
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, ACTION_DESTROY,
|
|
||||||
2,
|
|
||||||
{ WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_SETCONTEXT },
|
|
||||||
{ ACTION_IME_SETCONTEXT_CLOSE }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_IME_SETCONTEXT, 3, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
1,
|
|
||||||
{ WM_IME_NOTIFY },
|
|
||||||
{ ACTION_IME_NOTIFY_CLOSE }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
__LINE__, WM_COMMAND, 2, STAGE_TYPE_SEQUENCE, 0,
|
|
||||||
2,
|
|
||||||
{ WM_DESTROY, WM_NCDESTROY },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static void IME_DoTest(void)
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK
|
||||||
|
WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
WNDCLASSA wc;
|
LRESULT ret;
|
||||||
HWND hwnd;
|
MSG msg = { hwnd, uMsg, wParam, lParam };
|
||||||
MSG msg;
|
|
||||||
static const char s_szName[] = "MessageStateAnalyzerIME";
|
|
||||||
|
|
||||||
trace("IME_DoTest\n");
|
/* Build s_prefix */
|
||||||
DoInitialize(s_IMEStages, ARRAYSIZE(s_IMEStages));
|
MD_build_prefix();
|
||||||
|
|
||||||
/* register window class */
|
/* message dump */
|
||||||
ZeroMemory(&wc, sizeof(wc));
|
MD_msgdump(hwnd, uMsg, wParam, lParam);
|
||||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
|
||||||
wc.lpfnWndProc = WindowProc;
|
|
||||||
wc.hInstance = GetModuleHandleA(NULL);
|
|
||||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
||||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
|
||||||
wc.lpszClassName = s_szName;
|
|
||||||
if (!RegisterClassA(&wc))
|
|
||||||
{
|
|
||||||
skip("RegisterClassW failed.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create a window */
|
/* Add message */
|
||||||
hwnd = CreateWindowA(s_szName, s_szName, WS_OVERLAPPEDWINDOW,
|
s_Msgs[s_cMsgs++] = msg;
|
||||||
0, 0, WIDTH, HEIGHT, NULL, NULL,
|
|
||||||
GetModuleHandleW(NULL), NULL);
|
|
||||||
if (!hwnd)
|
|
||||||
{
|
|
||||||
skip("CreateWindowW failed.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* message loop */
|
/* Do inner task */
|
||||||
while (GetMessageA(&msg, NULL, 0, 0))
|
ret = InnerWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
{
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessageA(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
ok_int(UnregisterClassA(s_szName, GetModuleHandleA(NULL)), TRUE);
|
/* message return */
|
||||||
|
StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
|
||||||
|
MD_msgresult(hwnd, uMsg, wParam, lParam, ret);
|
||||||
|
|
||||||
DoFinish();
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
START_TEST(MessageStateAnalyzer)
|
START_TEST(MessageStateAnalyzer)
|
||||||
{
|
{
|
||||||
General_DoTest();
|
WNDCLASSW wc;
|
||||||
IME_DoTest();
|
HWND hwnd;
|
||||||
|
MSG msg;
|
||||||
|
static const WCHAR s_szName[] = L"MessageStateAnalyzer";
|
||||||
|
|
||||||
|
/* register window class */
|
||||||
|
ZeroMemory(&wc, sizeof(wc));
|
||||||
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
||||||
|
wc.lpfnWndProc = WindowProc;
|
||||||
|
wc.hInstance = GetModuleHandleW(NULL);
|
||||||
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||||
|
wc.lpszClassName = s_szName;
|
||||||
|
if (!RegisterClassW(&wc))
|
||||||
|
{
|
||||||
|
skip("RegisterClassW failed.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a window */
|
||||||
|
hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, NULL, NULL,
|
||||||
|
GetModuleHandleW(NULL), NULL);
|
||||||
|
if (!hwnd)
|
||||||
|
{
|
||||||
|
skip("CreateWindowW failed.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* message loop */
|
||||||
|
while (GetMessageW(&msg, NULL, 0, 0))
|
||||||
|
{
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessageW(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
DoAnalyzeAllMessages();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue