From 56ec5a6edbff0741af2db42457abeebc3631e832 Mon Sep 17 00:00:00 2001 From: Steven Edwards Date: Tue, 18 Nov 2003 22:24:42 +0000 Subject: [PATCH] Added user32 regression test from Wine. svn path=/trunk/; revision=6694 --- reactos/apps/tests/user32/.cvsignore | 6 + reactos/apps/tests/user32/class.c | 202 +++++ reactos/apps/tests/user32/input.c | 357 ++++++++ reactos/apps/tests/user32/listbox.c | 173 ++++ reactos/apps/tests/user32/makefile | 31 + reactos/apps/tests/user32/msg.c | 484 +++++++++++ reactos/apps/tests/user32/sysparams.c | 1136 +++++++++++++++++++++++++ reactos/apps/tests/user32/testlist.c | 34 + reactos/apps/tests/user32/win.c | 715 ++++++++++++++++ reactos/apps/tests/user32/wsprintf.c | 57 ++ 10 files changed, 3195 insertions(+) create mode 100644 reactos/apps/tests/user32/.cvsignore create mode 100644 reactos/apps/tests/user32/class.c create mode 100644 reactos/apps/tests/user32/input.c create mode 100644 reactos/apps/tests/user32/listbox.c create mode 100644 reactos/apps/tests/user32/makefile create mode 100644 reactos/apps/tests/user32/msg.c create mode 100644 reactos/apps/tests/user32/sysparams.c create mode 100644 reactos/apps/tests/user32/testlist.c create mode 100644 reactos/apps/tests/user32/win.c create mode 100644 reactos/apps/tests/user32/wsprintf.c diff --git a/reactos/apps/tests/user32/.cvsignore b/reactos/apps/tests/user32/.cvsignore new file mode 100644 index 00000000000..d63774a7353 --- /dev/null +++ b/reactos/apps/tests/user32/.cvsignore @@ -0,0 +1,6 @@ +*.o +*.d +*.exe +*.coff +*.sym +*.map diff --git a/reactos/apps/tests/user32/class.c b/reactos/apps/tests/user32/class.c new file mode 100644 index 00000000000..33508b2c9a9 --- /dev/null +++ b/reactos/apps/tests/user32/class.c @@ -0,0 +1,202 @@ +/* Unit test suite for window classes. + * + * Copyright 2002 Mike McCormack + * + * 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 +#include +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wingdi.h" +#include "winuser.h" + +#define NUMCLASSWORDS 4 + +LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProcW (hWnd, msg, wParam, lParam); +} + +/*********************************************************************** + * + * WinMain + */ +void ClassTest(HINSTANCE hInstance, BOOL global) +{ + WNDCLASSW cls, wc; + WCHAR className[] = {'T','e','s','t','C','l','a','s','s',0}; + WCHAR winName[] = {'W','i','n','C','l','a','s','s','T','e','s','t',0}; + ATOM test_atom; + HWND hTestWnd; + DWORD i; + WCHAR str[20]; + ATOM classatom; + + cls.style = CS_HREDRAW | CS_VREDRAW | (global?CS_GLOBALCLASS:0); + cls.lpfnWndProc = ClassTest_WndProc; + cls.cbClsExtra = NUMCLASSWORDS*sizeof(DWORD); + cls.cbWndExtra = 12; + cls.hInstance = hInstance; + cls.hIcon = LoadIconW (0, (LPWSTR)IDI_APPLICATION); + cls.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject (WHITE_BRUSH); + cls.lpszMenuName = 0; + cls.lpszClassName = className; + + classatom=RegisterClassW(&cls); + if (!classatom && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + return; + ok(classatom, "failed to register class"); + + ok(!RegisterClassW (&cls), + "RegisterClass of the same class should fail for the second time"); + +#if 0 + /* these succeeds on Wine, but shouldn't cause any trouble ... */ + ok(!GlobalFindAtomW(className), + "Found class as global atom"); + + ok(!FindAtomW(className), + "Found class as global atom"); +#endif + + /* Setup windows */ + hTestWnd = CreateWindowW (className, winName, + WS_OVERLAPPEDWINDOW + WS_HSCROLL + WS_VSCROLL, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, + 0, hInstance, 0); + + ok(hTestWnd!=0, "Failed to create window"); + + /* test initial values of valid classwords */ + for(i=0; i-X can be accompished by + * the sequence ALT-KEY-DOWN, X-KEY-DOWN, ALT-KEY-UP, X-KEY-UP + * but also X-KEY-DOWN, ALT-KEY-DOWN, X-KEY-UP, ALT-KEY-UP + * Whether a KEY or a SYSKEY message is sent is not always clear, it is + * also not the same in WINNT as in WIN9X */ + +/* NOTE that there will be test failures under WIN9X + * No applications are known to me that rely on this + * so I don't fix it */ + +/* TODO: + * 1. extend it to the wm_command and wm_syscommand notifications + * 2. add some more tests with special cases like dead keys or right (alt) key + * 3. there is some adapted code from input.c in here. Should really + * make that code exactly the same. + * 4. resolve the win9x case when there is a need or the testing frame work + * offers a nice way. + * 5. The test app creates a window, the user should not take the focus + * away during its short existence. I could do something to prevent that + * if it is a problem. + * + */ + +/* for definitions of INPUT */ +#define _WIN32_WINNT 0x401 + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "wine/test.h" + +#include "winbase.h" +#include "winuser.h" + +typedef struct tagINPUT +{ + DWORD type; + union + { + MOUSEINPUT mi; + KEYBDINPUT ki; + HARDWAREINPUT hi; + } DUMMYUNIONNAME; +} INPUT, *PINPUT, *LPINPUT; + +#include + +/* globals */ +HWND hWndTest; +long timetag = 0x10000000; + +#define MAXKEYEVENTS 6 +#define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one + and only one message */ + +/* keyboard message names, sorted as their value */ +static const char *MSGNAME[]={"WM_KEYDOWN", "WM_KEYUP", "WM_CHAR","WM_DEADCHAR", + "WM_SYSKEYDOWN", "WM_SYSKEYUP", "WM_SYSCHAR", "WM_SYSDEADCHAR" ,"WM_KEYLAST"}; + +/* keyevents, add more as needed */ +typedef enum KEVtag +{ ALTDOWN = 1, ALTUP, XDOWN, XUP, SHIFTDOWN, SHIFTUP, CTRLDOWN, CTRLUP } KEV; +/* matching VK's */ +int GETVKEY[]={0, VK_MENU, VK_MENU, 'X', 'X', VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL}; +/* matching scan codes */ +int GETSCAN[]={0, 0x38, 0x38, 0x2D, 0x2D, 0x2A, 0x2A, 0x1D, 0x1D }; +/* matching updown events */ +int GETUPDOWN[]={0, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP, 0, KEYEVENTF_KEYUP}; +/* matching descripts */ +char *getdesc[]={"", "+alt","-alt","+X","-X","+shift","-shift","+ctrl","-ctrl"}; + +#define ADDTOINPUTS(kev) \ +inputs[evtctr].type = INPUT_KEYBOARD; \ + inputs[evtctr].u.ki.wVk = GETVKEY[ kev]; \ + inputs[evtctr].u.ki.wScan = GETSCAN[ kev]; \ + inputs[evtctr].u.ki.dwFlags = GETUPDOWN[ kev]; \ + inputs[evtctr].u.ki.dwExtraInfo = 0; \ + inputs[evtctr].u.ki.time = ++timetag; \ + if( kev) evtctr++; + +typedef struct { + UINT message; + WPARAM wParam; + LPARAM lParam; +} KMSG; + +/******************************************* + * add new test sets here + * the software will make all combinations of the + * keyevent defined here + */ +struct { int nrkev; + KEV keydwn[MAXKEYEVENTS]; + KEV keyup[MAXKEYEVENTS]; +} testkeyset[]= { + { 2, { ALTDOWN, XDOWN }, { ALTUP, XUP}}, + { 3, { ALTDOWN, XDOWN , SHIFTDOWN}, { ALTUP, XUP, SHIFTUP}}, + { 3, { ALTDOWN, XDOWN , CTRLDOWN}, { ALTUP, XUP, CTRLUP}}, + { 3, { SHIFTDOWN, XDOWN , CTRLDOWN}, { SHIFTUP, XUP, CTRLUP}}, + { 0 } /* mark the end */ +}; + +/**********************adapted from input.c **********************************/ + +BYTE InputKeyStateTable[256]; +BYTE AsyncKeyStateTable[256]; +BYTE TrackSysKey = 0; /* determine whether ALT key up will cause a WM_SYSKEYUP + or a WM_KEYUP message */ +typedef union +{ + struct + { + unsigned long count : 16; + unsigned long code : 8; + unsigned long extended : 1; + unsigned long unused : 2; + unsigned long win_internal : 2; + unsigned long context : 1; + unsigned long previous : 1; + unsigned long transition : 1; + } lp1; + unsigned long lp2; +} KEYLP; + +int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) +{ + UINT message; + int VKey = GETVKEY[kev]; + KEYLP keylp; + + keylp.lp2 = 0; + + keylp.lp1.count = 1; + keylp.lp1.code = GETSCAN[kev]; + keylp.lp1.extended = 0 ;/* FIXME (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) != 0; */ + keylp.lp1.win_internal = 0; + + if (GETUPDOWN[kev] & KEYEVENTF_KEYUP ) + { + message = WM_KEYUP; + if( (InputKeyStateTable[VK_MENU] & 0x80) && ( + (VKey == VK_MENU) || (VKey == VK_CONTROL) || + !(InputKeyStateTable[VK_CONTROL] & 0x80))) { + if( TrackSysKey == VK_MENU || /* -down/-up sequence */ + (VKey != VK_MENU)) /* -down...-up */ + message = WM_SYSKEYUP; + TrackSysKey = 0; + } + InputKeyStateTable[VKey] &= ~0x80; + keylp.lp1.previous = 1; + keylp.lp1.transition = 1; + } + else + { + keylp.lp1.previous = (InputKeyStateTable[VKey] & 0x80) != 0; + keylp.lp1.transition = 0; + if (!(InputKeyStateTable[VKey] & 0x80)) InputKeyStateTable[VKey] ^= 0x01; + InputKeyStateTable[VKey] |= 0x80; + AsyncKeyStateTable[VKey] |= 0x80; + + message = WM_KEYDOWN; + if( (InputKeyStateTable[VK_MENU] & 0x80) && + !(InputKeyStateTable[VK_CONTROL] & 0x80)) { + message = WM_SYSKEYDOWN; + TrackSysKey = VKey; + } + } + + keylp.lp1.context = (InputKeyStateTable[VK_MENU] & 0x80) != 0; /* 1 if alt */ + + if( plParam) *plParam = keylp.lp2; + if( pwParam) *pwParam = VKey; + return message; +} + +/****************************** end copy input.c ****************************/ + +/* + * . prepare the keyevents for SendInputs + * . calculate the "expected" messages + * . Send the events to our window + * . retrieve the messages from the input queue + * . verify + */ +void do_test( HWND hwnd, int seqnr, KEV td[] ) +{ + INPUT inputs[MAXKEYEVENTS]; + KMSG expmsg[MAXKEYEVENTS]; + MSG msg; + char buf[100]; + int evtctr=0, kmctr, i; + buf[0]='\0'; + TrackSysKey=0; /* see input.c */ + for( i = 0; i < MAXKEYEVENTS; i++) { + ADDTOINPUTS(td[i]) + strcat(buf, getdesc[td[i]]); + if(td[i]) + expmsg[i].message = KbdMessage(td[i], &(expmsg[i].wParam), &(expmsg[i].lParam)); /* see queue_kbd_event() */ + else + expmsg[i].message = 0; + } + for( kmctr = 0; kmctr < MAXKEYEVENTS && expmsg[kmctr].message; kmctr++) + ; + assert( evtctr <= MAXKEYEVENTS ); + assert( evtctr == SendInput(evtctr, &inputs[0], sizeof(INPUT))); + i = 0; + trace("======== key stroke sequence #%d: %s =============\n", + seqnr + 1, buf); + while( PeekMessage(&msg,hwnd,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) ) { + trace("message[%d] %-15s wParam %04x lParam %08lx time %lx\n", i, + MSGNAME[msg.message - WM_KEYFIRST], msg.wParam, msg.lParam, msg.time); + if( i < kmctr ) { + ok( msg.message == expmsg[i].message && + msg.wParam == expmsg[i].wParam && + msg.lParam == expmsg[i].lParam, + "wrong message! expected:\n" + "message[%d] %-15s wParam %04x lParam %08lx",i, + MSGNAME[(expmsg[i]).message - WM_KEYFIRST], + expmsg[i].wParam, expmsg[i].lParam ); + } + i++; + } + trace("%d messages retrieved\n", i); + ok( i == kmctr, "message count is wrong: got %d expected: %d", i, kmctr); +} + +/* test all combinations of the specified key events */ +void TestASet( HWND hWnd, int nrkev, KEV kevdwn[], KEV kevup[] ) +{ + int i,j,k,l,m,n; + static int count=0; + KEV kbuf[MAXKEYEVENTS]; + assert( nrkev==2 || nrkev==3); + for(i=0;i +#include + +#include "wine/test.h" + +#ifdef VISIBLE +#define WAIT Sleep (1000) +#define REDRAW RedrawWindow (handle, NULL, 0, RDW_UPDATENOW) +#else +#define WAIT +#define REDRAW +#endif + +HWND +create_listbox (DWORD add_style) +{ + HWND handle=CreateWindow ("LISTBOX", "TestList", + (LBS_STANDARD & ~LBS_SORT) | add_style, + 0, 0, 100, 100, + NULL, NULL, NULL, 0); + + assert (handle); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "First added"); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Second added"); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Third added"); + +#ifdef VISIBLE + ShowWindow (handle, SW_SHOW); +#endif + REDRAW; + + return handle; +} + +struct listbox_prop { + DWORD add_style; +}; + +struct listbox_stat { + int selected, anchor, caret, selcount; +}; + +struct listbox_test { + struct listbox_prop prop; + struct listbox_stat init, init_todo; + struct listbox_stat click, click_todo; + struct listbox_stat step, step_todo; +}; + +void +listbox_query (HWND handle, struct listbox_stat *results) +{ + results->selected = SendMessage (handle, LB_GETCURSEL, 0, 0); + results->anchor = SendMessage (handle, LB_GETANCHORINDEX, 0, 0); + results->caret = SendMessage (handle, LB_GETCARETINDEX, 0, 0); + results->selcount = SendMessage (handle, LB_GETSELCOUNT, 0, 0); +} + +void +buttonpress (HWND handle, WORD x, WORD y) +{ + LPARAM lp=x+(y<<16); + + WAIT; + SendMessage (handle, WM_LBUTTONDOWN, (WPARAM) MK_LBUTTON, lp); + SendMessage (handle, WM_LBUTTONUP , (WPARAM) 0 , lp); + REDRAW; +} + +void +keypress (HWND handle, WPARAM keycode, BYTE scancode, BOOL extended) +{ + LPARAM lp=1+(scancode<<16)+(extended?KEYEVENTF_EXTENDEDKEY:0); + + WAIT; + SendMessage (handle, WM_KEYDOWN, keycode, lp); + SendMessage (handle, WM_KEYUP , keycode, lp | 0xc000000); + REDRAW; +} + +#define listbox_field_ok(t, s, f, got) \ + ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \ + ": expected %d, got %d", (unsigned int)t.prop.add_style, \ + t.s.f, got.f) + +#define listbox_todo_field_ok(t, s, f, got) \ + if (t.s##_todo.f) todo_wine { listbox_field_ok(t, s, f, got); } \ + else listbox_field_ok(t, s, f, got) + +#define listbox_ok(t, s, got) \ + listbox_todo_field_ok(t, s, selected, got); \ + listbox_todo_field_ok(t, s, anchor, got); \ + listbox_todo_field_ok(t, s, caret, got); \ + listbox_todo_field_ok(t, s, selcount, got) + +void +check (const struct listbox_test test) +{ + struct listbox_stat answer; + HWND hLB=create_listbox (test.prop.add_style); + RECT second_item; + + listbox_query (hLB, &answer); + listbox_ok (test, init, answer); + + SendMessage (hLB, LB_GETITEMRECT, (WPARAM) 1, (LPARAM) &second_item); + buttonpress(hLB, (WORD)second_item.left, (WORD)second_item.top); + + listbox_query (hLB, &answer); + listbox_ok (test, click, answer); + + keypress (hLB, VK_DOWN, 0x50, TRUE); + + listbox_query (hLB, &answer); + listbox_ok (test, step, answer); + + WAIT; + DestroyWindow (hLB); +} + +START_TEST(listbox) +{ + const struct listbox_test SS = +/* {add_style} */ + {{0}, + {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + { 1, 1, 1, LB_ERR}, {0,1,0,0}, + { 2, 2, 2, LB_ERR}, {0,1,0,0}}; +/* {selected, anchor, caret, selcount}{TODO fields} */ + const struct listbox_test SS_NS = + {{LBS_NOSEL}, + {LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}, + { 1, 1, 1, LB_ERR}, {1,1,0,0}, + { 2, 2, 2, LB_ERR}, {1,1,1,0}}; + const struct listbox_test MS = + {{LBS_MULTIPLESEL}, + { 0, LB_ERR, 0, 0}, {0,0,0,0}, + { 1, 1, 1, 1}, {0,1,0,0}, + { 2, 1, 2, 1}, {0,1,0,1}}; + const struct listbox_test MS_NS = + {{LBS_MULTIPLESEL | LBS_NOSEL}, + {LB_ERR, LB_ERR, 0, LB_ERR}, {1,0,0,1}, + { 1, 1, 1, LB_ERR}, {0,1,0,1}, + { 2, 2, 2, LB_ERR}, {0,1,0,1}}; + + trace (" Testing single selection...\n"); + check (SS); + trace (" ... with NOSEL\n"); + check (SS_NS); + trace (" Testing multiple selection...\n"); + check (MS); + trace (" ... with NOSEL\n"); + check (MS_NS); +} diff --git a/reactos/apps/tests/user32/makefile b/reactos/apps/tests/user32/makefile new file mode 100644 index 00000000000..41d2e2add43 --- /dev/null +++ b/reactos/apps/tests/user32/makefile @@ -0,0 +1,31 @@ +# $Id: makefile,v 1.1 2003/11/18 22:24:42 sedwards Exp $ + +PATH_TO_TOP = ../../.. + +TARGET_NORC = yes + +TARGET_TYPE = program + +TARGET_APPTYPE = console + +# require os code to explicitly request A/W version of structs/functions +TARGET_CFLAGS += -D_DISABLE_TIDENTS -D__USE_W32API + +TARGET_NAME = user32_test + +TARGET_SDKLIBS = gdi32.a user32.a + +TARGET_OBJECTS = \ + testlist.o \ + class.o \ + listbox.o \ + msg.o \ + sysparams.o \ + win.o \ + wsprintf.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF diff --git a/reactos/apps/tests/user32/msg.c b/reactos/apps/tests/user32/msg.c new file mode 100644 index 00000000000..775ce9819ec --- /dev/null +++ b/reactos/apps/tests/user32/msg.c @@ -0,0 +1,484 @@ +/* + * Unit tests for window message handling + * + * Copyright 1999 Ove Kaaven + * Copyright 2003 Dimitrie O. Paun + * + * 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 +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" + +#include "wine/test.h" + + +/* +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 +} msg_flags_t; + +struct message { + UINT message; /* the WM_* code */ + msg_flags_t flags; /* message props */ + WPARAM wParam; /* expacted value of wParam */ + LPARAM lParam; /* expacted value of lParam */ +}; + +/* CreateWindow (for overlapped window, not initially visible) (16/32) */ +static struct message WmCreateOverlappedSeq[] = { + { WM_GETMINMAXINFO, sent }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { 0 } +}; +/* ShowWindow (for overlapped window) (16/32) */ +static struct message WmShowOverlappedSeq[] = { + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent|wparam, /*FIXME: SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW*/ 0 }, + /* FIXME: WM_QUERYNEWPALETTE, if in 256-color mode */ + { WM_WINDOWPOSCHANGING, sent|wparam, /*FIXME: SWP_NOMOVE|SWP_NOSIZE*/ 0 }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ACTIVATE, sent|wparam, 1 }, + { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_NCPAINT, sent|wparam, 1 }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW }, + { WM_SIZE, sent }, + { WM_MOVE, sent }, + { 0 } +}; + +/* DestroyWindow (for overlapped window) (32) */ +static struct message WmDestroyOverlappedSeq[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGED, sent|wparam, 0 }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATEAPP, sent|wparam, 0 }, + { WM_KILLFOCUS, sent|wparam, 0 }, + { WM_DESTROY, sent }, + { WM_NCDESTROY, sent }, + { 0 } +}; +/* CreateWindow (for child window, not initially visible) */ +static struct message WmCreateChildSeq[] = { + { WM_NCCREATE, sent }, + /* child is inserted into parent's child list after WM_NCCREATE returns */ + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { WM_SIZE, sent }, + { WM_MOVE, sent }, + { WM_PARENTNOTIFY, sent|parent|wparam, 1 }, + { 0 } +}; +/* ShowWindow (for child window) */ +static struct message WmShowChildSeq[] = { + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_ERASEBKGND, sent|parent }, + { WM_WINDOWPOSCHANGED, sent|wparam, 0 }, + { 0 } +}; +/* DestroyWindow (for child window) */ +static struct message WmDestroyChildSeq[] = { + { WM_PARENTNOTIFY, sent|parent|wparam, 2 }, + { WM_SHOWWINDOW, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_ERASEBKGND, sent|parent }, + { WM_WINDOWPOSCHANGED, sent|wparam, 0 }, + { WM_DESTROY, sent }, + { WM_NCDESTROY, sent }, + { 0 } +}; +/* Moving the mouse in nonclient area */ +static struct message WmMouseMoveInNonClientAreaSeq[] = { /* FIXME: add */ + { WM_NCHITTEST, sent }, + { WM_SETCURSOR, sent }, + { WM_NCMOUSEMOVE, posted }, + { 0 } +}; +/* Moving the mouse in client area */ +static 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 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|defwinproc }, + { WM_WINDOWPOSCHANGED, sent|defwinproc }, + { WM_MOVE, sent|defwinproc }, + { WM_EXITSIZEMOVE, sent|defwinproc }, + { 0 } +}; +/* Sizing by dragging the thick borders (after WM_NCHITTEST and WM_SETCURSOR) (outline move) */ +static struct message WmDragThinkBordersBarSeq[] = { /* 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|defwinproc }, + { 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|defwinproc }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { WM_EXITSIZEMOVE, sent|defwinproc }, + { 0 } +}; +/* Resizing child window with MoveWindow (32) */ +static struct message WmResizingChildWithMoveWindowSeq[] = { + { WM_WINDOWPOSCHANGING, sent }, + { WM_NCCALCSIZE, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc }, + { 0 } +}; +/* Clicking on inactive button */ +static 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 struct message WmReparentButtonSeq[] = { /* FIXME: add */ + { WM_SHOWWINDOW, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER }, + { 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 modal dialog (32) */ +static struct message WmCreateModalDialogSeq[] = { /* FIXME: add */ + { WM_CANCELMODE, sent|parent }, + { WM_KILLFOCUS, sent|parent }, + { WM_ENABLE, sent|parent|wparam, 0 }, + /* (window proc creation messages not tracked yet, because...) */ + { WM_SETFONT, sent }, + { WM_INITDIALOG, sent }, + /* (...the window proc message hook was installed here, IsVisible still FALSE) */ + { WM_NCACTIVATE, sent|parent|wparam, 0 }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ACTIVATE, sent|parent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_WINDOWPOSCHANGING, sent|parent }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_ACTIVATE, sent|wparam, 1 }, + /* (setting focus) */ + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ERASEBKGND, sent }, + { WM_CTLCOLORDLG, sent|defwinproc }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_PAINT, sent }, + /* FIXME: (bunch of WM_CTLCOLOR* for each control) */ + { WM_PAINT, sent|parent }, + { WM_ENTERIDLE, sent|parent|wparam, 0}, + { WM_SETCURSOR, sent|parent }, + { 0 } +}; +/* Destruction of a modal dialog (32) */ +static struct message WmDestroyModalDialogSeq[] = { /* FIXME: add */ + /* (inside dialog proc: EndDialog is called) */ + { WM_ENABLE, sent|parent|wparam, 1 }, + { WM_SETFOCUS, sent }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_NCPAINT, sent|parent }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ERASEBKGND, sent|parent }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATE, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_WINDOWPOSCHANGING, sent|parent }, + { WM_NCACTIVATE, sent|parent|wparam, 1 }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ACTIVATE, sent|parent|wparam, 1 }, + { WM_KILLFOCUS, sent }, + { WM_SETFOCUS, sent|parent }, + { WM_DESTROY, sent }, + { WM_NCDESTROY, sent }, + { 0 } +}; +/* Creation of a modal dialog that is resized inside WM_INITDIALOG (32) */ +static struct message WmCreateModalDialogResizeSeq[] = { /* FIXME: add */ + /* (inside dialog proc, handling WM_INITDIALOG) */ + { WM_WINDOWPOSCHANGING, sent }, + { WM_NCCALCSIZE, sent }, + { WM_NCACTIVATE, sent|parent|wparam, 0 }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ACTIVATE, sent|parent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_WINDOWPOSCHANGING, sent|parent }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_ACTIVATE, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_SIZE, sent|defwinproc }, + /* (setting focus) */ + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_NCPAINT, sent }, + { WM_GETTEXT, sent|defwinproc }, + { WM_ERASEBKGND, sent }, + { WM_CTLCOLORDLG, sent|defwinproc }, + { WM_WINDOWPOSCHANGED, sent }, + { 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 } +}; + +static int sequence_cnt, sequence_size; +static struct message* sequence; + +static void add_message(struct message msg) +{ + if (!sequence) + sequence = malloc ( (sequence_size = 10) * sizeof (struct message) ); + if (sequence_cnt == sequence_size) + sequence = realloc ( sequence, (sequence_size *= 2) * sizeof (struct message) ); + assert(sequence); + sequence[sequence_cnt++] = msg; +} + +static void flush_sequence() +{ + free(sequence); + sequence = 0; + sequence_cnt = sequence_size = 0; +} + +static void ok_sequence(struct message *expected, const char *context) +{ + static struct message end_of_sequence = { 0, 0, 0, 0 }; + struct message *actual = sequence; + + add_message(end_of_sequence); + + /* naive sequence comparison. Would be nice to use a regexp engine here */ + while (expected->message || actual->message) + { + if (expected->message == actual->message) + { + if (expected->flags & wparam) + ok (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 (expected->lParam == actual->lParam, + "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + context, expected->message, expected->lParam, actual->lParam); + /* FIXME: should we check defwinproc? */ + ok ((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 ((expected->flags & parent) == (actual->flags & parent), + "%s: the msg 0x%04x was expected in %s\n", + context, expected->message, (expected->flags & parent) ? "parent" : "child"); + expected++; + actual++; + } + else if (expected->message && ((expected + 1)->message == actual->message) ) + { + todo_wine { + ok (FALSE, "%s: the msg 0x%04x was not received\n", context, expected->message); + expected++; + } + } + else if (actual->message && (expected->message == (actual + 1)->message) ) + { + todo_wine { + ok (FALSE, "%s: the msg 0x%04x was not expected\n", context, actual->message); + actual++; + } + } + else + { + todo_wine { + ok (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + context, expected->message, actual->message); + expected++; + actual++; + } + } + } + + flush_sequence(); +} + +/* test if we receive the right sequence of messages */ +static void test_messages(void) +{ + HWND hwnd, hparent, hchild; + HWND hchild2, hbutton; + + 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"); + + ShowWindow(hwnd, TRUE); + ok_sequence(WmShowOverlappedSeq, "ShowWindow:overlapped"); + + DestroyWindow(hwnd); + ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped"); + + 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"); + flush_sequence(); + + hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILDWINDOW, + 0, 0, 10, 10, hparent, 0, 0, NULL); + ok (hchild != 0, "Failed to create child window\n"); + ok_sequence(WmCreateChildSeq, "CreateWindow:child"); + + hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILDWINDOW, + 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_CHILDWINDOW, + 0, 100, 50, 50, hchild, 0, 0, NULL); + ok (hbutton != 0, "Failed to create button window\n"); + flush_sequence(); + + ShowWindow(hchild, TRUE); + ok_sequence(WmShowChildSeq, "ShowWindow:child"); + + MoveWindow(hchild, 10, 10, 20, 20, TRUE); + ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child"); + + DestroyWindow(hchild); + ok_sequence(WmDestroyChildSeq, "DestroyWindow:child"); +} + +static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + struct message msg = { message, sent|wparam|lparam, wParam, lParam }; + + add_message(msg); + return DefWindowProcA(hwnd, message, wParam, lParam); +} + +static BOOL RegisterWindowClasses(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = MsgCheckProcA; + 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 = "TestWindowClass"; + + if(!RegisterClassA(&cls)) return FALSE; + + cls.style = 0; + cls.lpfnWndProc = DefWindowProcA; + 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 = "TestParentClass"; + + if(!RegisterClassA(&cls)) return FALSE; + + cls.style = 0; + cls.lpfnWndProc = DefWindowProcA; + 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 = "SimpleWindowClass"; + + if(!RegisterClassA(&cls)) return FALSE; + + return TRUE; +} + +START_TEST(msg) +{ + if (!RegisterWindowClasses()) assert(0); + + test_messages(); +} diff --git a/reactos/apps/tests/user32/sysparams.c b/reactos/apps/tests/user32/sysparams.c new file mode 100644 index 00000000000..d68f57cb983 --- /dev/null +++ b/reactos/apps/tests/user32/sysparams.c @@ -0,0 +1,1136 @@ +/* Unit test suite for functions SystemParametersInfo and GetSystemMetrics. + * + * Copyright 2002 Andriy Palamarchuk + * + * 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 +#include +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winuser.h" + +#ifndef SPI_GETDESKWALLPAPER +# define SPI_GETDESKWALLPAPER 0x0073 +#endif + +static int strict; + +#define eq(received, expected, label, type) \ + ok((received) == (expected), "%s: got " type " instead of " type "\n", (label),(received),(expected)) + + +#define SPI_SETBEEP_REGKEY "Control Panel\\Sound" +#define SPI_SETBEEP_VALNAME "Beep" +#define SPI_SETMOUSE_REGKEY "Control Panel\\Mouse" +#define SPI_SETMOUSE_VALNAME1 "MouseThreshold1" +#define SPI_SETMOUSE_VALNAME2 "MouseThreshold2" +#define SPI_SETMOUSE_VALNAME3 "MouseSpeed" +#define SPI_SETBORDER_REGKEY "Control Panel\\Desktop\\WindowMetrics" +#define SPI_SETBORDER_VALNAME "BorderWidth" +#define SPI_SETKEYBOARDSPEED_REGKEY "Control Panel\\Keyboard" +#define SPI_SETKEYBOARDSPEED_VALNAME "KeyboardSpeed" +#define SPI_SETSCREENSAVETIMEOUT_REGKEY "Control Panel\\Desktop" +#define SPI_SETSCREENSAVETIMEOUT_VALNAME "ScreenSaveTimeOut" +#define SPI_SETSCREENSAVEACTIVE_REGKEY "Control Panel\\Desktop" +#define SPI_SETSCREENSAVEACTIVE_VALNAME "ScreenSaveActive" +#define SPI_SETGRIDGRANULARITY_REGKEY "Control Panel\\Desktop" +#define SPI_SETGRIDGRANULARITY_VALNAME "GridGranularity" +#define SPI_SETKEYBOARDDELAY_REGKEY "Control Panel\\Keyboard" +#define SPI_SETKEYBOARDDELAY_VALNAME "KeyboardDelay" +#define SPI_SETICONTITLEWRAP_REGKEY1 "Control Panel\\Desktop\\WindowMetrics" +#define SPI_SETICONTITLEWRAP_REGKEY2 "Control Panel\\Desktop" +#define SPI_SETICONTITLEWRAP_VALNAME "IconTitleWrap" +#define SPI_SETMENUDROPALIGNMENT_REGKEY1 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows" +#define SPI_SETMENUDROPALIGNMENT_REGKEY2 "Control Panel\\Desktop" +#define SPI_SETMENUDROPALIGNMENT_VALNAME "MenuDropAlignment" +#define SPI_SETDOUBLECLKWIDTH_REGKEY1 "Control Panel\\Mouse" +#define SPI_SETDOUBLECLKWIDTH_REGKEY2 "Control Panel\\Desktop" +#define SPI_SETDOUBLECLKWIDTH_VALNAME "DoubleClickWidth" +#define SPI_SETDOUBLECLKHEIGHT_REGKEY1 "Control Panel\\Mouse" +#define SPI_SETDOUBLECLKHEIGHT_REGKEY2 "Control Panel\\Desktop" +#define SPI_SETDOUBLECLKHEIGHT_VALNAME "DoubleClickHeight" +#define SPI_SETDOUBLECLICKTIME_REGKEY "Control Panel\\Mouse" +#define SPI_SETDOUBLECLICKTIME_VALNAME "DoubleClickSpeed" +#define SPI_SETMOUSEBUTTONSWAP_REGKEY "Control Panel\\Mouse" +#define SPI_SETMOUSEBUTTONSWAP_VALNAME "SwapMouseButtons" +#define SPI_SETWORKAREA_REGKEY "Control Panel\\Desktop" +#define SPI_SETWORKAREA_VALNAME "WINE_WorkArea" +#define SPI_SETSHOWSOUNDS_REGKEY "Control Panel\\Accessibility\\ShowSounds" +#define SPI_SETSHOWSOUNDS_VALNAME "On" +#define SPI_SETDRAGFULLWINDOWS_REGKEY "Control Panel\\Desktop" +#define SPI_SETDRAGFULLWINDOWS_VALNAME "DragFullWindows" +#define SPI_SETDESKWALLPAPER_REGKEY "Control Panel\\Desktop" +#define SPI_SETDESKWALLPAPER_VALNAME "Wallpaper" +/* FIXME - don't have access to Windows with this action (W95, NT5.0). Set real values */ +#define SPI_SETKEYBOARDPREF_REGKEY "Control Panel\\Desktop" +#define SPI_SETKEYBOARDPREF_VALNAME "WINE_WorkArea" +#define SPI_SETSCREENREADER_REGKEY "Control Panel\\Desktop" +#define SPI_SETSCREENREADER_VALNAME "???" + +/* volatile registry branch under CURRENT_USER_REGKEY for temporary values storage */ +#define WINE_CURRENT_USER_REGKEY "Wine" + +static HWND ghTestWnd; + +static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam ); +static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam ); +static int change_counter; +static int change_last_param; + +static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + switch (msg) { + + case WM_SETTINGCHANGE: + if (change_counter>0) { + ok(0,"too many changes counter=%d last change=%d\n", + change_counter,change_last_param); + } + change_counter++; + change_last_param = wParam; + break; + + case WM_DESTROY: + PostQuitMessage( 0 ); + break; + + default: + return( DefWindowProcA( hWnd, msg, wParam, lParam ) ); + } + + return 0; +} + +/* +Performs testing for system parameters messages +params: + - system parameter id + - supposed value of the registry key +*/ +static void test_change_message( int action, int optional ) +{ + if (change_counter==0 && optional==1) + return; + ok( 1 == change_counter, + "Missed a message: change_counter=%d", change_counter ); + change_counter = 0; + ok( action == change_last_param, + "Wrong action got %d expected %d", change_last_param, action ); + change_last_param = 0; +} + +/* + * Tests the HKEY_CURRENT_USER subkey value. + * The value should contain string value. + * + * Params: + * lpsSubKey - subkey name + * lpsRegName - registry entry name + * lpsTestValue - value to test + */ +static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName, LPCSTR testValue ) +{ + CHAR value[MAX_PATH]; + DWORD valueLen; + DWORD type; + HKEY hKey; + LONG rc; + int found=0; + + *value='\0'; + valueLen=sizeof(value); + RegOpenKeyA( HKEY_CURRENT_USER, subKey1, &hKey ); + rc=RegQueryValueExA( hKey, valName, NULL, &type, value, &valueLen ); + RegCloseKey( hKey ); + if (rc==ERROR_SUCCESS) + { + ok( !strcmp( testValue, value ), + "Wrong value in registry: subKey=%s, valName=%s, testValue=%s, value=%s", + subKey1, valName, testValue, value ); + found++; + } + else if (strict) + { + ok(0,"Missing registry entry: subKey=%s, valName=%s", + subKey1, valName); + } + if (subKey2 && !strict) + { + *value='\0'; + valueLen=sizeof(value); + RegOpenKeyA( HKEY_CURRENT_USER, subKey2, &hKey ); + rc=RegQueryValueExA( hKey, valName, NULL, &type, value, &valueLen ); + RegCloseKey( hKey ); + if (rc==ERROR_SUCCESS) + { + ok( !strcmp( testValue, value ), + "Wrong value in registry: subKey=%s, valName=%s, testValue=%s, value=%s", + subKey2, valName, testValue, value ); + found++; + } + } + ok(found,"Missing registry entry: %s in %s or %s", + valName, subKey1, (subKey2?subKey2:"") ); +} + +#define test_reg_key( subKey, valName, testValue ) \ + _test_reg_key( subKey, NULL, valName, testValue ) +#define test_reg_key_ex( subKey1, subKey2, valName, testValue ) \ + _test_reg_key( subKey1, subKey2, valName, testValue ) + +static void test_SPI_SETBEEP( void ) /* 2 */ +{ + BOOL rc; + BOOL old_b; + BOOL b; + BOOL curr_val; + + trace("testing SPI_{GET,SET}BEEP\n"); + rc=SystemParametersInfoA( SPI_GETBEEP, 0, &old_b, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + + curr_val = TRUE; + rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + test_change_message( SPI_SETBEEP, 0 ); + test_reg_key( SPI_SETBEEP_REGKEY, + SPI_SETBEEP_VALNAME, + curr_val ? "Yes" : "No" ); + rc=SystemParametersInfoA( SPI_GETBEEP, 0, &b, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( b, curr_val, "SPI_{GET,SET}BEEP", "%d" ); + rc=SystemParametersInfoW( SPI_GETBEEP, 0, &b, 0 ); + if (rc!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) + { + ok(rc!=0,"SystemParametersInfoW: rc=%d err=%ld\n",rc,GetLastError()); + eq( b, curr_val, "SystemParametersInfoW", "%d" ); + } + + /* is a message sent for the second change? */ + rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + test_change_message( SPI_SETBEEP, 0 ); + + curr_val = FALSE; + rc=SystemParametersInfoW( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + ok(rc!=0,"SystemParametersInfo: rc=%d err=%ld\n",rc,GetLastError()); + test_change_message( SPI_SETBEEP, 0 ); + test_reg_key( SPI_SETBEEP_REGKEY, + SPI_SETBEEP_VALNAME, + curr_val ? "Yes" : "No" ); + rc=SystemParametersInfoA( SPI_GETBEEP, 0, &b, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( b, curr_val, "SPI_{GET,SET}BEEP", "%d" ); + rc=SystemParametersInfoW( SPI_GETBEEP, 0, &b, 0 ); + if (rc!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) + { + ok(rc!=0,"SystemParametersInfoW: rc=%d err=%ld\n",rc,GetLastError()); + eq( b, curr_val, "SystemParametersInfoW", "%d" ); + } + ok( MessageBeep( MB_OK ), "Return value of MessageBeep when sound is disabled" ); + + rc=SystemParametersInfoA( SPI_SETBEEP, old_b, 0, SPIF_UPDATEINIFILE ); + ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%ld\n",rc,GetLastError()); +} + +static const char *setmouse_valuenames[3] = { + SPI_SETMOUSE_VALNAME1, + SPI_SETMOUSE_VALNAME2, + SPI_SETMOUSE_VALNAME3 +}; + +/* + * Runs check for one setting of spi_setmouse. + */ +static void run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *proj_change, + int nchange ) +{ + BOOL rc; + INT mi[3]; + static int aw_turn = 0; + + char buf[20]; + int i; + + aw_turn++; + rc=0; + if (aw_turn % 2!=0) /* call unicode version each second call */ + rc=SystemParametersInfoW( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (aw_turn % 2==0 || (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)) + rc=SystemParametersInfoA( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + ok(rc!=0,"SystemParametersInfo: rc=%d err=%ld\n",rc,GetLastError()); + test_change_message( SPI_SETMOUSE, 0 ); + for (i = 0; i < 3; i++) + { + sprintf( buf, "%d", curr_val[i] ); + test_reg_key( SPI_SETMOUSE_REGKEY, setmouse_valuenames[i], buf ); + } + + rc=SystemParametersInfoA( SPI_GETMOUSE, 0, mi, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + for (i = 0; i < 3; i++) + { + ok(mi[i] == curr_val[i], + "incorrect value for %d: %d != %d", i, mi[i], curr_val[i]); + } + + rc=SystemParametersInfoW( SPI_GETMOUSE, 0, mi, 0 ); + if (rc!=0 && GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) + { + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + for (i = 0; i < 3; i++) + { + ok(mi[i] == curr_val[i], + "incorrect value for %d: %d != %d", i, mi[i], curr_val[i]); + } + } + +#if 0 /* FIXME: this always fails for me - AJ */ + for (i = 0; i < nchange; i++) + { + POINT mv; + mouse_event( MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, 0, 0, 0, 0 ); + mouse_event( MOUSEEVENTF_MOVE, req_change[i].x, req_change[i].y, 0, 0 ); + GetCursorPos( &mv ); + ok( proj_change[i].x == mv.x, "Projected dx and real dx comparison. May fail under high load." ); + ok( proj_change[i].y == mv.y, "Projected dy equals real dy. May fail under high load." ); + } +#endif +} + +static void test_SPI_SETMOUSE( void ) /* 4 */ +{ + BOOL rc; + INT old_mi[3]; + + /* win nt default values - 6, 10, 1 */ + INT curr_val[3] = {6, 10, 1}; + + /* requested and projected mouse movements */ + POINT req_change[] = { {6, 6}, { 7, 6}, { 8, 6}, {10, 10}, {11, 10}, {100, 100} }; + POINT proj_change1[] = { {6, 6}, {14, 6}, {16, 6}, {20, 20}, {22, 20}, {200, 200} }; + POINT proj_change2[] = { {6, 6}, {14, 6}, {16, 6}, {20, 20}, {44, 20}, {400, 400} }; + POINT proj_change3[] = { {6, 6}, {14, 6}, {16, 6}, {20, 20}, {22, 20}, {200, 200} }; + POINT proj_change4[] = { {6, 6}, { 7, 6}, { 8, 6}, {10, 10}, {11, 10}, {100, 100} }; + POINT proj_change5[] = { {6, 6}, { 7, 6}, {16, 6}, {20, 20}, {22, 20}, {200, 200} }; + POINT proj_change6[] = { {6, 6}, {28, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} }; + POINT proj_change7[] = { {6, 6}, {14, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} }; + POINT proj_change8[] = { {6, 6}, {28, 6}, {32, 6}, {40, 40}, {44, 40}, {400, 400} }; + + int nchange = sizeof( req_change ) / sizeof( POINT ); + + trace("testing SPI_{GET,SET}MOUSE\n"); + rc=SystemParametersInfoA( SPI_GETMOUSE, 0, old_mi, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + + run_spi_setmouse_test( curr_val, req_change, proj_change1, nchange ); + + /* acceleration change */ + curr_val[2] = 2; + run_spi_setmouse_test( curr_val, req_change, proj_change2, nchange ); + + /* acceleration change */ + curr_val[2] = 3; + run_spi_setmouse_test( curr_val, req_change, proj_change3, nchange ); + + /* acceleration change */ + curr_val[2] = 0; + run_spi_setmouse_test( curr_val, req_change, proj_change4, nchange ); + + /* threshold change */ + curr_val[2] = 1; + curr_val[0] = 7; + run_spi_setmouse_test( curr_val, req_change, proj_change5, nchange ); + + /* threshold change */ + curr_val[2] = 2; + curr_val[0] = 6; + curr_val[1] = 6; + run_spi_setmouse_test( curr_val, req_change, proj_change6, nchange ); + + /* threshold change */ + curr_val[1] = 7; + run_spi_setmouse_test( curr_val, req_change, proj_change7, nchange ); + + /* threshold change */ + curr_val[1] = 5; + run_spi_setmouse_test( curr_val, req_change, proj_change8, nchange ); + + rc=SystemParametersInfoA( SPI_SETMOUSE, 0, old_mi, SPIF_UPDATEINIFILE ); + ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%ld\n",rc,GetLastError()); +} + +#if 0 +static void test_setborder(UINT curr_val) +{ + BOOL rc; + UINT border; + INT frame; + char buf[10]; + + rc=SystemParametersInfoA( SPI_SETBORDER, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + test_change_message( SPI_SETBORDER, 1 ); + sprintf( buf, "%d", curr_val ); + test_reg_key( SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME, buf ); + + if (curr_val == 0) + curr_val = 1; + rc=SystemParametersInfoA( SPI_GETBORDER, 0, &border, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( border, curr_val, "SPI_{GET,SET}BORDER", "%d"); + + frame = curr_val + GetSystemMetrics( SM_CXDLGFRAME ); + eq( frame, GetSystemMetrics( SM_CXFRAME ), "SM_CXFRAME", "%d" ); + eq( frame, GetSystemMetrics( SM_CYFRAME ), "SM_CYFRAME", "%d" ); + eq( frame, GetSystemMetrics( SM_CXSIZEFRAME ), "SM_CXSIZEFRAME", "%d" ); + eq( frame, GetSystemMetrics( SM_CYSIZEFRAME ), "SM_CYSIZEFRAME", "%d" ); +} + +static void test_SPI_SETBORDER( void ) /* 6 */ +{ + BOOL rc; + UINT old_border; + + /* These tests hang when XFree86 4.0 for Windows is running (tested on + * WinNT, SP2, Cygwin/XFree 4.1.0. Skip the test when XFree86 is + * running. + */ + if (FindWindowA( NULL, "Cygwin/XFree86" )) + return; + + trace("testing SPI_{GET,SET}BORDER\n"); + rc=SystemParametersInfoA( SPI_GETBORDER, 0, &old_border, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + + test_setborder(1); + test_setborder(0); + test_setborder(7); + test_setborder(20); + + /* This will restore sane values if the test hang previous run. */ + if ( old_border == 7 || old_border == 20 ) + old_border = -15; + + rc=SystemParametersInfoA( SPI_SETBORDER, old_border, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%ld\n",rc,GetLastError()); +} +#endif + +static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ +{ + BOOL rc; + UINT old_speed; + const UINT vals[]={0,20,31}; + int i; + + trace("testing SPI_{GET,SET}KEYBOARDSPEED\n"); + rc=SystemParametersInfoA( SPI_GETKEYBOARDSPEED, 0, &old_speed, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + + for (i=0;i 32 ? old_spacing-1 : 32); + rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, curr_val, 0, + SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + test_change_message( SPI_ICONHORIZONTALSPACING, 0 ); + /* The registry keys depend on the Windows version and the values too + * => don't test them + */ + + rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &spacing, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( spacing, curr_val, "ICONHORIZONTALSPACING", "%d"); + eq( GetSystemMetrics( SM_CXICONSPACING ), curr_val, "SM_CXICONSPACING", "%d" ); + + curr_val = 10; + rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, curr_val, 0, + SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + curr_val = 32; /*min value*/ + test_change_message( SPI_ICONHORIZONTALSPACING, 0 ); + + rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0, &spacing, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( spacing, curr_val, "ICONHORIZONTALSPACING", "%d" ); + eq( GetSystemMetrics( SM_CXICONSPACING ), curr_val, "SM_CXICONSPACING", "%d" ); + + rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, old_spacing, 0, SPIF_UPDATEINIFILE ); + ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%ld\n",rc,GetLastError()); +} + +static void test_SPI_SETSCREENSAVETIMEOUT( void ) /* 14 */ +{ + BOOL rc; + UINT old_timeout; + const UINT vals[]={0,32767}; + int i; + + trace("testing SPI_{GET,SET}SCREENSAVETIMEOUT\n"); + rc=SystemParametersInfoA( SPI_GETSCREENSAVETIMEOUT, 0, &old_timeout, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + + for (i=0;i don't test them + */ + + rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &spacing, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( spacing, curr_val, "ICONVERTICALSPACING", "%d" ); + eq( GetSystemMetrics( SM_CYICONSPACING ), curr_val, "SM_CYICONSPACING", "%d" ); + + curr_val = 10; + rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, curr_val, 0, + SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + curr_val = 32; /*min value*/ + test_change_message( SPI_ICONVERTICALSPACING, 0 ); + + rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0, &spacing, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + eq( spacing, curr_val, "ICONVERTICALSPACING", "%d" ); + eq( GetSystemMetrics( SM_CYICONSPACING ), curr_val, "SM_CYICONSPACING", "%d" ); + + rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, old_spacing, 0, + SPIF_UPDATEINIFILE ); + ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%ld\n",rc,GetLastError()); +} + +static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ +{ + BOOL rc; + BOOL old_b; + const UINT vals[]={TRUE,FALSE}; + int i; + + /* These tests hang when XFree86 4.0 for Windows is running (tested on + * WinNT, SP2, Cygwin/XFree 4.1.0. Skip the test when XFree86 is + * running. + */ + if (FindWindowA( NULL, "Cygwin/XFree86" )) + return; + + trace("testing SPI_{GET,SET}ICONTITLEWRAP\n"); + rc=SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &old_b, 0 ); + ok(rc!=0,"SystemParametersInfoA: rc=%d err=%ld\n",rc,GetLastError()); + + for (i=0;i= 3 && strcmp(argv[2],"strict")==0); + trace("strict=%d\n",strict); + + change_counter = 0; + change_last_param = 0; + + wc.lpszClassName = "SysParamsTestClass"; + wc.lpfnWndProc = SysParamsTestWndProc; + wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; + wc.hInstance = hInstance; + wc.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION ); + wc.hCursor = LoadCursorA( 0, (LPSTR)IDC_ARROW ); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 ); + wc.lpszMenuName = 0; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + RegisterClassA( &wc ); + + ghTestWnd = CreateWindowA( "SysParamsTestClass", "Test System Parameters Application", + WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 0, 0, hInstance, NULL ); + + hThread = CreateThread( NULL, 0, SysParamsThreadFunc, 0, 0, &dwThreadId ); + assert( hThread ); + CloseHandle( hThread ); + + while( GetMessageA( &msg, 0, 0, 0 )) { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } +} diff --git a/reactos/apps/tests/user32/testlist.c b/reactos/apps/tests/user32/testlist.c new file mode 100644 index 00000000000..ad55c1afea0 --- /dev/null +++ b/reactos/apps/tests/user32/testlist.c @@ -0,0 +1,34 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#include +#include +#include +#include "windef.h" +#include "winbase.h" + +extern void func_class(void); +extern void func_listbox(void); +extern void func_msg(void); +extern void func_sysparams(void); +extern void func_win(void); +extern void func_wsprintf(void); + +struct test +{ + const char *name; + void (*func)(void); +}; + +static const struct test winetest_testlist[] = +{ + { "class", func_class }, + { "listbox", func_listbox }, + { "msg", func_msg }, + { "sysparams", func_sysparams }, + { "win", func_win }, + { "wsprintf", func_wsprintf }, + { 0, 0 } +}; + +#define WINETEST_WANT_MAIN +#include "wine/test.h" diff --git a/reactos/apps/tests/user32/win.c b/reactos/apps/tests/user32/win.c new file mode 100644 index 00000000000..455b1d37d48 --- /dev/null +++ b/reactos/apps/tests/user32/win.c @@ -0,0 +1,715 @@ +/* + * Unit tests for window handling + * + * Copyright 2002 Bill Medland + * Copyright 2002 Alexandre Julliard + * + * 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 +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" + +#include "wine/test.h" + +HWND WINAPI GetShellWindow(void); + +#ifndef SPI_GETDESKWALLPAPER +#define SPI_GETDESKWALLPAPER 0x0073 +#endif + +#define LONG_PTR INT_PTR +#define ULONG_PTR UINT_PTR + +static HWND (WINAPI *pGetAncestor)(HWND,UINT); + +static HWND hwndMain, hwndMain2; +static HHOOK hhook; + +/* check the values returned by the various parent/owner functions on a given window */ +static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent, + HWND gw_owner, HWND ga_root, HWND ga_root_owner ) +{ + HWND res; + + if (pGetAncestor) + { + res = pGetAncestor( hwnd, GA_PARENT ); + ok( res == ga_parent, "Wrong result for GA_PARENT %p expected %p", res, ga_parent ); + } + res = (HWND)GetWindowLongA( hwnd, GWL_HWNDPARENT ); + ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %p expected %p", res, gwl_parent ); + res = GetParent( hwnd ); + ok( res == get_parent, "Wrong result for GetParent %p expected %p", res, get_parent ); + res = GetWindow( hwnd, GW_OWNER ); + ok( res == gw_owner, "Wrong result for GW_OWNER %p expected %p", res, gw_owner ); + if (pGetAncestor) + { + res = pGetAncestor( hwnd, GA_ROOT ); + ok( res == ga_root, "Wrong result for GA_ROOT %p expected %p", res, ga_root ); + res = pGetAncestor( hwnd, GA_ROOTOWNER ); + ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %p expected %p", res, ga_root_owner ); + } +} + + +static HWND create_tool_window( LONG style, HWND parent ) +{ + HWND ret = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", style, + 0, 0, 100, 100, parent, 0, 0, NULL ); + ok( ret != 0, "Creation failed" ); + return ret; +} + +/* test parent and owner values for various combinations */ +static void test_parent_owner(void) +{ + LONG style; + HWND test, owner, ret; + HWND desktop = GetDesktopWindow(); + HWND child = create_tool_window( WS_CHILD, hwndMain ); + + trace( "main window %p main2 %p desktop %p child %p\n", hwndMain, hwndMain2, desktop, child ); + + /* child without parent, should fail */ + test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", + WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL ); + ok( !test, "WS_CHILD without parent created" ); + + /* desktop window */ + check_parents( desktop, 0, 0, 0, 0, 0, 0 ); + style = GetWindowLongA( desktop, GWL_STYLE ); + ok( !SetWindowLongA( desktop, GWL_STYLE, WS_POPUP ), "Set GWL_STYLE on desktop succeeded" ); + ok( !SetWindowLongA( desktop, GWL_STYLE, 0 ), "Set GWL_STYLE on desktop succeeded" ); + ok( GetWindowLongA( desktop, GWL_STYLE ) == style, "Desktop style changed" ); + + /* normal child window */ + test = create_tool_window( WS_CHILD, hwndMain ); + trace( "created child %p\n", test ); + check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain ); + SetWindowLongA( test, GWL_STYLE, 0 ); + check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test ); + SetWindowLongA( test, GWL_STYLE, WS_POPUP ); + check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test ); + SetWindowLongA( test, GWL_STYLE, WS_POPUP|WS_CHILD ); + check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test ); + SetWindowLongA( test, GWL_STYLE, WS_CHILD ); + DestroyWindow( test ); + + /* normal child window with WS_MAXIMIZE */ + test = create_tool_window( WS_CHILD | WS_MAXIMIZE, hwndMain ); + DestroyWindow( test ); + + /* normal child window with WS_THICKFRAME */ + test = create_tool_window( WS_CHILD | WS_THICKFRAME, hwndMain ); + DestroyWindow( test ); + + /* popup window with WS_THICKFRAME */ + test = create_tool_window( WS_POPUP | WS_THICKFRAME, hwndMain ); + DestroyWindow( test ); + + /* child of desktop */ + test = create_tool_window( WS_CHILD, desktop ); + trace( "created child of desktop %p\n", test ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); + SetWindowLongA( test, GWL_STYLE, WS_POPUP ); + check_parents( test, desktop, 0, 0, 0, test, test ); + SetWindowLongA( test, GWL_STYLE, 0 ); + check_parents( test, desktop, 0, 0, 0, test, test ); + DestroyWindow( test ); + + /* child of desktop with WS_MAXIMIZE */ + test = create_tool_window( WS_CHILD | WS_MAXIMIZE, desktop ); + DestroyWindow( test ); + + /* child of desktop with WS_MINIMIZE */ + test = create_tool_window( WS_CHILD | WS_MINIMIZE, desktop ); + DestroyWindow( test ); + + /* child of child */ + test = create_tool_window( WS_CHILD, child ); + trace( "created child of child %p\n", test ); + check_parents( test, child, child, child, 0, hwndMain, hwndMain ); + SetWindowLongA( test, GWL_STYLE, 0 ); + check_parents( test, child, child, 0, 0, hwndMain, test ); + SetWindowLongA( test, GWL_STYLE, WS_POPUP ); + check_parents( test, child, child, 0, 0, hwndMain, test ); + DestroyWindow( test ); + + /* child of child with WS_MAXIMIZE */ + test = create_tool_window( WS_CHILD | WS_MAXIMIZE, child ); + DestroyWindow( test ); + + /* child of child with WS_MINIMIZE */ + test = create_tool_window( WS_CHILD | WS_MINIMIZE, child ); + DestroyWindow( test ); + + /* not owned top-level window */ + test = create_tool_window( 0, 0 ); + trace( "created top-level %p\n", test ); + check_parents( test, desktop, 0, 0, 0, test, test ); + SetWindowLongA( test, GWL_STYLE, WS_POPUP ); + check_parents( test, desktop, 0, 0, 0, test, test ); + SetWindowLongA( test, GWL_STYLE, WS_CHILD ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); + DestroyWindow( test ); + + /* not owned top-level window with WS_MAXIMIZE */ + test = create_tool_window( WS_MAXIMIZE, 0 ); + DestroyWindow( test ); + + /* owned top-level window */ + test = create_tool_window( 0, hwndMain ); + trace( "created owned top-level %p\n", test ); + check_parents( test, desktop, hwndMain, 0, hwndMain, test, test ); + SetWindowLongA( test, GWL_STYLE, WS_POPUP ); + check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); + SetWindowLongA( test, GWL_STYLE, WS_CHILD ); + check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop ); + DestroyWindow( test ); + + /* owned top-level window with WS_MAXIMIZE */ + test = create_tool_window( WS_MAXIMIZE, hwndMain ); + DestroyWindow( test ); + + /* not owned popup */ + test = create_tool_window( WS_POPUP, 0 ); + trace( "created popup %p\n", test ); + check_parents( test, desktop, 0, 0, 0, test, test ); + SetWindowLongA( test, GWL_STYLE, WS_CHILD ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); + SetWindowLongA( test, GWL_STYLE, 0 ); + check_parents( test, desktop, 0, 0, 0, test, test ); + DestroyWindow( test ); + + /* not owned popup with WS_MAXIMIZE */ + test = create_tool_window( WS_POPUP | WS_MAXIMIZE, 0 ); + DestroyWindow( test ); + + /* owned popup */ + test = create_tool_window( WS_POPUP, hwndMain ); + trace( "created owned popup %p\n", test ); + check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); + SetWindowLongA( test, GWL_STYLE, WS_CHILD ); + check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop ); + SetWindowLongA( test, GWL_STYLE, 0 ); + check_parents( test, desktop, hwndMain, 0, hwndMain, test, test ); + DestroyWindow( test ); + + /* owned popup with WS_MAXIMIZE */ + test = create_tool_window( WS_POPUP | WS_MAXIMIZE, hwndMain ); + DestroyWindow( test ); + + /* top-level window owned by child (same as owned by top-level) */ + test = create_tool_window( 0, child ); + trace( "created top-level owned by child %p\n", test ); + check_parents( test, desktop, hwndMain, 0, hwndMain, test, test ); + DestroyWindow( test ); + + /* top-level window owned by child (same as owned by top-level) with WS_MAXIMIZE */ + test = create_tool_window( WS_MAXIMIZE, child ); + DestroyWindow( test ); + + /* popup owned by desktop (same as not owned) */ + test = create_tool_window( WS_POPUP, desktop ); + trace( "created popup owned by desktop %p\n", test ); + check_parents( test, desktop, 0, 0, 0, test, test ); + DestroyWindow( test ); + + /* popup owned by desktop (same as not owned) with WS_MAXIMIZE */ + test = create_tool_window( WS_POPUP | WS_MAXIMIZE, desktop ); + DestroyWindow( test ); + + /* popup owned by child (same as owned by top-level) */ + test = create_tool_window( WS_POPUP, child ); + trace( "created popup owned by child %p\n", test ); + check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); + DestroyWindow( test ); + + /* popup owned by child (same as owned by top-level) with WS_MAXIMIZE */ + test = create_tool_window( WS_POPUP | WS_MAXIMIZE, child ); + DestroyWindow( test ); + + /* not owned popup with WS_CHILD (same as WS_POPUP only) */ + test = create_tool_window( WS_POPUP | WS_CHILD, 0 ); + trace( "created WS_CHILD popup %p\n", test ); + check_parents( test, desktop, 0, 0, 0, test, test ); + DestroyWindow( test ); + + /* not owned popup with WS_CHILD | WS_MAXIMIZE (same as WS_POPUP only) */ + test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, 0 ); + DestroyWindow( test ); + + /* owned popup with WS_CHILD (same as WS_POPUP only) */ + test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain ); + trace( "created owned WS_CHILD popup %p\n", test ); + check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain ); + DestroyWindow( test ); + + /* owned popup with WS_CHILD (same as WS_POPUP only) with WS_MAXIMIZE */ + test = create_tool_window( WS_POPUP | WS_CHILD | WS_MAXIMIZE, hwndMain ); + DestroyWindow( test ); + + /******************** parent changes *************************/ + trace( "testing parent changes\n" ); + + /* desktop window */ + check_parents( desktop, 0, 0, 0, 0, 0, 0 ); +#if 0 /* this test succeeds on NT but crashes on win9x systems */ + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 ); + ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop" ); + check_parents( desktop, 0, 0, 0, 0, 0, 0 ); + ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop" ); + check_parents( desktop, 0, 0, 0, 0, 0, 0 ); +#endif + /* normal child window */ + test = create_tool_window( WS_CHILD, hwndMain ); + trace( "created child %p\n", test ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 ); + ok( ret == hwndMain, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain ); + check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child ); + ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 ); + check_parents( test, child, child, child, 0, hwndMain, hwndMain ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)desktop ); + ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); + + /* window is now child of desktop so GWL_HWNDPARENT changes owner from now on */ + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child ); + ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret ); + check_parents( test, desktop, child, desktop, child, test, desktop ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 ); + ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); + DestroyWindow( test ); + + /* not owned top-level window */ + test = create_tool_window( 0, 0 ); + trace( "created top-level %p\n", test ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 ); + ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret ); + check_parents( test, desktop, hwndMain2, 0, hwndMain2, test, test ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child ); + ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 ); + check_parents( test, desktop, child, 0, child, test, test ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 ); + ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child ); + check_parents( test, desktop, 0, 0, 0, test, test ); + DestroyWindow( test ); + + /* not owned popup */ + test = create_tool_window( WS_POPUP, 0 ); + trace( "created popup %p\n", test ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)hwndMain2 ); + ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret ); + check_parents( test, desktop, hwndMain2, hwndMain2, hwndMain2, test, hwndMain2 ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (LONG_PTR)child ); + ok( ret == hwndMain2, "GWL_HWNDPARENT return value %p expected %p", ret, hwndMain2 ); + check_parents( test, desktop, child, child, child, test, hwndMain ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, 0 ); + ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child ); + check_parents( test, desktop, 0, 0, 0, test, test ); + DestroyWindow( test ); + + /* normal child window */ + test = create_tool_window( WS_CHILD, hwndMain ); + trace( "created child %p\n", test ); + + ret = SetParent( test, desktop ); + ok( ret == hwndMain, "SetParent return value %p expected %p", ret, hwndMain ); + check_parents( test, desktop, 0, desktop, 0, test, desktop ); + + ret = SetParent( test, child ); + ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop ); + check_parents( test, child, child, child, 0, hwndMain, hwndMain ); + + ret = SetParent( test, hwndMain2 ); + ok( ret == child, "SetParent return value %p expected %p", ret, child ); + check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 ); + DestroyWindow( test ); + + /* not owned top-level window */ + test = create_tool_window( 0, 0 ); + trace( "created top-level %p\n", test ); + + ret = SetParent( test, child ); + ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop ); + check_parents( test, child, child, 0, 0, hwndMain, test ); + DestroyWindow( test ); + + /* owned popup */ + test = create_tool_window( WS_POPUP, hwndMain2 ); + trace( "created owned popup %p\n", test ); + + ret = SetParent( test, child ); + ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop ); + check_parents( test, child, child, hwndMain2, hwndMain2, hwndMain, hwndMain2 ); + + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)hwndMain ); + ok( ret == child, "GWL_HWNDPARENT return value %p expected %p", ret, child ); + check_parents( test, hwndMain, hwndMain, hwndMain2, hwndMain2, hwndMain, hwndMain2 ); + DestroyWindow( test ); + + /**************** test owner destruction *******************/ + + /* owned child popup */ + owner = create_tool_window( 0, 0 ); + test = create_tool_window( WS_POPUP, owner ); + trace( "created owner %p and popup %p\n", owner, test ); + ret = SetParent( test, child ); + ok( ret == desktop, "SetParent return value %p expected %p", ret, desktop ); + check_parents( test, child, child, owner, owner, hwndMain, owner ); + /* window is now child of 'child' but owned by 'owner' */ + DestroyWindow( owner ); + ok( IsWindow(test), "Window %p destroyed by owner destruction", test ); + check_parents( test, child, child, owner, owner, hwndMain, owner ); + ok( !IsWindow(owner), "Owner %p not destroyed", owner ); + DestroyWindow(test); + + /* owned top-level popup */ + owner = create_tool_window( 0, 0 ); + test = create_tool_window( WS_POPUP, owner ); + trace( "created owner %p and popup %p\n", owner, test ); + check_parents( test, desktop, owner, owner, owner, test, owner ); + DestroyWindow( owner ); + ok( !IsWindow(test), "Window %p not destroyed by owner destruction", test ); + + /* top-level popup owned by child */ + owner = create_tool_window( WS_CHILD, hwndMain2 ); + test = create_tool_window( WS_POPUP, 0 ); + trace( "created owner %p and popup %p\n", owner, test ); + ret = (HWND)SetWindowLongA( test, GWL_HWNDPARENT, (ULONG_PTR)owner ); + ok( ret == 0, "GWL_HWNDPARENT return value %p expected 0", ret ); + check_parents( test, desktop, owner, owner, owner, test, hwndMain2 ); + DestroyWindow( owner ); + ok( IsWindow(test), "Window %p destroyed by owner destruction", test ); + ok( !IsWindow(owner), "Owner %p not destroyed", owner ); + check_parents( test, desktop, owner, owner, owner, test, owner ); + DestroyWindow(test); + + /* final cleanup */ + DestroyWindow(child); +} + + +static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_GETMINMAXINFO: + { + MINMAXINFO* minmax = (MINMAXINFO *)lparam; + + trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam); + trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n" + " ptMinTrackSize (%ld,%ld), 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); + SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021); + break; + } + case WM_NCCREATE: + { + BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021; + CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; + + trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style); + if (got_getminmaxinfo) + trace("%p got WM_GETMINMAXINFO\n", hwnd); + + if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) + ok(got_getminmaxinfo, "main: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n"); + else + ok(!got_getminmaxinfo, "main: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n"); + break; + } + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_GETMINMAXINFO: + { + MINMAXINFO* minmax = (MINMAXINFO *)lparam; + + trace("hwnd %p, WM_GETMINMAXINFO, %08x, %08lx\n", hwnd, wparam, lparam); + trace("ptReserved (%ld,%ld), ptMaxSize (%ld,%ld), ptMaxPosition (%ld,%ld)\n" + " ptMinTrackSize (%ld,%ld), 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); + SetWindowLongA(hwnd, GWL_USERDATA, 0x20031021); + break; + } + case WM_NCCREATE: + { + BOOL got_getminmaxinfo = GetWindowLongA(hwnd, GWL_USERDATA) == 0x20031021; + CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; + + trace("WM_NCCREATE: hwnd %p, parent %p, style %08lx\n", hwnd, cs->hwndParent, cs->style); + if (got_getminmaxinfo) + trace("%p got WM_GETMINMAXINFO\n", hwnd); + + if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) + ok(got_getminmaxinfo, "tool: WM_GETMINMAXINFO should have been received before WM_NCCREATE\n"); + else + ok(!got_getminmaxinfo, "tool: WM_GETMINMAXINFO should NOT have been received before WM_NCCREATE\n"); + break; + } + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static BOOL RegisterWindowClasses(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = main_window_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 = "MainWindowClass"; + + if(!RegisterClassA(&cls)) return FALSE; + + cls.style = 0; + cls.lpfnWndProc = tool_window_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 = "ToolWindowClass"; + + if(!RegisterClassA(&cls)) return FALSE; + + return TRUE; +} + +static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) +{ + static const char *CBT_code_name[10] = { + "HCBT_MOVESIZE", + "HCBT_MINMAX", + "HCBT_QS", + "HCBT_CREATEWND", + "HCBT_DESTROYWND", + "HCBT_ACTIVATE", + "HCBT_CLICKSKIPPED", + "HCBT_KEYSKIPPED", + "HCBT_SYSCOMMAND", + "HCBT_SETFOCUS" }; + const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown"; + + trace("CBT: %d (%s), %08x, %08lx\n", nCode, code_name, wParam, lParam); + + switch (nCode) + { + case HCBT_CREATEWND: + { + CBT_CREATEWNDA *createwnd = (CBT_CREATEWNDA *)lParam; + trace("HCBT_CREATEWND: hwnd %p, parent %p, style %08lx\n", + (HWND)wParam, createwnd->lpcs->hwndParent, createwnd->lpcs->style); + ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n"); + break; + } + } + + return CallNextHookEx(hhook, nCode, wParam, lParam); +} + +static void test_shell_window() +{ + BOOL ret; + DWORD error; + HMODULE hinst, hUser32; + BOOL (WINAPI*SetShellWindow)(HWND); + BOOL (WINAPI*SetShellWindowEx)(HWND, HWND); + HWND hwnd1, hwnd2, hwnd3, hwnd4, hwnd5; + HWND shellWindow, nextWnd; + + shellWindow = GetShellWindow(); + hinst = GetModuleHandle(0); + hUser32 = GetModuleHandleA("user32"); + + SetShellWindow = (void *)GetProcAddress(hUser32, "SetShellWindow"); + SetShellWindowEx = (void *)GetProcAddress(hUser32, "SetShellWindowEx"); + + trace("previous shell window: %p\n", shellWindow); + + if (shellWindow) { + DWORD pid; + HANDLE hProcess; + + ret = DestroyWindow(shellWindow); + error = GetLastError(); + + ok(!ret, "DestroyWindow(shellWindow)\n"); + /* passes on Win XP, but not on Win98 + ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n"); */ + + /* close old shell instance */ + GetWindowThreadProcessId(shellWindow, &pid); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + ret = TerminateProcess(hProcess, 0); + ok(ret, "termination of previous shell process failed: GetLastError()=%ld", GetLastError()); + WaitForSingleObject(hProcess, INFINITE); /* wait for termination */ + CloseHandle(hProcess); + } + + hwnd1 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST1"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 100, 100, 300, 200, 0, 0, hinst, 0); + trace("created window 1: %p\n", hwnd1); + + ret = SetShellWindow(hwnd1); + ok(ret, "first call to SetShellWindow(hwnd1)\n"); + shellWindow = GetShellWindow(); + ok(shellWindow==hwnd1, "wrong shell window: %p", shellWindow); + + ret = SetShellWindow(hwnd1); + ok(!ret, "second call to SetShellWindow(hwnd1)\n"); + + ret = SetShellWindow(0); + error = GetLastError(); + /* passes on Win XP, but not on Win98 + ok(!ret, "reset shell window by SetShellWindow(0)\n"); + ok(error==ERROR_INVALID_WINDOW_HANDLE, "ERROR_INVALID_WINDOW_HANDLE after SetShellWindow(0)\n"); */ + + ret = SetShellWindow(hwnd1); + /* passes on Win XP, but not on Win98 + ok(!ret, "third call to SetShellWindow(hwnd1)\n"); */ + + todo_wine + { + SetWindowLong(hwnd1, GWL_EXSTYLE, GetWindowLong(hwnd1,GWL_EXSTYLE)|WS_EX_TOPMOST); + ret = GetWindowLong(hwnd1,GWL_EXSTYLE)&WS_EX_TOPMOST? TRUE: FALSE; + ok(!ret, "SetWindowExStyle(hwnd1, WS_EX_TOPMOST)\n"); + } + + ret = DestroyWindow(hwnd1); + ok(ret, "DestroyWindow(hwnd1)\n"); + + hwnd2 = CreateWindowEx(WS_EX_TOPMOST, TEXT("#32770"), TEXT("TEST2"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 150, 250, 300, 200, 0, 0, hinst, 0); + trace("created window 2: %p\n", hwnd2); + ret = SetShellWindow(hwnd2); + ok(!ret, "SetShellWindow(hwnd2) with WS_EX_TOPMOST"); + + hwnd3 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST3"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 200, 400, 300, 200, 0, 0, hinst, 0); + trace("created window 3: %p\n", hwnd3); + + hwnd4 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST4"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 250, 500, 300, 200, 0, 0, hinst, 0); + trace("created window 4: %p\n", hwnd4); + + nextWnd = GetWindow(hwnd4, GW_HWNDNEXT); + ok(nextWnd==hwnd3, "wrong next window for hwnd4: %p - expected hwnd3\n", nextWnd); + + ret = SetShellWindow(hwnd4); + ok(ret, "SetShellWindow(hwnd4)\n"); + shellWindow = GetShellWindow(); + ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4", shellWindow); + + nextWnd = GetWindow(hwnd4, GW_HWNDNEXT); + ok(nextWnd==0, "wrong next window for hwnd4: %p - expected 0\n", nextWnd); + + ret = SetWindowPos(hwnd4, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + ok(ret, "SetWindowPos(hwnd4, HWND_TOPMOST)\n"); + + ret = SetWindowPos(hwnd4, hwnd3, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + ok(ret, "SetWindowPos(hwnd4, hwnd3"); + + ret = SetShellWindow(hwnd3); + ok(!ret, "SetShellWindow(hwnd3)\n"); + shellWindow = GetShellWindow(); + ok(shellWindow==hwnd4, "wrong shell window: %p - expected hwnd4", shellWindow); + + hwnd5 = CreateWindowEx(0, TEXT("#32770"), TEXT("TEST5"), WS_OVERLAPPEDWINDOW/*|WS_VISIBLE*/, 300, 600, 300, 200, 0, 0, hinst, 0); + trace("created window 5: %p\n", hwnd5); + ret = SetWindowPos(hwnd4, hwnd5, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + ok(ret, "SetWindowPos(hwnd4, hwnd5)\n"); + + todo_wine + { + nextWnd = GetWindow(hwnd4, GW_HWNDNEXT); + ok(nextWnd==0, "wrong next window for hwnd4 after SetWindowPos(): %p - expected 0\n", nextWnd); + } + + /* destroy test windows */ + DestroyWindow(hwnd2); + DestroyWindow(hwnd3); + DestroyWindow(hwnd4); + DestroyWindow(hwnd5); +} + + +START_TEST(win) +{ + pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" ); + + if (!RegisterWindowClasses()) assert(0); + + hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); + assert(hhook); + + hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP, + 100, 100, 200, 200, + 0, 0, 0, NULL); + hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP, + 100, 100, 200, 200, + 0, 0, 0, NULL); + assert( hwndMain ); + assert( hwndMain2 ); + + test_parent_owner(); + test_shell_window(); + UnhookWindowsHookEx(hhook); +} diff --git a/reactos/apps/tests/user32/wsprintf.c b/reactos/apps/tests/user32/wsprintf.c new file mode 100644 index 00000000000..b1f8c8f860d --- /dev/null +++ b/reactos/apps/tests/user32/wsprintf.c @@ -0,0 +1,57 @@ + /* Unit test suite for the wsprintf functions + * + * Copyright 2002 Bill Medland + * + * 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 + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" + +static void wsprintfATest(void) +{ + char buf[25]; + int rc; + + rc=wsprintfA(buf, "%010ld", -1); + ok(rc == 10, "wsPrintfA length failure: rc=%d error=%ld",rc,GetLastError()); + ok((lstrcmpA(buf, "-000000001") == 0), + "wsprintfA zero padded negative value failure: buf=[%s]",buf); +} + +static void wsprintfWTest(void) +{ + static const WCHAR fmt[] = {'%','0','1','0','l','d','\0'}; + static const WCHAR target[] = {'-','0','0','0','0','0','0','0','0','1', '\0'}; + WCHAR buf[25]; + int rc; + + rc=wsprintfW(buf, fmt, -1); + if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + return; + ok(rc == 10, "wsPrintfW length failure: rc=%d error=%ld",rc,GetLastError()); + ok((lstrcmpW(buf, target) == 0), + "wsprintfW zero padded negative value failure"); +} + +START_TEST(wsprintf) +{ + wsprintfATest(); + wsprintfWTest(); +}