--- /dev/null
+/* Unit test suite for edit control.
+ *
+ * Copyright 2004 Vitaliy Margolen
+ * Copyright 2005 C. Scott Ananian
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+#ifndef ES_COMBO
+#define ES_COMBO 0x200
+#endif
+
+#define ID_EDITTEST2 99
+#define MAXLEN 200
+
+struct edit_notify {
+ int en_change, en_maxtext, en_update;
+};
+
+static struct edit_notify notifications;
+
+static char szEditTest2Name[] = "Edit Test 2 window class";
+static HINSTANCE hinst;
+static HWND hwndET2;
+
+static HWND create_editcontrol (DWORD style, DWORD exstyle)
+{
+ HWND handle;
+
+ handle = CreateWindowEx(exstyle,
+ "EDIT",
+ NULL,
+ ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
+ 10, 10, 300, 300,
+ NULL, NULL, NULL, NULL);
+ assert (handle);
+ if (winetest_interactive)
+ ShowWindow (handle, SW_SHOW);
+ return handle;
+}
+
+static LONG get_edit_style (HWND hwnd)
+{
+ return GetWindowLongA( hwnd, GWL_STYLE ) & (
+ ES_LEFT |
+/* FIXME: not implemented
+ ES_CENTER |
+ ES_RIGHT |
+ ES_OEMCONVERT |
+*/
+ ES_MULTILINE |
+ ES_UPPERCASE |
+ ES_LOWERCASE |
+ ES_PASSWORD |
+ ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL |
+ ES_NOHIDESEL |
+ ES_COMBO |
+ ES_READONLY |
+ ES_WANTRETURN |
+ ES_NUMBER
+ );
+}
+
+static void set_client_height(HWND Wnd, unsigned Height)
+{
+ RECT ClientRect, WindowRect;
+
+ GetWindowRect(Wnd, &WindowRect);
+ GetClientRect(Wnd, &ClientRect);
+ SetWindowPos(Wnd, NULL, WindowRect.left, WindowRect.top,
+ WindowRect.right - WindowRect.left,
+ Height + (WindowRect.bottom - WindowRect.top) - (ClientRect.bottom - ClientRect.top),
+ SWP_NOMOVE | SWP_NOZORDER);
+}
+
+#define edit_pos_ok(exp, got, txt) \
+ ok(exp == got, "wrong " #txt " expected %d got %ld\n", exp, got);
+
+#define edit_todo_pos_ok(exp, got, txt, todo) \
+ if (todo) todo_wine { edit_pos_ok(exp, got, txt); } \
+ else edit_pos_ok(exp, got, txt)
+
+#define check_pos(hwEdit, set_height, test_top, test_height, test_left, todo_top, todo_height, todo_left) \
+do { \
+ RECT format_rect; \
+ int left_margin; \
+ set_client_height(hwEdit, set_height); \
+ SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
+ left_margin = LOWORD(SendMessage(hwEdit, EM_GETMARGINS, 0, 0)); \
+ edit_todo_pos_ok(test_top, format_rect.top, vertical position, todo_top); \
+ edit_todo_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height, todo_height); \
+ edit_todo_pos_ok(test_left, format_rect.left - left_margin, left, todo_left); \
+} while(0)
+
+static void test_edit_control_1(void)
+{
+ HWND hwEdit;
+ MSG msMessage;
+ int i;
+ LONG r;
+ HFONT Font, OldFont;
+ HDC Dc;
+ TEXTMETRIC Metrics;
+
+ msMessage.message = WM_KEYDOWN;
+
+ trace("EDIT: Single line\n");
+ hwEdit = create_editcontrol(0, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%lx\n", r);
+ for (i=0;i<65535;i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
+ }
+ DestroyWindow (hwEdit);
+
+ trace("EDIT: Single line want returns\n");
+ hwEdit = create_editcontrol(ES_WANTRETURN, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%lx\n", r);
+ for (i=0;i<65535;i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
+ }
+ DestroyWindow (hwEdit);
+
+ trace("EDIT: Multiline line\n");
+ hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%lx\n", r);
+ for (i=0;i<65535;i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
+ }
+ DestroyWindow (hwEdit);
+
+ trace("EDIT: Multi line want returns\n");
+ hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL | ES_WANTRETURN, 0);
+ r = get_edit_style(hwEdit);
+ ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%lx\n", r);
+ for (i=0;i<65535;i++)
+ {
+ msMessage.wParam = i;
+ r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
+ ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
+ "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
+ }
+ DestroyWindow (hwEdit);
+
+ /* Get a stock font for which we can determine the metrics */
+ Font = GetStockObject(SYSTEM_FONT);
+ assert(NULL != Font);
+ Dc = GetDC(NULL);
+ assert(NULL != Dc);
+ OldFont = SelectObject(Dc, Font);
+ assert(NULL != OldFont);
+ if (! GetTextMetrics(Dc, &Metrics))
+ {
+ assert(FALSE);
+ }
+ SelectObject(Dc, OldFont);
+ ReleaseDC(NULL, Dc);
+
+ trace("EDIT: Text position\n");
+ hwEdit = create_editcontrol(0, 0);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, 0);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, WS_EX_CLIENTEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, WS_EX_CLIENTEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP, 0);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, 0);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 3, 0, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 2, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 2, Metrics.tmHeight , 2, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP, WS_EX_CLIENTEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP, WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 0, Metrics.tmHeight , 0, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 0, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 3, 0, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 2, Metrics.tmHeight , 2, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 2, Metrics.tmHeight , 2, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, ES_MULTILINE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, ES_MULTILINE | WS_EX_CLIENTEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE | WS_EX_CLIENTEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, ES_MULTILINE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 1, 1, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 1, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(0, ES_MULTILINE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(WS_BORDER, ES_MULTILINE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
+ SendMessage(hwEdit, WM_SETFONT, (WPARAM) Font, (LPARAM) FALSE);
+ check_pos(hwEdit, Metrics.tmHeight - 1, 0, Metrics.tmHeight - 1, 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight , 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 1, 0, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 2, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 4, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ check_pos(hwEdit, Metrics.tmHeight + 10, 1, Metrics.tmHeight , 1, 0, 0, 0);
+ DestroyWindow(hwEdit);
+}
+
+/* WM_SETTEXT is implemented by selecting all text, and then replacing the
+ * selection. This test checks that the first 'select all' doesn't generate
+ * an UPDATE message which can escape and (via a handler) change the
+ * selection, which would cause WM_SETTEXT to break. This old bug
+ * was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
+ */
+static void test_edit_control_2(void)
+{
+ HWND hwndMain;
+ char szLocalString[MAXLEN];
+
+ /* Create main and edit windows. */
+ hwndMain = CreateWindow(szEditTest2Name, "ET2", WS_OVERLAPPEDWINDOW,
+ 0, 0, 200, 200, NULL, NULL, hinst, NULL);
+ assert(hwndMain);
+ if (winetest_interactive)
+ ShowWindow (hwndMain, SW_SHOW);
+
+ hwndET2 = CreateWindow("EDIT", NULL,
+ WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
+ 0, 0, 150, 50, /* important this not be 0 size. */
+ hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
+ assert(hwndET2);
+ if (winetest_interactive)
+ ShowWindow (hwndET2, SW_SHOW);
+
+ trace("EDIT: SETTEXT atomicity\n");
+ /* Send messages to "type" in the word 'foo'. */
+ SendMessage(hwndET2, WM_CHAR, 'f', 1);
+ SendMessage(hwndET2, WM_CHAR, 'o', 1);
+ SendMessage(hwndET2, WM_CHAR, 'o', 1);
+ /* 'foo' should have been changed to 'bar' by the UPDATE handler. */
+ GetWindowText(hwndET2, szLocalString, MAXLEN);
+ ok(lstrcmp(szLocalString, "bar")==0,
+ "Wrong contents of edit: %s\n", szLocalString);
+
+ /* OK, done! */
+ DestroyWindow (hwndET2);
+ DestroyWindow (hwndMain);
+}
+
+static void ET2_check_change(void) {
+ char szLocalString[MAXLEN];
+ /* This EN_UPDATE handler changes any 'foo' to 'bar'. */
+ GetWindowText(hwndET2, szLocalString, MAXLEN);
+ if (lstrcmp(szLocalString, "foo")==0) {
+ lstrcpy(szLocalString, "bar");
+ SendMessage(hwndET2, WM_SETTEXT, 0, (LPARAM) szLocalString);
+ }
+ /* always leave the cursor at the end. */
+ SendMessage(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
+}
+static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
+{
+ if (id==ID_EDITTEST2 && codeNotify == EN_UPDATE)
+ ET2_check_change();
+}
+static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (iMsg) {
+ HANDLE_MSG(hwnd, WM_COMMAND, ET2_OnCommand);
+ }
+ return DefWindowProc(hwnd, iMsg, wParam, lParam);
+}
+
+static BOOL RegisterWindowClasses (void)
+{
+ WNDCLASSA cls;
+ cls.style = 0;
+ cls.lpfnWndProc = ET2_WndProc;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = hinst;
+ cls.hIcon = NULL;
+ cls.hCursor = LoadCursorA (NULL, IDC_ARROW);
+ cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = szEditTest2Name;
+ if (!RegisterClassA (&cls)) return FALSE;
+
+ return TRUE;
+}
+
+static void zero_notify(void)
+{
+ notifications.en_change = 0;
+ notifications.en_maxtext = 0;
+ notifications.en_update = 0;
+}
+
+#define test_notify(enchange, enmaxtext, enupdate) \
+ ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
+ "got %d\n", enchange, notifications.en_change); \
+ ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
+ "got %d\n", enmaxtext, notifications.en_maxtext); \
+ ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
+ "got %d\n", enupdate, notifications.en_update)
+
+
+static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_COMMAND:
+ switch (HIWORD(wParam)) {
+ case EN_MAXTEXT:
+ notifications.en_maxtext++;
+ break;
+ case EN_UPDATE:
+ notifications.en_update++;
+ break;
+ case EN_CHANGE:
+ notifications.en_change++;
+ break;
+ }
+ break;
+ }
+ return DefWindowProcA(hWnd, msg, wParam, lParam);
+}
+
+/* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notificatisons sent in response
+ * to these messages.
+ */
+static void test_edit_control_3(void)
+{
+ WNDCLASSA cls;
+ HWND hWnd;
+ HWND hParent;
+ int len;
+ static const char *str = "this is a long string.";
+ static const char *str2 = "this is a long string.\r\nthis is a long string.\r\nthis is a long string.\r\nthis is a long string.";
+
+ trace("EDIT: Test notifications\n");
+
+ cls.style = 0;
+ cls.lpfnWndProc = edit3_wnd_procA;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = GetModuleHandleA(0);
+ cls.hIcon = 0;
+ cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+ cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = "ParentWindowClass";
+
+ assert(RegisterClassA(&cls));
+
+ hParent = CreateWindowExA(0,
+ "ParentWindowClass",
+ NULL,
+ 0,
+ CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
+ NULL, NULL, NULL, NULL);
+ assert(hParent);
+
+ trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ 0,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) > len, "text should have been truncated\n");
+ test_notify(1, 1, 1);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(1 == len, "wrong text length, expected 1, got %d\n", len);
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Single line, ES_AUTOHSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_AUTOHSCROLL,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_MULTILINE,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_MULTILINE | ES_AUTOHSCROLL,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ DestroyWindow(hWnd);
+
+ trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
+ hWnd = CreateWindowExA(0,
+ "EDIT",
+ NULL,
+ ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
+ 10, 10, 50, 50,
+ hParent, NULL, NULL, NULL);
+ assert(hWnd);
+
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(1, 0, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
+
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
+ zero_notify();
+ SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
+ test_notify(1, 1, 1);
+
+ zero_notify();
+ SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
+ len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
+ ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
+ test_notify(0, 0, 0);
+
+ DestroyWindow(hWnd);
+}
+
+/* Test EM_CHARFROMPOS and EM_POSFROMCHAR
+ */
+static void test_edit_control_4(void)
+{
+ HWND hwEdit;
+ int lo, hi, mid;
+ int ret;
+ int i;
+
+ trace("EDIT: Test EM_CHARFROMPOS and EM_POSFROMCHAR\n");
+ hwEdit = create_editcontrol(0, 0);
+ SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
+ lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2;
+
+ for (i = lo; i < mid; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+ for (i = mid; i <= hi; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+ ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_RIGHT, 0);
+ SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
+ lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2;
+
+ for (i = lo; i < mid; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+ for (i = mid; i <= hi; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+ ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_CENTER, 0);
+ SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
+ lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2;
+
+ for (i = lo; i < mid; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+ for (i = mid; i <= hi; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+ ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE, 0);
+ SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
+ lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2 +1;
+
+ for (i = lo; i < mid; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+ for (i = mid; i <= hi; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+ ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT, 0);
+ SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
+ lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2 +1;
+
+ for (i = lo; i < mid; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+ for (i = mid; i <= hi; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+ ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+
+ hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER, 0);
+ SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
+ lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
+ hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
+ mid = lo + (hi - lo) / 2 +1;
+
+ for (i = lo; i < mid; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(0 == ret, "expected 0 got %d\n", ret);
+ }
+ for (i = mid; i <= hi; i++) {
+ ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
+ ok(1 == ret, "expected 1 got %d\n", ret);
+ }
+ ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
+ ok(-1 == ret, "expected -1 got %d\n", ret);
+ DestroyWindow(hwEdit);
+}
+
+static void test_margins(void)
+{
+ HWND hwEdit;
+ RECT old_rect, new_rect;
+ INT old_left_margin, old_right_margin;
+ DWORD old_margins, new_margins;
+
+ hwEdit = create_editcontrol(WS_BORDER, 0);
+
+ old_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
+ old_left_margin = LOWORD(old_margins);
+ old_right_margin = HIWORD(old_margins);
+
+ /* Check if setting the margins works */
+
+ SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
+ new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
+ ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
+
+ SendMessage(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
+ new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
+ ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
+ ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
+
+
+ /* The size of the rectangle must decrease if we increase the margin */
+
+ SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
+ SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+ SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
+ SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
+ ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
+ ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
+ ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
+
+
+ /* If we set the margin to same value as the current margin,
+ the rectangle must not change */
+
+ SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
+ old_rect.left = 1;
+ old_rect.right = 99;
+ old_rect.top = 1;
+ old_rect.bottom = 99;
+ SendMessage(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);
+ SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+ SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
+ SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+ ok(new_rect.left == old_rect.left, "The left border of the rectangle has changed\n");
+ ok(new_rect.right == old_rect.right, "The right border of the rectangle has changed\n");
+ ok(new_rect.top == old_rect.top, "The top border of the rectangle has changed\n");
+ ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle has changed\n");
+
+ DestroyWindow (hwEdit);
+}
+
+START_TEST(edit)
+{
+ hinst = GetModuleHandleA (NULL);
+ if (!RegisterWindowClasses())
+ assert(0);
+
+ test_edit_control_1();
+ test_edit_control_2();
+ test_edit_control_3();
+ test_edit_control_4();
+ test_margins();
+}
--- /dev/null
+/*
+ * Unit tests for window message handling
+ *
+ * Copyright 1999 Ove Kaaven
+ * Copyright 2003 Dimitrie O. Paun
+ * Copyright 2004, 2005 Dmitry Timoshkov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define WINVER 0x0500
+#define _WIN32_WINNT 0x0500 /* For WM_CHANGEUISTATE */
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+#include "wine/test.h"
+
+#define MDI_FIRST_CHILD_ID 2004
+#define OBJID_QUERYCLASSNAMEIDX -12 // Fixme w32api
+#define OBJID_NATIVEOM -16 // ditto
+
+/* undocumented SWP flags - from SDK 3.1 */
+#define SWP_NOCLIENTSIZE 0x0800
+#define SWP_NOCLIENTMOVE 0x1000
+
+#define WND_PARENT_ID 1
+#define WND_POPUP_ID 2
+#define WND_CHILD_ID 3
+
+static BOOL test_DestroyWindow_flag;
+static HWINEVENTHOOK hEvent_hook;
+
+static HWND (WINAPI *pGetAncestor)(HWND,UINT);
+
+/*
+FIXME: add tests for these
+Window Edge Styles (Win31/Win95/98 look), in order of precedence:
+ WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
+ WS_THICKFRAME: thick border
+ WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
+ WS_BORDER (default for overlapped windows): single black border
+ none (default for child (and popup?) windows): no border
+*/
+
+typedef enum {
+ sent=0x1,
+ posted=0x2,
+ parent=0x4,
+ wparam=0x8,
+ lparam=0x10,
+ defwinproc=0x20,
+ beginpaint=0x40,
+ optional=0x80,
+ hook=0x100,
+ winevent_hook=0x200
+} msg_flags_t;
+
+struct message {
+ UINT message; /* the WM_* code */
+ msg_flags_t flags; /* message props */
+ WPARAM wParam; /* expected value of wParam */
+ LPARAM lParam; /* expected value of lParam */
+};
+
+/* Empty message sequence */
+static const struct message WmEmptySeq[] =
+{
+ { 0 }
+};
+/* CreateWindow (for overlapped window, not initially visible) (16/32) */
+static const struct message WmCreateOverlappedSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_GETMINMAXINFO, sent },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
+ * for a not visible overlapped window.
+ */
+static const struct message WmSWP_ShowOverlappedSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
+ { WM_ACTIVATEAPP, sent|wparam, 1 },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { WM_IME_NOTIFY, sent|defwinproc|optional },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ /* Win9x adds SWP_NOZORDER below */
+ { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+ { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_ERASEBKGND, sent|optional },
+ { 0 }
+};
+/* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
+ * for a visible overlapped window.
+ */
+static const struct message WmSWP_HideOverlappedSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+
+/* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
+ * for a visible overlapped window.
+ */
+static const struct message WmSWP_ResizeSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE },
+ { WM_GETMINMAXINFO, sent|defwinproc },
+ { WM_NCCALCSIZE, sent|wparam, TRUE },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
+ { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+
+/* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
+ * for a visible popup window.
+ */
+static const struct message WmSWP_ResizePopupSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE },
+ { WM_NCCALCSIZE, sent|wparam, TRUE },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
+ { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+
+/* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
+ * for a visible overlapped window.
+ */
+static const struct message WmSWP_MoveSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE },
+ { WM_MOVE, sent|defwinproc|wparam, 0 },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+
+/* ShowWindow(SW_SHOW) for a not visible overlapped window */
+static const struct message WmShowOverlappedSeq[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+ { WM_ACTIVATEAPP, sent|wparam, 1 },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { WM_IME_NOTIFY, sent|defwinproc|optional },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ /* Win9x adds SWP_NOZORDER below */
+ { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+ { WM_NCCALCSIZE, sent|optional },
+ { WM_NCPAINT, sent|optional },
+ { WM_ERASEBKGND, sent|optional },
+#if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
+ * messages. Does that mean that CreateWindow doesn't set initial
+ * window dimensions for overlapped windows?
+ */
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+#endif
+ { 0 }
+};
+/* ShowWindow(SW_HIDE) for a visible overlapped window */
+static const struct message WmHideOverlappedSeq[] = {
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { WM_NCACTIVATE, sent|wparam, 0 },
+ { WM_ACTIVATE, sent|wparam, 0 },
+ { WM_ACTIVATEAPP, sent|wparam, 0 },
+ { WM_KILLFOCUS, sent|wparam, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_NOTIFY, sent|optional|defwinproc },
+ { 0 }
+};
+/* DestroyWindow for a visible overlapped window */
+static const struct message WmDestroyOverlappedSeq[] = {
+ { HCBT_DESTROYWND, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_NCACTIVATE, sent|wparam, 0 },
+ { WM_ACTIVATE, sent|wparam, 0 },
+ { WM_ACTIVATEAPP, sent|wparam, 0 },
+ { WM_KILLFOCUS, sent|wparam, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_NOTIFY, sent|optional|defwinproc },
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* CreateWindow (for a child popup window, not initially visible) */
+static const struct message WmCreateChildPopupSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { 0 }
+};
+/* CreateWindow (for a popup window, not initially visible,
+ * which sets WS_VISIBLE in WM_CREATE handler)
+ */
+static const struct message WmCreateInvisiblePopupSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { WM_STYLECHANGING, sent },
+ { WM_STYLECHANGED, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
+ * for a popup window with WS_VISIBLE style set
+ */
+static const struct message WmShowVisiblePopupSeq_2[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
+ * for a popup window with WS_VISIBLE style set
+ */
+static const struct message WmShowVisiblePopupSeq_3[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent|parent },
+ { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { WM_IME_NOTIFY, sent|defwinproc|optional },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+ { 0 }
+};
+/* CreateWindow (for child window, not initially visible) */
+static const struct message WmCreateChildSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ /* child is inserted into parent's child list after WM_NCCREATE returns */
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
+ { 0 }
+};
+/* CreateWindow (for maximized child window, not initially visible) */
+static const struct message WmCreateMaximizedChildSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
+ { WM_GETMINMAXINFO, sent },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
+ { 0 }
+};
+/* CreateWindow (for a child window, initially visible) */
+static const struct message WmCreateVisibleChildSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ /* child is inserted into parent's child list after WM_NCCREATE returns */
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
+ { 0 }
+};
+/* ShowWindow(SW_SHOW) for a not visible child window */
+static const struct message WmShowChildSeq[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* ShowWindow(SW_HIDE) for a visible child window */
+static const struct message WmHideChildSeq[] = {
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
+ * for a not visible child window
+ */
+static const struct message WmShowChildSeq_2[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CHILDACTIVATE, sent },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
+ * for a not visible child window
+ */
+static const struct message WmShowChildSeq_3[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
+ * for a visible child window with a caption
+ */
+static const struct message WmShowChildSeq_4[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { WM_CHILDACTIVATE, sent },
+ { 0 }
+};
+/* ShowWindow(SW_SHOW) for child with invisible parent */
+static const struct message WmShowChildInvisibleParentSeq[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { 0 }
+};
+/* ShowWindow(SW_HIDE) for child with invisible parent */
+static const struct message WmHideChildInvisibleParentSeq[] = {
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { 0 }
+};
+/* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
+static const struct message WmShowChildInvisibleParentSeq_2[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
+static const struct message WmHideChildInvisibleParentSeq_2[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* DestroyWindow for a visible child window */
+static const struct message WmDestroyChildSeq[] = {
+ { HCBT_DESTROYWND, hook },
+ { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { HCBT_SETFOCUS, hook }, /* set focus to a parent */
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|parent },
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_DESTROY, sent|optional }, /* some other (IME?) window */
+ { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* Moving the mouse in nonclient area */
+static const struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */
+ { WM_NCHITTEST, sent },
+ { WM_SETCURSOR, sent },
+ { WM_NCMOUSEMOVE, posted },
+ { 0 }
+};
+/* Moving the mouse in client area */
+static const struct message WmMouseMoveInClientAreaSeq[] = { /* FIXME: add */
+ { WM_NCHITTEST, sent },
+ { WM_SETCURSOR, sent },
+ { WM_MOUSEMOVE, posted },
+ { 0 }
+};
+/* Moving by dragging the title bar (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
+static const struct message WmDragTitleBarSeq[] = { /* FIXME: add */
+ { WM_NCLBUTTONDOWN, sent|wparam, HTCAPTION },
+ { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_MOVE+2 },
+ { WM_GETMINMAXINFO, sent|defwinproc },
+ { WM_ENTERSIZEMOVE, sent|defwinproc },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
+ { WM_MOVE, sent|defwinproc },
+ { WM_EXITSIZEMOVE, sent|defwinproc },
+ { 0 }
+};
+/* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */
+static const struct message WmDragThickBordersBarSeq[] = { /* FIXME: add */
+ { WM_NCLBUTTONDOWN, sent|wparam, 0xd },
+ { WM_SYSCOMMAND, sent|defwinproc|wparam, 0xf004 },
+ { WM_GETMINMAXINFO, sent|defwinproc },
+ { WM_ENTERSIZEMOVE, sent|defwinproc },
+ { WM_SIZING, sent|defwinproc|wparam, 4}, /* one for each mouse movement */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, 0 },
+ { WM_GETMINMAXINFO, sent|defwinproc },
+ { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
+ { WM_NCPAINT, sent|defwinproc|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc },
+ { WM_ERASEBKGND, sent|defwinproc },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, 0 },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+ { WM_EXITSIZEMOVE, sent|defwinproc },
+ { 0 }
+};
+/* Resizing child window with MoveWindow (32) */
+static const struct message WmResizingChildWithMoveWindowSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+/* Clicking on inactive button */
+static const struct message WmClickInactiveButtonSeq[] = { /* FIXME: add */
+ { WM_NCHITTEST, sent },
+ { WM_PARENTNOTIFY, sent|parent|wparam, WM_LBUTTONDOWN },
+ { WM_MOUSEACTIVATE, sent },
+ { WM_MOUSEACTIVATE, sent|parent|defwinproc },
+ { WM_SETCURSOR, sent },
+ { WM_SETCURSOR, sent|parent|defwinproc },
+ { WM_LBUTTONDOWN, posted },
+ { WM_KILLFOCUS, posted|parent },
+ { WM_SETFOCUS, posted },
+ { WM_CTLCOLORBTN, posted|parent },
+ { BM_SETSTATE, posted },
+ { WM_CTLCOLORBTN, posted|parent },
+ { WM_LBUTTONUP, posted },
+ { BM_SETSTATE, posted },
+ { WM_CTLCOLORBTN, posted|parent },
+ { WM_COMMAND, posted|parent },
+ { 0 }
+};
+/* Reparenting a button (16/32) */
+/* The last child (button) reparented gets topmost for its new parent. */
+static const struct message WmReparentButtonSeq[] = { /* FIXME: add */
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOZORDER },
+ { WM_CHILDACTIVATE, sent },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { 0 }
+};
+/* Creation of a custom dialog (32) */
+static const struct message WmCreateCustomDialogSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_GETMINMAXINFO, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_NCCREATE, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { WM_KILLFOCUS, sent|parent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_IME_NOTIFY, sent|optional|defwinproc },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_NCPAINT, sent|wparam, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { WM_ERASEBKGND, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_CTLCOLORDLG, sent|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_NCCALCSIZE, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_NCPAINT, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETICON, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { WM_ERASEBKGND, sent|optional },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_CTLCOLORDLG, sent|optional|defwinproc },
+ { WM_SIZE, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_MOVE, sent },
+ { 0 }
+};
+/* Calling EndDialog for a custom dialog (32) */
+static const struct message WmEndCustomDialogSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_GETTEXT, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { HCBT_ACTIVATE, hook },
+ { WM_NCACTIVATE, sent|wparam, 0 },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { WM_GETICON, sent|optional|defwinproc },
+ { WM_GETICON, sent|optional|defwinproc },
+ { WM_GETICON, sent|optional|defwinproc },
+ { WM_GETTEXT, sent|optional|defwinproc },
+ { WM_ACTIVATE, sent|wparam, 0 },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
+ { WM_IME_NOTIFY, sent|optional },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|parent|defwinproc },
+ { 0 }
+};
+/* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
+static const struct message WmShowCustomDialogSeq[] = {
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_ACTIVATE, sent|wparam, 1 },
+
+ { WM_KILLFOCUS, sent|parent },
+ { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { WM_IME_NOTIFY, sent|optional|defwinproc },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_NCPAINT, sent|wparam, 1 },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_ERASEBKGND, sent },
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_CTLCOLORDLG, sent|defwinproc },
+
+ { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* Creation and destruction of a modal dialog (32) */
+static const struct message WmModalDialogSeq[] = {
+ { WM_CANCELMODE, sent|parent },
+ { HCBT_SETFOCUS, hook },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_KILLFOCUS, sent|parent },
+ { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
+ { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ENABLE, sent|parent|wparam, 0 },
+ { HCBT_CREATEWND, hook },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SETFONT, sent },
+ { WM_INITDIALOG, sent },
+ { WM_CHANGEUISTATE, sent|optional },
+ { WM_SHOWWINDOW, sent },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCPAINT, sent },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_ERASEBKGND, sent },
+ { WM_CTLCOLORDLG, sent },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_NCCALCSIZE, sent|optional },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_CTLCOLORDLG, sent|optional },
+ { WM_PAINT, sent|optional },
+ { WM_CTLCOLORBTN, sent },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_ENTERIDLE, sent|parent|optional },
+ { WM_GETICON, sent|parent|optional },
+ { WM_GETICON, sent|parent|optional },
+ { WM_GETICON, sent|parent|optional },
+ { WM_TIMER, sent },
+ { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ENABLE, sent|parent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { HCBT_ACTIVATE, hook },
+ { WM_NCACTIVATE, sent|wparam, 0 },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_ACTIVATE, sent|wparam, 0 },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|optional },
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|parent|defwinproc },
+ { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
+ { HCBT_DESTROYWND, hook },
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */
+static const struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */
+ /* (inside dialog proc, handling WM_INITDIALOG) */
+ { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+ { WM_NCCALCSIZE, sent },
+ { WM_NCACTIVATE, sent|parent|wparam, 0 },
+ { WM_GETTEXT, sent|defwinproc },
+ { WM_ACTIVATE, sent|parent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|parent },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
+ { WM_SIZE, sent|defwinproc },
+ /* (setting focus) */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+ { WM_NCPAINT, sent },
+ { WM_GETTEXT, sent|defwinproc },
+ { WM_ERASEBKGND, sent },
+ { WM_CTLCOLORDLG, sent|defwinproc },
+ { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
+ { WM_PAINT, sent },
+ /* (bunch of WM_CTLCOLOR* for each control) */
+ { WM_PAINT, sent|parent },
+ { WM_ENTERIDLE, sent|parent|wparam, 0 },
+ { WM_SETCURSOR, sent|parent },
+ { 0 }
+};
+/* SetMenu for NonVisible windows with size change*/
+static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+ { 0 }
+};
+/* SetMenu for NonVisible windows with no size change */
+static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+/* SetMenu for Visible windows with size change */
+static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCPAINT, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_ACTIVATE, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_ERASEBKGND, sent|optional },
+ { 0 }
+};
+/* SetMenu for Visible windows with no size change */
+static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_NCPAINT, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_ACTIVATE, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+/* DrawMenuBar for a visible window */
+static const struct message WmDrawMenuBarSeq[] =
+{
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_NCPAINT, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+
+static const struct message WmSetRedrawFalseSeq[] =
+{
+ { WM_SETREDRAW, sent|wparam, 0 },
+ { 0 }
+};
+
+static const struct message WmSetRedrawTrueSeq[] =
+{
+ { WM_SETREDRAW, sent|wparam, 1 },
+ { 0 }
+};
+
+static const struct message WmEnableWindowSeq_1[] =
+{
+ { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
+ { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
+ { 0 }
+};
+
+static const struct message WmEnableWindowSeq_2[] =
+{
+ { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
+ { 0 }
+};
+
+static const struct message WmGetScrollRangeSeq[] =
+{
+ { SBM_GETRANGE, sent },
+ { 0 }
+};
+static const struct message WmGetScrollInfoSeq[] =
+{
+ { SBM_GETSCROLLINFO, sent },
+ { 0 }
+};
+static const struct message WmSetScrollRangeSeq[] =
+{
+ /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
+ sends SBM_SETSCROLLINFO.
+ */
+ { SBM_SETSCROLLINFO, sent },
+ { 0 }
+};
+/* SetScrollRange for a window without a non-client area */
+static const struct message WmSetScrollRangeHSeq_empty[] =
+{
+ { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
+ { 0 }
+};
+static const struct message WmSetScrollRangeVSeq_empty[] =
+{
+ { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
+ { 0 }
+};
+static const struct message WmSetScrollRangeHVSeq[] =
+{
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { 0 }
+};
+/* SetScrollRange for a window with a non-client area */
+static const struct message WmSetScrollRangeHV_NC_Seq[] =
+{
+ { WM_WINDOWPOSCHANGING, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER*/ },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCPAINT, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_GETICON, sent|optional|defwinproc },
+ { WM_GETICON, sent|optional|defwinproc },
+ { WM_GETICON, sent|optional|defwinproc },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
+ { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|0x1000*/ },
+ { WM_SIZE, sent|defwinproc },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_GETTEXT, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|optional },
+ { 0 }
+};
+/* test if we receive the right sequence of messages */
+/* after calling ShowWindow( SW_SHOWNA) */
+static const struct message WmSHOWNAChildInvisParInvis[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { 0 }
+};
+static const struct message WmSHOWNAChildVisParInvis[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { 0 }
+};
+static const struct message WmSHOWNAChildVisParVis[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER },
+ { 0 }
+};
+static const struct message WmSHOWNAChildInvisParVis[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER},
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+static const struct message WmSHOWNATopVisible[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+ { 0 }
+};
+static const struct message WmSHOWNATopInvisible[] = {
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_NCPAINT, sent|wparam, 1 },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETICON, sent|optional },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+ { WM_NCPAINT, sent|wparam|optional, 1 },
+ { WM_ERASEBKGND, sent|optional },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { 0 }
+};
+
+static int after_end_dialog;
+static int sequence_cnt, sequence_size;
+static struct message* sequence;
+static int log_all_parent_messages;
+
+static void add_message(const struct message *msg)
+{
+ if (!sequence)
+ {
+ sequence_size = 10;
+ sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
+ }
+ if (sequence_cnt == sequence_size)
+ {
+ sequence_size *= 2;
+ sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
+ }
+ assert(sequence);
+
+ sequence[sequence_cnt].message = msg->message;
+ sequence[sequence_cnt].flags = msg->flags;
+ sequence[sequence_cnt].wParam = msg->wParam;
+ sequence[sequence_cnt].lParam = msg->lParam;
+
+ sequence_cnt++;
+}
+
+static void flush_sequence(void)
+{
+ HeapFree(GetProcessHeap(), 0, sequence);
+ sequence = 0;
+ sequence_cnt = sequence_size = 0;
+}
+
+#define ok_sequence( exp, contx, todo) \
+ ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
+
+
+static void ok_sequence_(const struct message *expected, const char *context, int todo,
+ const char *file, int line)
+{
+ static const struct message end_of_sequence = { 0, 0, 0, 0 };
+ const struct message *actual;
+ int failcount = 0;
+
+ add_message(&end_of_sequence);
+
+ actual = sequence;
+
+ while (expected->message && actual->message)
+ {
+ trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
+
+ if (expected->message == actual->message)
+ {
+ if (expected->flags & wparam)
+ {
+ if (expected->wParam != actual->wParam && todo)
+ {
+ todo_wine {
+ failcount ++;
+ ok_( file, line) (FALSE,
+ "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
+ context, expected->message, expected->wParam, actual->wParam);
+ }
+ }
+ else
+ ok_( file, line) (expected->wParam == actual->wParam,
+ "%s: in msg 0x%04x expecting wParam 0x%x got 0x%x\n",
+ context, expected->message, expected->wParam, actual->wParam);
+ }
+ if (expected->flags & lparam)
+ ok_( file, line) (expected->lParam == actual->lParam,
+ "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
+ context, expected->message, expected->lParam, actual->lParam);
+ ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
+ "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
+ context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
+ ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
+ "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
+ context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
+ ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
+ "%s: the msg 0x%04x should have been %s\n",
+ context, expected->message, (expected->flags & posted) ? "posted" : "sent");
+ ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
+ "%s: the msg 0x%04x was expected in %s\n",
+ context, expected->message, (expected->flags & parent) ? "parent" : "child");
+ ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
+ "%s: the msg 0x%04x should have been sent by a hook\n",
+ context, expected->message);
+ ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
+ "%s: the msg 0x%04x should have been sent by a winevent hook\n",
+ context, expected->message);
+ expected++;
+ actual++;
+ }
+ /* silently drop winevent messages if there is no support for them */
+ else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
+ expected++;
+ else if (todo)
+ {
+ failcount++;
+ todo_wine {
+ ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
+ context, expected->message, actual->message);
+ }
+ flush_sequence();
+ return;
+ }
+ else
+ {
+ ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
+ context, expected->message, actual->message);
+ expected++;
+ actual++;
+ }
+ }
+
+ /* skip all optional trailing messages */
+ while (expected->message && ((expected->flags & optional) ||
+ ((expected->flags & winevent_hook) && !hEvent_hook)))
+ expected++;
+
+ if (todo)
+ {
+ todo_wine {
+ if (expected->message || actual->message) {
+ failcount++;
+ ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
+ context, expected->message, actual->message);
+ }
+ }
+ }
+ else
+ {
+ if (expected->message || actual->message)
+ ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
+ context, expected->message, actual->message);
+ }
+ if( todo && !failcount) /* succeeded yet marked todo */
+ todo_wine {
+ ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
+ }
+
+ flush_sequence();
+}
+
+/******************************** MDI test **********************************/
+
+/* CreateWindow for MDI frame window, initially visible */
+static const struct message WmCreateMDIframeSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_GETMINMAXINFO, sent },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { HCBT_ACTIVATE, hook },
+ { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+ { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* Win9x */
+ { WM_ACTIVATEAPP, sent|wparam, 1 },
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_GETICON, sent|defwinproc|optional },
+ { WM_GETICON, sent|defwinproc|optional },
+ { WM_ACTIVATE, sent|wparam, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+ /* Win9x adds SWP_NOZORDER below */
+ { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { 0 }
+};
+/* DestroyWindow for MDI frame window, initially visible */
+static const struct message WmDestroyMDIframeSeq[] = {
+ { HCBT_DESTROYWND, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_NCACTIVATE, sent|wparam, 0 },
+ { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
+ { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* CreateWindow for MDI client window, initially visible */
+static const struct message WmCreateMDIclientSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { 0 }
+};
+/* DestroyWindow for MDI client window, initially visible */
+static const struct message WmDestroyMDIclientSeq[] = {
+ { HCBT_DESTROYWND, hook },
+ { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* CreateWindow for MDI child window, initially visible */
+static const struct message WmCreateMDIchildVisibleSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+
+ /* Win9x: message sequence terminates here. */
+
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
+ { HCBT_SETFOCUS, hook }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+ { WM_MDIACTIVATE, sent|defwinproc },
+ { 0 }
+};
+/* DestroyWindow for MDI child window, initially visible */
+static const struct message WmDestroyMDIchildVisibleSeq[] = {
+ { HCBT_DESTROYWND, hook },
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+
+ /* { WM_DESTROY, sent }
+ * Win9x: message sequence terminates here.
+ */
+
+ { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+
+ { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { WM_DESTROY, sent },
+
+ { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* CreateWindow for MDI child window, initially invisible */
+static const struct message WmCreateMDIchildInvisibleSeq[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
+ { 0 }
+};
+/* DestroyWindow for MDI child window, initially invisible */
+static const struct message WmDestroyMDIchildInvisibleSeq[] = {
+ { HCBT_DESTROYWND, hook },
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* CreateWindow for the 1st MDI child window, initially visible and maximized */
+static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
+ { WM_GETMINMAXINFO, sent },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+
+ /* Win9x: message sequence terminates here. */
+
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
+ { HCBT_SETFOCUS, hook }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+ { WM_MDIACTIVATE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { 0 }
+};
+/* CreateWindow for the 2nd MDI child window, initially visible and maximized */
+static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
+ /* restore the 1st MDI child */
+ { WM_SETREDRAW, sent|wparam, 0 },
+ { HCBT_MINMAX, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
+ /* create the 2nd MDI child */
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
+ { WM_GETMINMAXINFO, sent },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
+ { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
+
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+
+ /* Win9x: message sequence terminates here. */
+
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+
+ { WM_MDIACTIVATE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { 0 }
+};
+/* WM_MDICREATE MDI child window, initially visible and maximized */
+static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
+ { WM_MDICREATE, sent },
+ { HCBT_CREATEWND, hook },
+ { WM_NCCREATE, sent },
+ { WM_NCCALCSIZE, sent|wparam, 0 },
+ { WM_CREATE, sent },
+ { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_SIZE, sent },
+ { WM_MOVE, sent },
+ { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
+ { WM_GETMINMAXINFO, sent },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
+
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+
+ /* Win9x: message sequence terminates here. */
+
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
+ { HCBT_SETFOCUS, hook }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+
+ { WM_MDIACTIVATE, sent|defwinproc },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI client */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent|defwinproc },
+
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+
+ { 0 }
+};
+/* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
+static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
+ { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
+ { HCBT_SYSCOMMAND, hook },
+ { WM_CLOSE, sent|defwinproc },
+ { WM_MDIDESTROY, sent }, /* in MDI client */
+
+ /* bring the 1st MDI child to top */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
+
+ { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+
+ { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
+ { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
+
+ /* maximize the 1st MDI child */
+ { HCBT_MINMAX, hook },
+ { WM_GETMINMAXINFO, sent|defwinproc },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|0x8000 },
+ { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
+ { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+
+ /* restore the 2nd MDI child */
+ { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
+ { HCBT_MINMAX, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOZORDER|0x8000 },
+ { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
+
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+
+ { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+
+ /* bring the 1st MDI child to top */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent|defwinproc },
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+ { WM_MDIACTIVATE, sent|defwinproc },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+
+ /* apparently ShowWindow(SW_SHOW) on an MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { WM_MDIREFRESHMENU, sent },
+
+ { HCBT_DESTROYWND, hook },
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent|defwinproc },
+ { WM_NCDESTROY, sent|defwinproc },
+ { 0 }
+};
+/* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
+static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
+ { WM_MDIDESTROY, sent }, /* in MDI client */
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI client */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI client */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent|defwinproc },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+
+ { WM_NCACTIVATE, sent|wparam, 0 },
+ { WM_MDIACTIVATE, sent },
+
+ { HCBT_MINMAX, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI child */
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_MOVE, sent|defwinproc },
+ { WM_SIZE, sent|defwinproc },
+
+ /* in MDI client */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTMOVE },
+ { WM_SIZE, sent },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+
+ { WM_MDIREFRESHMENU, sent }, /* in MDI client */
+
+ { HCBT_DESTROYWND, hook },
+ /* Win2k sends wparam set to
+ * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
+ * while Win9x doesn't bother to set child window id according to
+ * CLIENTCREATESTRUCT.idFirstChild
+ */
+ { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
+
+ { WM_SHOWWINDOW, sent|wparam, 0 },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_ERASEBKGND, sent|parent|optional },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+
+ { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_DESTROY, sent },
+ { WM_NCDESTROY, sent },
+ { 0 }
+};
+/* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
+static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
+ { HCBT_MINMAX, hook },
+ { WM_GETMINMAXINFO, sent },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+
+ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent }, /* in MDI client */
+ { HCBT_SETFOCUS, hook },
+ { WM_KILLFOCUS, sent }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|defwinproc },
+ { WM_MDIACTIVATE, sent|defwinproc },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { 0 }
+};
+/* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
+static const struct message WmMaximizeMDIchildVisibleSeq[] = {
+ { HCBT_MINMAX, hook },
+ { WM_GETMINMAXINFO, sent },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { 0 }
+};
+/* ShowWindow(SW_RESTORE) for a visible MDI child window */
+static const struct message WmRestoreMDIchildVisibleSeq[] = {
+ { HCBT_MINMAX, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { 0 }
+};
+/* ShowWindow(SW_RESTORE) for a not visible MDI child window */
+static const struct message WmRestoreMDIchildInisibleSeq[] = {
+ { HCBT_MINMAX, hook },
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|0x8000 },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|0x8000 },
+ { WM_SIZE, sent|defwinproc },
+ /* in MDI frame */
+ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER },
+ { WM_NCCALCSIZE, sent|wparam, 1 },
+ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
+ { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
+ { 0 }
+};
+
+static HWND mdi_client;
+static WNDPROC old_mdi_client_proc;
+
+static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ struct message msg;
+
+ /* do not log painting messages */
+ if (message != WM_PAINT &&
+ message != WM_ERASEBKGND &&
+ message != WM_NCPAINT &&
+ message != WM_NCHITTEST &&
+ message != WM_GETTEXT &&
+ message != WM_MDIGETACTIVE &&
+ message != WM_DEVICECHANGE)
+ {
+ trace("mdi client: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *winpos = (WINDOWPOS *)lParam;
+
+ trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
+ trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+ winpos->hwnd, winpos->hwndInsertAfter,
+ winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+ /* Log only documented flags, win2k uses 0x1000 and 0x2000
+ * in the high word for internal purposes
+ */
+ wParam = winpos->flags & 0xffff;
+ break;
+ }
+ }
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+ }
+
+ return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
+}
+
+static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ /* do not log painting messages */
+ if (message != WM_PAINT &&
+ message != WM_ERASEBKGND &&
+ message != WM_NCPAINT &&
+ message != WM_NCHITTEST &&
+ message != WM_GETTEXT &&
+ message != WM_DEVICECHANGE)
+ {
+ trace("mdi child: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *winpos = (WINDOWPOS *)lParam;
+
+ trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
+ trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+ winpos->hwnd, winpos->hwndInsertAfter,
+ winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+ /* Log only documented flags, win2k uses 0x1000 and 0x2000
+ * in the high word for internal purposes
+ */
+ wParam = winpos->flags & 0xffff;
+ break;
+ }
+
+ case WM_MDIACTIVATE:
+ {
+ HWND active, client = GetParent(hwnd);
+
+ active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
+
+ if (hwnd == (HWND)lParam) /* if we are being activated */
+ ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
+ else
+ ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
+ break;
+ }
+ }
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+ }
+
+ defwndproc_counter++;
+ ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
+static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ /* do not log painting messages */
+ if (message != WM_PAINT &&
+ message != WM_ERASEBKGND &&
+ message != WM_NCPAINT &&
+ message != WM_NCHITTEST &&
+ message != WM_GETTEXT &&
+ message != WM_DEVICECHANGE)
+ {
+ trace("mdi frame: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *winpos = (WINDOWPOS *)lParam;
+
+ trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
+ trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+ winpos->hwnd, winpos->hwndInsertAfter,
+ winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+ /* Log only documented flags, win2k uses 0x1000 and 0x2000
+ * in the high word for internal purposes
+ */
+ wParam = winpos->flags & 0xffff;
+ break;
+ }
+ }
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+ }
+
+ defwndproc_counter++;
+ ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
+static BOOL mdi_RegisterWindowClasses(void)
+{
+ WNDCLASSA cls;
+
+ cls.style = 0;
+ cls.lpfnWndProc = mdi_frame_wnd_proc;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = GetModuleHandleA(0);
+ cls.hIcon = 0;
+ cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+ cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = "MDI_frame_class";
+ if (!RegisterClassA(&cls)) return FALSE;
+
+ cls.lpfnWndProc = mdi_child_wnd_proc;
+ cls.lpszClassName = "MDI_child_class";
+ if (!RegisterClassA(&cls)) return FALSE;
+
+ if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
+ old_mdi_client_proc = cls.lpfnWndProc;
+ cls.hInstance = GetModuleHandleA(0);
+ cls.lpfnWndProc = mdi_client_hook_proc;
+ cls.lpszClassName = "MDI_client_class";
+ if (!RegisterClassA(&cls)) assert(0);
+
+ return TRUE;
+}
+
+static void test_mdi_messages(void)
+{
+ MDICREATESTRUCTA mdi_cs;
+ CLIENTCREATESTRUCT client_cs;
+ HWND mdi_frame, mdi_child, mdi_child2, active_child;
+ BOOL zoomed;
+ HMENU hMenu = CreateMenu();
+
+ assert(mdi_RegisterWindowClasses());
+
+ flush_sequence();
+
+ trace("creating MDI frame window\n");
+ mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
+ WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+ WS_MAXIMIZEBOX | WS_VISIBLE,
+ 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
+ GetDesktopWindow(), hMenu,
+ GetModuleHandleA(0), NULL);
+ assert(mdi_frame);
+ ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", TRUE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
+
+ trace("creating MDI client window\n");
+ client_cs.hWindowMenu = 0;
+ client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
+ mdi_client = CreateWindowExA(0, "MDI_client_class",
+ NULL,
+ WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
+ 0, 0, 0, 0,
+ mdi_frame, 0, GetModuleHandleA(0), &client_cs);
+ assert(mdi_client);
+ ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(!active_child, "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+
+ SetFocus(0);
+ flush_sequence();
+
+ trace("creating invisible MDI child window\n");
+ mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
+ WS_CHILD,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ mdi_client, 0, GetModuleHandleA(0), NULL);
+ assert(mdi_child);
+
+ flush_sequence();
+ ShowWindow(mdi_child, SW_SHOWNORMAL);
+ ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
+
+ ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
+ ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(!active_child, "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+
+ ShowWindow(mdi_child, SW_HIDE);
+ ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
+ flush_sequence();
+
+ ShowWindow(mdi_child, SW_SHOW);
+ ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
+
+ ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
+ ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(!active_child, "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+
+ DestroyWindow(mdi_child);
+ flush_sequence();
+
+ trace("creating visible MDI child window\n");
+ mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
+ WS_CHILD | WS_VISIBLE,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ mdi_client, 0, GetModuleHandleA(0), NULL);
+ assert(mdi_child);
+ ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
+
+ ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
+ ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ DestroyWindow(mdi_child);
+ ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ /* Win2k: MDI client still returns a just destroyed child as active
+ * Win9x: MDI client returns 0
+ */
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child || /* win2k */
+ !active_child, /* win9x */
+ "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+
+ flush_sequence();
+
+ trace("creating invisible MDI child window\n");
+ mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
+ WS_CHILD,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ mdi_client, 0, GetModuleHandleA(0), NULL);
+ assert(mdi_child2);
+ ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
+
+ ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
+ ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ /* Win2k: MDI client still returns a just destroyed child as active
+ * Win9x: MDI client returns mdi_child2
+ */
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child || /* win2k */
+ active_child == mdi_child2, /* win9x */
+ "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ ShowWindow(mdi_child2, SW_MAXIMIZE);
+ ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", TRUE);
+
+ ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
+ ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
+ ok(zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child2 || /* win2k */
+ GetFocus() == 0, /* win9x */
+ "wrong focus window %p\n", GetFocus());
+
+ SetFocus(0);
+ flush_sequence();
+
+ ShowWindow(mdi_child2, SW_HIDE);
+ ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
+
+ ShowWindow(mdi_child2, SW_RESTORE);
+ ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", TRUE);
+ flush_sequence();
+
+ ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
+ ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
+ ok(!zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ SetFocus(0);
+ flush_sequence();
+
+ ShowWindow(mdi_child2, SW_HIDE);
+ ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
+
+ ShowWindow(mdi_child2, SW_SHOW);
+ ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ ShowWindow(mdi_child2, SW_MAXIMIZE);
+ ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", TRUE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ ShowWindow(mdi_child2, SW_RESTORE);
+ ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):MDI child", TRUE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ SetFocus(0);
+ flush_sequence();
+
+ ShowWindow(mdi_child2, SW_HIDE);
+ ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ DestroyWindow(mdi_child2);
+ ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ /* test for maximized MDI children */
+ trace("creating maximized visible MDI child window 1\n");
+ mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
+ WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ mdi_client, 0, GetModuleHandleA(0), NULL);
+ assert(mdi_child);
+ ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
+ ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child || /* win2k */
+ GetFocus() == 0, /* win9x */
+ "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
+ ok(zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ trace("creating maximized visible MDI child window 2\n");
+ mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
+ WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ mdi_client, 0, GetModuleHandleA(0), NULL);
+ assert(mdi_child2);
+ ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
+ ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
+ ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
+ ok(zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ trace("destroying maximized visible MDI child window 2\n");
+ DestroyWindow(mdi_child2);
+ ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
+
+ ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ /* Win2k: MDI client still returns a just destroyed child as active
+ * Win9x: MDI client returns 0
+ */
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child2 || /* win2k */
+ !active_child, /* win9x */
+ "wrong active MDI child %p\n", active_child);
+ flush_sequence();
+
+ ShowWindow(mdi_child, SW_MAXIMIZE);
+ ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
+ flush_sequence();
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
+
+ trace("re-creating maximized visible MDI child window 2\n");
+ mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
+ WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ mdi_client, 0, GetModuleHandleA(0), NULL);
+ assert(mdi_child2);
+ ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
+ ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
+ ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
+ ok(zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
+ ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
+ ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
+
+ ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
+ ok(zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ DestroyWindow(mdi_child);
+ ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
+
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
+
+ /* Win2k: MDI client still returns a just destroyed child as active
+ * Win9x: MDI client returns 0
+ */
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child || /* win2k */
+ !active_child, /* win9x */
+ "wrong active MDI child %p\n", active_child);
+ flush_sequence();
+ /* end of test for maximized MDI children */
+
+ mdi_cs.szClass = "MDI_child_Class";
+ mdi_cs.szTitle = "MDI child";
+ mdi_cs.hOwner = GetModuleHandleA(0);
+ mdi_cs.x = 0;
+ mdi_cs.y = 0;
+ mdi_cs.cx = CW_USEDEFAULT;
+ mdi_cs.cy = CW_USEDEFAULT;
+ mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
+ mdi_cs.lParam = 0;
+ mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
+ ok(mdi_child != 0, "MDI child creation failed\n");
+ ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
+
+ ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
+
+ ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
+ ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
+ ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
+
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
+ ok(zoomed, "wrong zoomed state %d\n", zoomed);
+ flush_sequence();
+
+ SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
+ ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
+
+ ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
+ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
+ ok(!active_child, "wrong active MDI child %p\n", active_child);
+
+ SetFocus(0);
+ flush_sequence();
+
+ DestroyWindow(mdi_client);
+ ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
+
+ DestroyWindow(mdi_frame);
+ ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
+}
+/************************* End of MDI test **********************************/
+
+static void test_WM_SETREDRAW(HWND hwnd)
+{
+ DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
+
+ flush_sequence();
+
+ SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
+ ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
+
+ ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
+ ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
+
+ flush_sequence();
+ SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
+ ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
+
+ ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
+ ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
+
+ /* restore original WS_VISIBLE state */
+ SetWindowLongA(hwnd, GWL_STYLE, style);
+
+ flush_sequence();
+}
+
+static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ struct message msg;
+
+ trace("dialog: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *winpos = (WINDOWPOS *)lParam;
+
+ trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
+ trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+ winpos->hwnd, winpos->hwndInsertAfter,
+ winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+ /* Log only documented flags, win2k uses 0x1000 and 0x2000
+ * in the high word for internal purposes
+ */
+ wParam = winpos->flags & 0xffff;
+ break;
+ }
+ }
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+
+ if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
+ if (message == WM_TIMER) EndDialog( hwnd, 0 );
+ return 0;
+}
+
+static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
+{
+ DWORD style, exstyle;
+ INT xmin, xmax;
+ BOOL ret;
+
+ exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
+ style = GetWindowLongA(hwnd, GWL_STYLE);
+ /* do not be confused by WS_DLGFRAME set */
+ if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
+
+ if (clear) ok(style & clear, "style %08lx should be set\n", clear);
+ if (set) ok(!(style & set), "style %08lx should not be set\n", set);
+
+ ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
+ ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
+ if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
+ ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
+ else
+ ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
+
+ style = GetWindowLongA(hwnd, GWL_STYLE);
+ if (set) ok(style & set, "style %08lx should be set\n", set);
+ if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
+
+ /* a subsequent call should do nothing */
+ ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
+ ok( ret, "SetScrollRange(%d) error %ld\n", ctl, GetLastError());
+ ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
+
+ xmin = 0xdeadbeef;
+ xmax = 0xdeadbeef;
+ trace("Ignore GetScrollRange error below if you are on Win9x\n");
+ ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
+ ok( ret, "GetScrollRange(%d) error %ld\n", ctl, GetLastError());
+ ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
+ ok(xmin == min, "unexpected min scroll value %d\n", xmin);
+ ok(xmax == max, "unexpected max scroll value %d\n", xmax);
+}
+
+static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
+{
+ DWORD style, exstyle;
+ SCROLLINFO si;
+ BOOL ret;
+
+ exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
+ style = GetWindowLongA(hwnd, GWL_STYLE);
+ /* do not be confused by WS_DLGFRAME set */
+ if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
+
+ if (clear) ok(style & clear, "style %08lx should be set\n", clear);
+ if (set) ok(!(style & set), "style %08lx should not be set\n", set);
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE;
+ si.nMin = min;
+ si.nMax = max;
+ SetScrollInfo(hwnd, ctl, &si, TRUE);
+ if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
+ ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
+ else
+ ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
+
+ style = GetWindowLongA(hwnd, GWL_STYLE);
+ if (set) ok(style & set, "style %08lx should be set\n", set);
+ if (clear) ok(!(style & clear), "style %08lx should not be set\n", clear);
+
+ /* a subsequent call should do nothing */
+ SetScrollInfo(hwnd, ctl, &si, TRUE);
+ if (style & WS_HSCROLL)
+ ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
+ else if (style & WS_VSCROLL)
+ ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
+ else
+ ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
+
+ si.fMask = SIF_PAGE;
+ si.nPage = 5;
+ SetScrollInfo(hwnd, ctl, &si, FALSE);
+ ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
+
+ si.fMask = SIF_POS;
+ si.nPos = max - 1;
+ SetScrollInfo(hwnd, ctl, &si, FALSE);
+ ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
+
+ si.fMask = SIF_RANGE;
+ si.nMin = 0xdeadbeef;
+ si.nMax = 0xdeadbeef;
+ ret = GetScrollInfo(hwnd, ctl, &si);
+ ok( ret, "GetScrollInfo error %ld\n", GetLastError());
+ ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
+ ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
+ ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
+}
+
+/* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
+static void test_scroll_messages(HWND hwnd)
+{
+ SCROLLINFO si;
+ INT min, max;
+ BOOL ret;
+
+ min = 0xdeadbeef;
+ max = 0xdeadbeef;
+ ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
+ ok( ret, "GetScrollRange error %ld\n", GetLastError());
+ if (sequence->message != WmGetScrollRangeSeq[0].message)
+ trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
+ /* values of min and max are undefined */
+ flush_sequence();
+
+ ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
+ ok( ret, "SetScrollRange error %ld\n", GetLastError());
+ if (sequence->message != WmSetScrollRangeSeq[0].message)
+ trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
+ flush_sequence();
+
+ min = 0xdeadbeef;
+ max = 0xdeadbeef;
+ ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
+ ok( ret, "GetScrollRange error %ld\n", GetLastError());
+ if (sequence->message != WmGetScrollRangeSeq[0].message)
+ trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
+ /* values of min and max are undefined */
+ flush_sequence();
+
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE;
+ si.nMin = 20;
+ si.nMax = 160;
+ SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
+ if (sequence->message != WmSetScrollRangeSeq[0].message)
+ trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
+ flush_sequence();
+
+ si.fMask = SIF_PAGE;
+ si.nPage = 10;
+ SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
+ if (sequence->message != WmSetScrollRangeSeq[0].message)
+ trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
+ flush_sequence();
+
+ si.fMask = SIF_POS;
+ si.nPos = 20;
+ SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
+ if (sequence->message != WmSetScrollRangeSeq[0].message)
+ trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
+ flush_sequence();
+
+ si.fMask = SIF_RANGE;
+ si.nMin = 0xdeadbeef;
+ si.nMax = 0xdeadbeef;
+ ret = GetScrollInfo(hwnd, SB_CTL, &si);
+ ok( ret, "GetScrollInfo error %ld\n", GetLastError());
+ if (sequence->message != WmGetScrollInfoSeq[0].message)
+ trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
+ /* values of min and max are undefined */
+ flush_sequence();
+
+ /* set WS_HSCROLL */
+ test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
+ /* clear WS_HSCROLL */
+ test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
+
+ /* set WS_HSCROLL */
+ test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
+ /* clear WS_HSCROLL */
+ test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
+
+ /* set WS_VSCROLL */
+ test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
+ /* clear WS_VSCROLL */
+ test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
+
+ /* set WS_VSCROLL */
+ test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
+ /* clear WS_VSCROLL */
+ test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
+}
+
+static void test_showwindow(void)
+{
+ HWND hwnd, hchild;
+
+ hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hwnd != 0, "Failed to create overlapped window\n");
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
+ 0, 0, 10, 10, hwnd, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child\n");
+ flush_sequence();
+
+ /* ShowWindow( SW_SHOWNA) for invisible top level window */
+ trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
+ ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
+ ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE);
+ trace("done\n");
+
+ /* ShowWindow( SW_SHOWNA) for now visible top level window */
+ trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
+ ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
+ ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
+ trace("done\n");
+ /* back to invisible */
+ ShowWindow(hchild, SW_HIDE);
+ ShowWindow(hwnd, SW_HIDE);
+ flush_sequence();
+ /* ShowWindow(SW_SHOWNA) with child and parent invisible */
+ trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
+ ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
+ ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", TRUE);
+ trace("done\n");
+ /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
+ ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
+ flush_sequence();
+ trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
+ ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
+ ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", TRUE);
+ trace("done\n");
+ /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
+ ShowWindow( hwnd, SW_SHOW);
+ flush_sequence();
+ trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
+ ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
+ ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
+ trace("done\n");
+
+ /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
+ ShowWindow( hchild, SW_HIDE);
+ flush_sequence();
+ trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
+ ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
+ ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
+ trace("done\n");
+
+ SetCapture(hchild);
+ ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
+ DestroyWindow(hchild);
+ ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
+
+ DestroyWindow(hwnd);
+ flush_sequence();
+}
+
+static void test_sys_menu(HWND hwnd)
+{
+ HMENU hmenu;
+ UINT state;
+
+ /* test existing window without CS_NOCLOSE style */
+ hmenu = GetSystemMenu(hwnd, FALSE);
+ ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
+
+ state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+ ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+ ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
+
+ EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
+ ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
+
+ state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+ ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+ ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
+
+ EnableMenuItem(hmenu, SC_CLOSE, 0);
+ ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
+
+ state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+ ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+ ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
+
+ /* test new window with CS_NOCLOSE style */
+ hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hwnd != 0, "Failed to create overlapped window\n");
+
+ hmenu = GetSystemMenu(hwnd, FALSE);
+ ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
+
+ state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+ ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+
+ DestroyWindow(hwnd);
+}
+
+/* test if we receive the right sequence of messages */
+static void test_messages(void)
+{
+ HWND hwnd, hparent, hchild;
+ HWND hchild2, hbutton;
+ HMENU hmenu;
+ MSG msg;
+ DWORD ret;
+
+ flush_sequence();
+
+ hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hwnd != 0, "Failed to create overlapped window\n");
+ ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
+
+ /* test ShowWindow(SW_HIDE) on a newly created invisible window */
+ ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
+ ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
+
+ /* test WM_SETREDRAW on a not visible top level window */
+ test_WM_SETREDRAW(hwnd);
+
+ SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
+ ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
+ ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
+
+ ok(GetActiveWindow() == hwnd, "window should be active\n");
+ ok(GetFocus() == hwnd, "window should have input focus\n");
+ ShowWindow(hwnd, SW_HIDE);
+ ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
+
+ ShowWindow(hwnd, SW_SHOW);
+ ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
+
+ ShowWindow(hwnd, SW_SHOW);
+ ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
+
+ ok(GetActiveWindow() == hwnd, "window should be active\n");
+ ok(GetFocus() == hwnd, "window should have input focus\n");
+ SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
+ ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
+ ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
+ ok(GetActiveWindow() == hwnd, "window should still be active\n");
+
+ /* test WM_SETREDRAW on a visible top level window */
+ ShowWindow(hwnd, SW_SHOW);
+ test_WM_SETREDRAW(hwnd);
+
+ trace("testing scroll APIs on a visible top level window %p\n", hwnd);
+ test_scroll_messages(hwnd);
+
+ /* test resizing and moving */
+ SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
+ ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
+ SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );
+ ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
+
+ /* popups don't get WM_GETMINMAXINFO */
+ SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
+ SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
+ flush_sequence();
+ SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
+ ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
+
+ test_sys_menu(hwnd);
+
+ flush_sequence();
+ DestroyWindow(hwnd);
+ ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
+
+ hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hparent != 0, "Failed to create parent window\n");
+ flush_sequence();
+
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
+ 0, 0, 10, 10, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child window\n");
+ ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", TRUE);
+ DestroyWindow(hchild);
+ flush_sequence();
+
+ /* visible child window with a caption */
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
+ WS_CHILD | WS_VISIBLE | WS_CAPTION,
+ 0, 0, 10, 10, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child window\n");
+ ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
+
+ trace("testing scroll APIs on a visible child window %p\n", hchild);
+ test_scroll_messages(hchild);
+
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
+ ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
+
+ DestroyWindow(hchild);
+ flush_sequence();
+
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
+ 0, 0, 10, 10, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child window\n");
+ ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
+
+ hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
+ 100, 100, 50, 50, hparent, 0, 0, NULL);
+ ok (hchild2 != 0, "Failed to create child2 window\n");
+ flush_sequence();
+
+ hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
+ 0, 100, 50, 50, hchild, 0, 0, NULL);
+ ok (hbutton != 0, "Failed to create button window\n");
+
+ /* test WM_SETREDRAW on a not visible child window */
+ test_WM_SETREDRAW(hchild);
+
+ ShowWindow(hchild, SW_SHOW);
+ ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
+
+ ShowWindow(hchild, SW_HIDE);
+ ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
+
+ ShowWindow(hchild, SW_SHOW);
+ ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
+
+ /* test WM_SETREDRAW on a visible child window */
+ test_WM_SETREDRAW(hchild);
+
+ MoveWindow(hchild, 10, 10, 20, 20, TRUE);
+ ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
+
+ ShowWindow(hchild, SW_HIDE);
+ flush_sequence();
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
+ ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
+
+ ShowWindow(hchild, SW_HIDE);
+ flush_sequence();
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
+ ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
+
+ /* DestroyWindow sequence below expects that a child has focus */
+ SetFocus(hchild);
+ flush_sequence();
+
+ DestroyWindow(hchild);
+ ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
+ DestroyWindow(hchild2);
+ DestroyWindow(hbutton);
+
+ flush_sequence();
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
+ 0, 0, 100, 100, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child popup window\n");
+ ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
+ DestroyWindow(hchild);
+
+ /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
+ flush_sequence();
+ hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
+ 0, 0, 100, 100, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create popup window\n");
+ ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
+ ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
+ ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
+ flush_sequence();
+ ShowWindow(hchild, SW_SHOW);
+ ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
+ flush_sequence();
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
+ ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
+ flush_sequence();
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
+ ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
+ DestroyWindow(hchild);
+
+ /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
+ * changes nothing in message sequences.
+ */
+ flush_sequence();
+ hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
+ 0, 0, 100, 100, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create popup window\n");
+ ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
+ ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
+ ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
+ flush_sequence();
+ ShowWindow(hchild, SW_SHOW);
+ ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
+ flush_sequence();
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
+ ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
+ DestroyWindow(hchild);
+
+ flush_sequence();
+ hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
+ 0, 0, 100, 100, hparent, 0, 0, NULL);
+ ok(hwnd != 0, "Failed to create custom dialog window\n");
+ ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
+
+ /*
+ trace("testing scroll APIs on a visible dialog %p\n", hwnd);
+ test_scroll_messages(hwnd);
+ */
+
+ flush_sequence();
+ after_end_dialog = 1;
+ EndDialog( hwnd, 0 );
+ ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
+
+ DestroyWindow(hwnd);
+ after_end_dialog = 0;
+
+ hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP,
+ 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
+ ok(hwnd != 0, "Failed to create custom dialog window\n");
+ flush_sequence();
+ trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
+ ShowWindow(hwnd, SW_SHOW);
+ ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
+ DestroyWindow(hwnd);
+
+ flush_sequence();
+ DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
+ ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
+
+ /* test showing child with hidden parent */
+ ShowWindow( hparent, SW_HIDE );
+ flush_sequence();
+
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
+ 0, 0, 10, 10, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child window\n");
+ ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
+
+ ShowWindow( hchild, SW_SHOW );
+ ok_sequence(WmShowChildInvisibleParentSeq, "ShowWindow:show child with invisible parent", TRUE);
+ ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
+ ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
+
+ ShowWindow( hchild, SW_HIDE );
+ ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", TRUE);
+ ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
+ ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
+
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
+ ok_sequence(WmShowChildInvisibleParentSeq_2, "SetWindowPos:show child with invisible parent", FALSE);
+ ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
+ ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
+
+ SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
+ ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
+ ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
+ ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
+
+ DestroyWindow(hchild);
+ DestroyWindow(hparent);
+ flush_sequence();
+
+ /* Message sequence for SetMenu */
+ ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a window without a menu\n");
+ ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
+
+ hmenu = CreateMenu();
+ ok (hmenu != 0, "Failed to create menu\n");
+ ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
+ hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, hmenu, 0, NULL);
+ ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
+ ok (SetMenu(hwnd, 0), "SetMenu\n");
+ ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
+ ok (SetMenu(hwnd, 0), "SetMenu\n");
+ ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
+ ShowWindow(hwnd, SW_SHOW);
+ flush_sequence();
+ ok (SetMenu(hwnd, 0), "SetMenu\n");
+ ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", TRUE);
+ ok (SetMenu(hwnd, hmenu), "SetMenu\n");
+ ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", TRUE);
+
+ ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
+ ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", TRUE);
+
+ DestroyWindow(hwnd);
+ flush_sequence();
+
+ /* Message sequence for EnableWindow */
+ hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hparent != 0, "Failed to create parent window\n");
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
+ 0, 0, 10, 10, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child window\n");
+
+ SetFocus(hchild);
+ flush_sequence();
+
+ EnableWindow(hparent, FALSE);
+ ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
+
+ EnableWindow(hparent, TRUE);
+ ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE);
+
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ flush_sequence();
+
+ /* MsgWaitForMultipleObjects test */
+ ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
+ ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
+
+ PostMessageA(hparent, WM_USER, 0, 0);
+
+ ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
+ ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %lx\n", ret);
+
+ ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
+ ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
+
+ ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
+ ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %lx\n", ret);
+ /* end of MsgWaitForMultipleObjects test */
+
+ /* the following test causes an exception in user.exe under win9x */
+ if (!PostMessageW( hparent, WM_USER, 0, 0 )) return;
+ PostMessageW( hparent, WM_USER+1, 0, 0 );
+ /* PeekMessage(NULL) fails, but still removes the message */
+ SetLastError(0xdeadbeef);
+ ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
+ ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
+ GetLastError() == 0xdeadbeef, /* NT4 */
+ "last error is %ld\n", GetLastError() );
+ ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
+ ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
+
+ DestroyWindow(hchild);
+ DestroyWindow(hparent);
+ flush_sequence();
+
+ test_showwindow();
+}
+
+/****************** button message test *************************/
+static const struct message WmSetFocusButtonSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { 0 }
+};
+static const struct message WmKillFocusButtonSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_KILLFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { 0 }
+};
+static const struct message WmSetFocusStaticSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORSTATIC, sent|defwinproc },
+ { 0 }
+};
+static const struct message WmKillFocusStaticSeq[] =
+{
+ { HCBT_SETFOCUS, hook },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_KILLFOCUS, sent|wparam, 0 },
+ { WM_CTLCOLORSTATIC, sent|defwinproc },
+ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
+ { 0 }
+};
+static const struct message WmLButtonDownSeq[] =
+{
+ { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
+ { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
+ { HCBT_SETFOCUS, hook },
+ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { 0 }
+};
+static const struct message WmLButtonUpSeq[] =
+{
+ { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
+ { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
+ { WM_CTLCOLORBTN, sent|defwinproc },
+ { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+ { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
+ { 0 }
+};
+
+static WNDPROC old_button_proc;
+
+static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ trace("button: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+
+ if (message == BM_SETSTATE)
+ ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
+
+ defwndproc_counter++;
+ ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
+static void subclass_button(void)
+{
+ WNDCLASSA cls;
+
+ if (!GetClassInfoA(0, "button", &cls)) assert(0);
+
+ old_button_proc = cls.lpfnWndProc;
+
+ cls.hInstance = GetModuleHandle(0);
+ cls.lpfnWndProc = button_hook_proc;
+ cls.lpszClassName = "my_button_class";
+ if (!RegisterClassA(&cls)) assert(0);
+}
+
+static void test_button_messages(void)
+{
+ static const struct
+ {
+ DWORD style;
+ DWORD dlg_code;
+ const struct message *setfocus;
+ const struct message *killfocus;
+ } button[] = {
+ { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
+ WmSetFocusButtonSeq, WmKillFocusButtonSeq },
+ { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
+ WmSetFocusButtonSeq, WmKillFocusButtonSeq },
+ { BS_CHECKBOX, DLGC_BUTTON,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_AUTOCHECKBOX, DLGC_BUTTON,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_3STATE, DLGC_BUTTON,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_AUTO3STATE, DLGC_BUTTON,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_GROUPBOX, DLGC_STATIC,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
+ WmSetFocusButtonSeq, WmKillFocusButtonSeq },
+ { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
+ WmSetFocusStaticSeq, WmKillFocusStaticSeq },
+ { BS_OWNERDRAW, DLGC_BUTTON,
+ WmSetFocusButtonSeq, WmKillFocusButtonSeq }
+ };
+ unsigned int i;
+ HWND hwnd;
+ DWORD dlg_code;
+
+ subclass_button();
+
+ for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
+ {
+ hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP,
+ 0, 0, 50, 14, 0, 0, 0, NULL);
+ ok(hwnd != 0, "Failed to create button window\n");
+
+ dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
+ ok(dlg_code == button[i].dlg_code, "%d: wrong dlg_code %08lx\n", i, dlg_code);
+
+ ShowWindow(hwnd, SW_SHOW);
+ UpdateWindow(hwnd);
+ SetFocus(0);
+ flush_sequence();
+
+ trace("button style %08lx\n", button[i].style);
+ SetFocus(hwnd);
+ ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
+
+ SetFocus(0);
+ ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
+
+ DestroyWindow(hwnd);
+ }
+
+ hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE,
+ 0, 0, 50, 14, 0, 0, 0, NULL);
+ ok(hwnd != 0, "Failed to create button window\n");
+
+ SetFocus(0);
+ flush_sequence();
+
+ SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
+ ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
+
+ SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
+ ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
+ DestroyWindow(hwnd);
+}
+
+/************* painting message test ********************/
+
+void dump_region(HRGN hrgn)
+{
+ DWORD i, size;
+ RGNDATA *data = NULL;
+ RECT *rect;
+
+ if (!hrgn)
+ {
+ printf( "null region\n" );
+ return;
+ }
+ if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
+ if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
+ GetRegionData( hrgn, size, data );
+ printf("%ld rects:", data->rdh.nCount );
+ for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
+ printf( " (%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom );
+ printf("\n");
+ HeapFree( GetProcessHeap(), 0, data );
+}
+
+static void check_update_rgn( HWND hwnd, HRGN hrgn )
+{
+ INT ret;
+ RECT r1, r2;
+ HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN update = CreateRectRgn( 0, 0, 0, 0 );
+
+ ret = GetUpdateRgn( hwnd, update, FALSE );
+ ok( ret != ERROR, "GetUpdateRgn failed\n" );
+ if (ret == NULLREGION)
+ {
+ ok( !hrgn, "Update region shouldn't be empty\n" );
+ }
+ else
+ {
+ if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
+ {
+ ok( 0, "Regions are different\n" );
+ if (winetest_debug > 0)
+ {
+ printf( "Update region: " );
+ dump_region( update );
+ printf( "Wanted region: " );
+ dump_region( hrgn );
+ }
+ }
+ }
+ GetRgnBox( update, &r1 );
+ GetUpdateRect( hwnd, &r2, FALSE );
+ ok( r1.left == r2.left && r1.top == r2.top && r1.right == r2.right && r1.bottom == r2.bottom,
+ "Rectangles are different: %ld,%ld-%ld,%ld / %ld,%ld-%ld,%ld\n",
+ r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom );
+
+ DeleteObject( tmp );
+ DeleteObject( update );
+}
+
+static const struct message WmInvalidateRgn[] = {
+ { WM_NCPAINT, sent },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { 0 }
+};
+
+static const struct message WmGetUpdateRect[] = {
+ { WM_NCPAINT, sent },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_PAINT, sent },
+ { 0 }
+};
+
+static const struct message WmInvalidateFull[] = {
+ { WM_NCPAINT, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { 0 }
+};
+
+static const struct message WmInvalidateErase[] = {
+ { WM_NCPAINT, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent },
+ { 0 }
+};
+
+static const struct message WmInvalidatePaint[] = {
+ { WM_PAINT, sent },
+ { WM_NCPAINT, sent|wparam|beginpaint, 1 },
+ { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
+ { 0 }
+};
+
+static const struct message WmInvalidateErasePaint[] = {
+ { WM_PAINT, sent },
+ { WM_NCPAINT, sent|wparam|beginpaint, 1 },
+ { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
+ { WM_ERASEBKGND, sent|beginpaint },
+ { 0 }
+};
+
+static const struct message WmInvalidateErasePaint2[] = {
+ { WM_PAINT, sent },
+ { WM_NCPAINT, sent|beginpaint },
+ { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
+ { WM_ERASEBKGND, sent|beginpaint },
+ { 0 }
+};
+
+static const struct message WmErase[] = {
+ { WM_ERASEBKGND, sent },
+ { 0 }
+};
+
+static const struct message WmPaint[] = {
+ { WM_PAINT, sent },
+ { 0 }
+};
+
+static const struct message WmParentOnlyPaint[] = {
+ { WM_PAINT, sent|parent },
+ { 0 }
+};
+
+static const struct message WmInvalidateParent[] = {
+ { WM_NCPAINT, sent|parent },
+ { WM_GETTEXT, sent|defwinproc|parent|optional },
+ { WM_ERASEBKGND, sent|parent },
+ { 0 }
+};
+
+static const struct message WmInvalidateParentChild[] = {
+ { WM_NCPAINT, sent|parent },
+ { WM_GETTEXT, sent|defwinproc|parent|optional },
+ { WM_ERASEBKGND, sent|parent },
+ { WM_NCPAINT, sent },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent },
+ { 0 }
+};
+
+static const struct message WmInvalidateParentChild2[] = {
+ { WM_ERASEBKGND, sent|parent },
+ { WM_NCPAINT, sent },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_ERASEBKGND, sent },
+ { 0 }
+};
+
+static const struct message WmParentPaint[] = {
+ { WM_PAINT, sent|parent },
+ { WM_PAINT, sent },
+ { 0 }
+};
+
+static const struct message WmParentPaintNc[] = {
+ { WM_PAINT, sent|parent },
+ { WM_PAINT, sent },
+ { WM_NCPAINT, sent|beginpaint },
+ { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
+ { WM_ERASEBKGND, sent|beginpaint },
+ { 0 }
+};
+
+static const struct message WmChildPaintNc[] = {
+ { WM_PAINT, sent },
+ { WM_NCPAINT, sent|beginpaint },
+ { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
+ { WM_ERASEBKGND, sent|beginpaint },
+ { 0 }
+};
+
+static const struct message WmParentErasePaint[] = {
+ { WM_PAINT, sent|parent },
+ { WM_NCPAINT, sent|parent|beginpaint },
+ { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
+ { WM_ERASEBKGND, sent|parent|beginpaint },
+ { WM_PAINT, sent },
+ { WM_NCPAINT, sent|beginpaint },
+ { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
+ { WM_ERASEBKGND, sent|beginpaint },
+ { 0 }
+};
+
+static const struct message WmParentOnlyNcPaint[] = {
+ { WM_PAINT, sent|parent },
+ { WM_NCPAINT, sent|parent|beginpaint },
+ { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
+ { 0 }
+};
+
+static const struct message WmSetParentStyle[] = {
+ { WM_STYLECHANGING, sent|parent },
+ { WM_STYLECHANGED, sent|parent },
+ { 0 }
+};
+
+static void test_paint_messages(void)
+{
+ RECT rect;
+ POINT pt;
+ MSG msg;
+ HWND hparent, hchild;
+ HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
+ HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
+ HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hwnd != 0, "Failed to create overlapped window\n");
+
+ ShowWindow( hwnd, SW_SHOW );
+ UpdateWindow( hwnd );
+
+ /* try to flush pending X expose events */
+ MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+
+ check_update_rgn( hwnd, 0 );
+ SetRectRgn( hrgn, 10, 10, 20, 20 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
+ check_update_rgn( hwnd, hrgn );
+ SetRectRgn( hrgn2, 20, 20, 30, 30 );
+ RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
+ CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
+ check_update_rgn( hwnd, hrgn );
+ /* validate everything */
+ RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
+ check_update_rgn( hwnd, 0 );
+ /* now with frame */
+ SetRectRgn( hrgn, -5, -5, 20, 20 );
+
+ /* flush pending messages */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+
+ flush_sequence();
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
+ ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
+
+ SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
+ check_update_rgn( hwnd, hrgn );
+
+ flush_sequence();
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
+ ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
+
+ flush_sequence();
+ RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
+ ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
+
+ GetClientRect( hwnd, &rect );
+ SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
+ check_update_rgn( hwnd, hrgn );
+
+ flush_sequence();
+ RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
+ ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
+
+ flush_sequence();
+ RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
+ ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
+ check_update_rgn( hwnd, 0 );
+
+ flush_sequence();
+ RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
+ ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
+ check_update_rgn( hwnd, 0 );
+
+ flush_sequence();
+ SetRectRgn( hrgn, 0, 0, 100, 100 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
+ SetRectRgn( hrgn, 0, 0, 50, 100 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
+ SetRectRgn( hrgn, 50, 0, 100, 100 );
+ check_update_rgn( hwnd, hrgn );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
+ ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
+ check_update_rgn( hwnd, 0 );
+
+ flush_sequence();
+ SetRectRgn( hrgn, 0, 0, 100, 100 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
+ SetRectRgn( hrgn, 0, 0, 100, 50 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
+ ok_sequence( WmErase, "Erase", FALSE );
+ SetRectRgn( hrgn, 0, 50, 100, 100 );
+ check_update_rgn( hwnd, hrgn );
+
+ flush_sequence();
+ SetRectRgn( hrgn, 0, 0, 100, 100 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
+ SetRectRgn( hrgn, 0, 0, 50, 50 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
+ ok_sequence( WmPaint, "Paint", FALSE );
+
+ flush_sequence();
+ SetRectRgn( hrgn, -4, -4, -2, -2 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
+ SetRectRgn( hrgn, -200, -200, -198, -198 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
+ ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
+
+ flush_sequence();
+ SetRectRgn( hrgn, -4, -4, -2, -2 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
+ SetRectRgn( hrgn, -4, -4, -3, -3 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
+ SetRectRgn( hrgn, 0, 0, 1, 1 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
+ ok_sequence( WmPaint, "Paint", FALSE );
+
+ flush_sequence();
+ SetRectRgn( hrgn, -4, -4, -1, -1 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
+ RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
+ /* make sure no WM_PAINT was generated */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
+
+ flush_sequence();
+ SetRectRgn( hrgn, -4, -4, -1, -1 );
+ RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
+ {
+ if (msg.hwnd == hwnd && msg.message == WM_PAINT)
+ {
+ /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
+ INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
+ ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
+ ret = GetUpdateRect( hwnd, &rect, FALSE );
+ ok( ret, "Invalid GetUpdateRect result %d\n", ret );
+ /* this will send WM_NCPAINT and validate the non client area */
+ ret = GetUpdateRect( hwnd, &rect, TRUE );
+ ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
+ }
+ DispatchMessage( &msg );
+ }
+ ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
+
+ DestroyWindow( hwnd );
+
+ /* now test with a child window */
+
+ hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok (hparent != 0, "Failed to create parent window\n");
+
+ hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
+ 10, 10, 100, 100, hparent, 0, 0, NULL);
+ ok (hchild != 0, "Failed to create child window\n");
+
+ ShowWindow( hparent, SW_SHOW );
+ UpdateWindow( hparent );
+ UpdateWindow( hchild );
+ /* try to flush pending X expose events */
+ MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+
+ flush_sequence();
+ log_all_parent_messages++;
+
+ SetRect( &rect, 0, 0, 50, 50 );
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
+ ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
+
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ pt.x = pt.y = 0;
+ MapWindowPoints( hchild, hparent, &pt, 1 );
+ SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
+ check_update_rgn( hchild, hrgn );
+ SetRectRgn( hrgn, 0, 0, 50, 50 );
+ check_update_rgn( hparent, hrgn );
+ RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
+ ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
+ RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
+ ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
+
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
+
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
+ RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
+ ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
+ RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
+ ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
+
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
+ RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
+ ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
+
+ SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
+ flush_sequence();
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
+ RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
+ ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
+
+ /* flush all paint messages */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ flush_sequence();
+
+ /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
+ SetRectRgn( hrgn, 0, 0, 50, 50 );
+ check_update_rgn( hparent, hrgn );
+ RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
+ ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
+ SetRectRgn( hrgn, 0, 0, 50, 50 );
+ check_update_rgn( hparent, hrgn );
+
+ /* flush all paint messages */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
+ flush_sequence();
+
+ /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ SetRectRgn( hrgn, 0, 0, 50, 50 );
+ check_update_rgn( hparent, hrgn );
+ RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
+ ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
+ SetRectRgn( hrgn2, 10, 10, 50, 50 );
+ CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
+ check_update_rgn( hparent, hrgn );
+ /* flush all paint messages */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ flush_sequence();
+
+ /* same as above but parent gets completely validated */
+ SetRect( &rect, 20, 20, 30, 30 );
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ SetRectRgn( hrgn, 20, 20, 30, 30 );
+ check_update_rgn( hparent, hrgn );
+ RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
+ ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
+ check_update_rgn( hparent, 0 ); /* no update region */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
+
+ /* make sure RDW_VALIDATE on child doesn't have the same effect */
+ flush_sequence();
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ SetRectRgn( hrgn, 20, 20, 30, 30 );
+ check_update_rgn( hparent, hrgn );
+ RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
+ SetRectRgn( hrgn, 20, 20, 30, 30 );
+ check_update_rgn( hparent, hrgn );
+
+ /* same as above but normal WM_PAINT doesn't validate parent */
+ flush_sequence();
+ SetRect( &rect, 20, 20, 30, 30 );
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ SetRectRgn( hrgn, 20, 20, 30, 30 );
+ check_update_rgn( hparent, hrgn );
+ /* no WM_PAINT in child while parent still pending */
+ while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
+ while (PeekMessage( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
+
+ flush_sequence();
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
+ /* no WM_PAINT in child while parent still pending */
+ while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
+ RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
+ /* now that parent is valid child should get WM_PAINT */
+ while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmEmptySeq, "No other message", FALSE );
+
+ /* same thing with WS_CLIPCHILDREN in parent */
+ flush_sequence();
+ SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
+ ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
+ /* changing style invalidates non client area, but we need to invalidate something else to see it */
+ RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
+ ok_sequence( WmEmptySeq, "No message", FALSE );
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
+ ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
+
+ flush_sequence();
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
+ SetRectRgn( hrgn, 20, 20, 30, 30 );
+ check_update_rgn( hparent, hrgn );
+ /* no WM_PAINT in child while parent still pending */
+ while (PeekMessage( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
+ /* WM_PAINT in parent first */
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
+
+ /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
+ flush_sequence();
+ SetRect( &rect, 0, 0, 30, 30 );
+ RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
+ SetRectRgn( hrgn, 0, 0, 30, 30 );
+ check_update_rgn( hparent, hrgn );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
+
+ /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
+ flush_sequence();
+ SetRect( &rect, -10, 0, 30, 30 );
+ RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
+ SetRect( &rect, 0, 0, 20, 20 );
+ RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
+ RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
+ ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
+
+ /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
+ flush_sequence();
+ SetRect( &rect, -10, 0, 30, 30 );
+ RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
+ SetRect( &rect, 0, 0, 100, 100 );
+ RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
+ RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
+ ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
+ RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
+ ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
+
+ /* test RDW_INTERNALPAINT behavior */
+
+ flush_sequence();
+ RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
+
+ RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
+
+ RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
+
+ SetWindowLong( hparent, GWL_STYLE, GetWindowLong(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
+ ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
+ RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
+ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+ ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
+
+ log_all_parent_messages--;
+ DestroyWindow( hparent );
+ ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
+
+ DeleteObject( hrgn );
+ DeleteObject( hrgn2 );
+}
+
+struct wnd_event
+{
+ HWND hwnd;
+ HANDLE event;
+};
+
+static DWORD WINAPI thread_proc(void *param)
+{
+ MSG msg;
+ struct wnd_event *wnd_event = (struct wnd_event *)param;
+
+ wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
+
+ SetEvent(wnd_event->event);
+
+ while (GetMessage(&msg, 0, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
+
+ return 0;
+}
+
+static void test_interthread_messages(void)
+{
+ HANDLE hThread;
+ DWORD tid;
+ WNDPROC proc;
+ MSG msg;
+ char buf[256];
+ int len, expected_len;
+ struct wnd_event wnd_event;
+ BOOL ret;
+
+ wnd_event.event = CreateEventW(NULL, 0, 0, NULL);
+ if (!wnd_event.event)
+ {
+ trace("skipping interthread message test under win9x\n");
+ return;
+ }
+
+ hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
+ ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
+
+ ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+
+ CloseHandle(wnd_event.event);
+
+ SetLastError(0xdeadbeef);
+ ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
+ ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
+
+ proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
+ ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
+
+ expected_len = lstrlenA("window caption text");
+ memset(buf, 0, sizeof(buf));
+ SetLastError(0xdeadbeef);
+ len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
+ ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
+ ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
+
+ msg.hwnd = wnd_event.hwnd;
+ msg.message = WM_GETTEXT;
+ msg.wParam = sizeof(buf);
+ msg.lParam = (LPARAM)buf;
+ memset(buf, 0, sizeof(buf));
+ SetLastError(0xdeadbeef);
+ len = DispatchMessageA(&msg);
+ ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
+ "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
+
+ /* the following test causes an exception in user.exe under win9x */
+ msg.hwnd = wnd_event.hwnd;
+ msg.message = WM_TIMER;
+ msg.wParam = 0;
+ msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
+ SetLastError(0xdeadbeef);
+ len = DispatchMessageA(&msg);
+ ok(!len && GetLastError() == 0xdeadbeef,
+ "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %ld\n", len, GetLastError());
+
+ ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
+ ok( ret, "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
+
+ ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+ CloseHandle(hThread);
+
+ ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
+}
+
+
+static const struct message WmVkN[] = {
+ { WM_KEYDOWN, wparam|lparam, 'N', 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
+ { WM_CHAR, wparam|lparam, 'n', 1 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
+ { 0 }
+};
+static const struct message WmShiftVkN[] = {
+ { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
+ { WM_KEYDOWN, wparam|lparam, 'N', 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
+ { WM_CHAR, wparam|lparam, 'N', 1 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmCtrlVkN[] = {
+ { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, wparam|lparam, 'N', 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
+ { WM_CHAR, wparam|lparam, 0x000e, 1 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmCtrlVkN_2[] = {
+ { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, wparam|lparam, 'N', 1 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmAltVkN[] = {
+ { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
+ { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
+ { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
+ { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
+ { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
+ { HCBT_SYSCOMMAND, hook },
+ { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
+ { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_INITMENU, sent|defwinproc },
+ { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
+ { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
+ { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_CAPTURECHANGED, sent|defwinproc },
+ { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
+ { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
+ { WM_EXITMENULOOP, sent|defwinproc },
+ { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
+ { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
+ { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
+ { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
+ { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmAltVkN_2[] = {
+ { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
+ { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
+ { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
+ { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmCtrlAltVkN[] = {
+ { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
+ { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
+ { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmCtrlShiftVkN[] = {
+ { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
+ { WM_KEYDOWN, wparam|lparam, 'N', 1 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmCtrlAltShiftVkN[] = {
+ { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
+ { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
+ { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
+ { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
+ { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
+ { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
+ { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
+ { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
+ { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmAltPressRelease[] = {
+ { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
+ { HCBT_SYSCOMMAND, hook },
+ { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
+ { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
+ { WM_INITMENU, sent|defwinproc },
+ { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
+ { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) },
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
+
+ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
+ { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
+ { WM_CAPTURECHANGED, sent|defwinproc },
+ { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
+ { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
+ { WM_EXITMENULOOP, sent|defwinproc },
+ { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { 0 }
+};
+static const struct message WmAltMouseButton[] = {
+ { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+ { WM_MOUSEMOVE, wparam|optional, 0, 0 },
+ { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
+ { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 },
+ { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 },
+ { WM_LBUTTONUP, wparam, 0, 0 },
+ { WM_LBUTTONUP, sent|wparam, 0, 0 },
+ { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
+ { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
+ { 0 }
+};
+
+static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
+{
+ MSG msg;
+
+ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ struct message log_msg;
+
+ trace("accel: %p, %04x, %08x, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam);
+
+ /* ignore some unwanted messages */
+ if (msg.message == WM_MOUSEMOVE ||
+ msg.message == WM_DEVICECHANGE)
+ continue;
+
+ log_msg.message = msg.message;
+ log_msg.flags = wparam|lparam;
+ log_msg.wParam = msg.wParam;
+ log_msg.lParam = msg.lParam;
+ add_message(&log_msg);
+
+ if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+static void test_accelerators(void)
+{
+ RECT rc;
+ SHORT state;
+ HACCEL hAccel;
+ HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ 100, 100, 200, 200, 0, 0, 0, NULL);
+ BOOL ret;
+
+ assert(hwnd != 0);
+ UpdateWindow(hwnd);
+ SetFocus(hwnd);
+ ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
+
+ state = GetKeyState(VK_SHIFT);
+ ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
+ state = GetKeyState(VK_CAPITAL);
+ ok(state == 0, "wrong CapsLock state %04x\n", state);
+
+ hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
+ assert(hAccel != 0);
+
+ pump_msg_loop(hwnd, 0);
+ flush_sequence();
+
+ trace("testing VK_N press/release\n");
+ flush_sequence();
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmVkN, "VK_N press/release", FALSE);
+
+ trace("testing Shift+VK_N press/release\n");
+ flush_sequence();
+ keybd_event(VK_SHIFT, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
+
+ trace("testing Ctrl+VK_N press/release\n");
+ flush_sequence();
+ keybd_event(VK_CONTROL, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
+
+ trace("testing Alt+VK_N press/release\n");
+ flush_sequence();
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
+
+ trace("testing Ctrl+Alt+VK_N press/release 1\n");
+ flush_sequence();
+ keybd_event(VK_CONTROL, 0, 0, 0);
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
+
+ ret = DestroyAcceleratorTable(hAccel);
+ ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
+
+ hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(2));
+ assert(hAccel != 0);
+
+ trace("testing VK_N press/release\n");
+ flush_sequence();
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmVkN, "VK_N press/release", FALSE);
+
+ trace("testing Shift+VK_N press/release\n");
+ flush_sequence();
+ keybd_event(VK_SHIFT, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
+
+ trace("testing Ctrl+VK_N press/release 2\n");
+ flush_sequence();
+ keybd_event(VK_CONTROL, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
+
+ trace("testing Alt+VK_N press/release 2\n");
+ flush_sequence();
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
+
+ trace("testing Ctrl+Alt+VK_N press/release 2\n");
+ flush_sequence();
+ keybd_event(VK_CONTROL, 0, 0, 0);
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
+
+ trace("testing Ctrl+Shift+VK_N press/release\n");
+ flush_sequence();
+ keybd_event(VK_CONTROL, 0, 0, 0);
+ keybd_event(VK_SHIFT, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
+
+ trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
+ flush_sequence();
+ keybd_event(VK_CONTROL, 0, 0, 0);
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event(VK_SHIFT, 0, 0, 0);
+ keybd_event('N', 0, 0, 0);
+ keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, hAccel);
+ ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
+
+ ret = DestroyAcceleratorTable(hAccel);
+ ok( ret, "DestroyAcceleratorTable error %ld\n", GetLastError());
+
+ trace("testing Alt press/release\n");
+ flush_sequence();
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_MENU, 0, 0, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, 0);
+ /* this test doesn't pass in Wine for managed windows */
+ ok_sequence(WmAltPressRelease, "Alt press/release", TRUE);
+
+ trace("testing Alt+MouseButton press/release\n");
+ /* first, move mouse pointer inside of the window client area */
+ GetClientRect(hwnd, &rc);
+ MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
+ rc.left += (rc.right - rc.left)/2;
+ rc.top += (rc.bottom - rc.top)/2;
+ SetCursorPos(rc.left, rc.top);
+
+ pump_msg_loop(hwnd, 0);
+ flush_sequence();
+ keybd_event(VK_MENU, 0, 0, 0);
+ mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
+ mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
+ keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+ pump_msg_loop(hwnd, 0);
+ ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE);
+
+ DestroyWindow(hwnd);
+}
+
+/************* window procedures ********************/
+
+static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ static long beginpaint_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ trace("%p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_ENABLE:
+ {
+ LONG style = GetWindowLongA(hwnd, GWL_STYLE);
+ ok((BOOL)wParam == !(style & WS_DISABLED),
+ "wrong WS_DISABLED state: %d != %d\n", wParam, !(style & WS_DISABLED));
+ break;
+ }
+
+ case WM_CAPTURECHANGED:
+ if (test_DestroyWindow_flag)
+ {
+ DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
+ if (style & WS_CHILD)
+ lParam = GetWindowLongA(hwnd, GWL_ID);
+ else if (style & WS_POPUP)
+ lParam = WND_POPUP_ID;
+ else
+ lParam = WND_PARENT_ID;
+ }
+ break;
+
+ case WM_NCDESTROY:
+ {
+ HWND capture;
+
+ ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
+ capture = GetCapture();
+ if (capture)
+ {
+ ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
+ trace("current capture %p, releasing...\n", capture);
+ ReleaseCapture();
+ }
+ }
+ /* fall through */
+ case WM_DESTROY:
+ if (pGetAncestor)
+ ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
+ if (test_DestroyWindow_flag)
+ {
+ DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
+ if (style & WS_CHILD)
+ lParam = GetWindowLongA(hwnd, GWL_ID);
+ else if (style & WS_POPUP)
+ lParam = WND_POPUP_ID;
+ else
+ lParam = WND_PARENT_ID;
+ }
+ break;
+
+ /* test_accelerators() depends on this */
+ case WM_NCHITTEST:
+ return HTCLIENT;
+
+ /* ignore */
+ case WM_MOUSEMOVE:
+ case WM_SETCURSOR:
+ case WM_DEVICECHANGE:
+ return 0;
+
+ case WM_WINDOWPOSCHANGING:
+ case WM_WINDOWPOSCHANGED:
+ {
+ WINDOWPOS *winpos = (WINDOWPOS *)lParam;
+
+ trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
+ trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+ winpos->hwnd, winpos->hwndInsertAfter,
+ winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
+
+ /* Log only documented flags, win2k uses 0x1000 and 0x2000
+ * in the high word for internal purposes
+ */
+ wParam = winpos->flags & 0xffff;
+ break;
+ }
+ }
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ if (beginpaint_counter) msg.flags |= beginpaint;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+
+ if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
+ {
+ HWND parent = GetParent(hwnd);
+ RECT rc;
+ MINMAXINFO *minmax = (MINMAXINFO *)lParam;
+
+ GetClientRect(parent, &rc);
+ trace("parent %p client size = (%ld x %ld)\n", parent, rc.right, rc.bottom);
+
+ trace("ptReserved = (%ld,%ld)\n"
+ "ptMaxSize = (%ld,%ld)\n"
+ "ptMaxPosition = (%ld,%ld)\n"
+ "ptMinTrackSize = (%ld,%ld)\n"
+ "ptMaxTrackSize = (%ld,%ld)\n",
+ minmax->ptReserved.x, minmax->ptReserved.y,
+ minmax->ptMaxSize.x, minmax->ptMaxSize.y,
+ minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
+ minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
+ minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+
+ ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %ld != %ld\n",
+ minmax->ptMaxSize.x, rc.right);
+ ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %ld != %ld\n",
+ minmax->ptMaxSize.y, rc.bottom);
+ }
+
+ if (message == WM_PAINT)
+ {
+ PAINTSTRUCT ps;
+ beginpaint_counter++;
+ BeginPaint( hwnd, &ps );
+ beginpaint_counter--;
+ EndPaint( hwnd, &ps );
+ return 0;
+ }
+
+ defwndproc_counter++;
+ ret = DefWindowProcA(hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
+static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ trace("popup: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
+
+ msg.message = message;
+ msg.flags = sent|wparam|lparam;
+ if (defwndproc_counter) msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(&msg);
+
+ if (message == WM_CREATE)
+ {
+ DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
+ SetWindowLongA(hwnd, GWL_STYLE, style);
+ }
+
+ defwndproc_counter++;
+ ret = DefWindowProcA(hwnd, message, wParam, lParam);
+ defwndproc_counter--;
+
+ return ret;
+}
+
+static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static long defwndproc_counter = 0;
+ static long beginpaint_counter = 0;
+ LRESULT ret;
+ struct message msg;
+
+ trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam