1 /* Windows GUI Behaviour Tester
3 * Copyright 1999 Ove Kåven
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /* checks to include */
28 #define LOGGING /* can be undefined under Wine and use -debugmsg +message instead */
29 #define MAIN_STYLE WS_OVERLAPPEDWINDOW|WS_HSCROLL
30 #define MAIN_EXSTYLE 0
31 #undef TEST_DESTROY_MAIN
38 /************************/
39 /*** GLOBAL VARIABLES ***/
40 /************************/
44 HWND hListBox,hMainWnd,hSubWnd;
45 HWND hButton[4]={0,0,0,0};
46 HWND hDialog=0,hGroup=0,hSubDlg=0;
47 WNDPROC wndButton[4],wndDialog,wndGroup,wndSubDlg;
48 BOOL Clicked=0,Ready=0;
50 #define STATE_CREATE 0
51 #define STATE_DESTROY 1
53 #define STATE_UPDATE 3
54 #define STATE_DIALOG 4
56 #define STATE_DIRECT 6
57 #define STATE_DISPATCH 7
58 #define STATE_RECURS 8
71 static char wclassname[] = "GUITestClass";
72 static char wcclassname[] = "GUITestChildClass";
73 static char winname[] = "GUITest";
75 /**************************/
76 /*** LOGGING FACILITIES ***/
77 /**************************/
83 #define MSG(x) {x,#x},
84 #define MSG2(x,y) {y,#x},
87 /* we get these in CreateWindow */
94 /* we get these in ShowWindow */
96 MSG(WM_WINDOWPOSCHANGING)
97 MSG(WM_QUERYNEWPALETTE)
105 MSG(WM_WINDOWPOSCHANGED)
109 /* we get these in DestroyWindow */
114 /* we get these directly sent */
117 MSG(WM_MOUSEACTIVATE)
118 MSG(WM_CHILDACTIVATE)
128 MSG(WM_LBUTTONDBLCLK)
129 MSG(WM_NCLBUTTONDOWN)
131 MSG(WM_NCLBUTTONDBLCLK)
140 MSG(WM_CTLCOLORSTATIC)
145 /* moving and sizing */
146 MSG2(WM_ENTERSIZEMOVE,0x0231)
147 MSG2(WM_EXITSIZEMOVE,0x0232)
152 /* menus/dialog boxes */
164 /* getting these from Wine but not from Windows */
165 MSG2(WM_SETVISIBLE,0x0009) /* unheard of in BC++ 4.52 */
167 MSG(WM_CAPTURECHANGED)
172 struct MSGNAMES ButMsgs[]={
178 char*MsgName(UINT msg,HWND hWnd)
181 static char buffer[64],wclass[64];
182 GetClassName(hWnd,wclass,sizeof(wclass));
184 #define MSGSEARCH(msgs) { \
185 for (i=0; msgs[i].name&&msgs[i].msg!=msg; i++); \
186 if (msgs[i].name) return msgs[i].name; \
189 if (!stricmp(wclass,"Button")) MSGSEARCH(ButMsgs);
193 sprintf(buffer,"WM_USER+%04x{%s}",msg-WM_USER,wclass);
196 /* message not found */
197 sprintf(buffer,"%04x{%s}",msg,wclass);
201 char*WndName(HWND hWnd,int state)
203 static char buffer[16];
204 if (!hWnd) return "0000";
205 if (hWnd==hMainWnd || (state==STATE_CREATE && !hMainWnd)) return "main";
206 if (hWnd==hSubWnd || (state==STATE_CREATE && !hSubWnd)) return "chld";
207 if (hWnd==hDialog || (state==STATE_DIALOG && !hDialog)) return "tdlg";
208 if (hWnd==hGroup) return "tgrp";
209 if (hWnd==hButton[0]) return "but1";
210 if (hWnd==hButton[1]) return "but2";
211 if (hWnd==hButton[2]) return "but3";
212 if (hWnd==hButton[3]) return "but4";
213 if (hWnd==hSubDlg || (state==STATE_CREATE && !hSubDlg)) return "sdlg";
215 int id=GetDlgCtrlID(hWnd);
217 sprintf(buffer,"dlgitem(%d)",id);
221 sprintf(buffer,"%04x",hWnd);
225 void Log(const char*fmt)
228 if (!Clicked) SendMessage(hListBox,LB_ADDSTRING,0,(LPARAM)fmt);
232 void Logf(const char*fmt,...)
235 static char buffer[256];
238 vsprintf(buffer,fmt,par);
243 void LogChildOrder(HWND hWnd)
245 HWND hWndChild = GetWindow(hWnd,GW_CHILD);
246 static char buffer[256];
248 strcpy(buffer,"child list:");
250 strcat(strcat(buffer," "),WndName(hWndChild,State));
251 hWndChild=GetWindow(hWndChild,GW_HWNDNEXT);
256 void LogMessage(int state,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam,char*name)
258 static char buffer[256];
259 DWORD tick=GetTickCount()-StartTime;
260 char*msgname=MsgName(msg,hWnd);
261 if (!name) name=WndName(hWnd,state);
266 Logf("%04d[%s(%d):%s]%s(%s,%08x)",tick,StateName[state],Rec,
267 name,msgname,WndName((HWND)wParam,State),lParam);
273 Logf("%04d[%s(%d):%s]%s(%08x,%s)",tick,StateName[state],Rec,
274 name,msgname,wParam,WndName((HWND)lParam,State));
279 Logf("%04d[%s(%d):%s]%s(%08x,%04x:%s)",tick,StateName[state],Rec,
280 name,msgname,wParam,HIWORD(lParam),WndName((HWND)LOWORD(lParam),State));
283 case WM_WINDOWPOSCHANGING:
284 case WM_WINDOWPOSCHANGED:
286 WINDOWPOS*pos=(WINDOWPOS*)lParam;
288 Logf("%04d[%s(%d):%s]%s(%08x,%p)",tick,StateName[state],Rec,
289 name,msgname,wParam,pos);
291 Logf("%04d[%s(%d):%s]%s(%04x,%p)",tick,StateName[state],Rec,
292 name,msgname,wParam,pos);
294 strcpy(buffer,"FLAGS:");
295 if (pos->flags&SWP_DRAWFRAME) strcat(buffer," DRAWFRAME");
296 if (pos->flags&SWP_HIDEWINDOW) strcat(buffer," HIDEWINDOW");
297 if (pos->flags&SWP_NOACTIVATE) strcat(buffer," NOACTIVATE");
298 if (pos->flags&SWP_NOCOPYBITS) strcat(buffer," NOCOPYBITS");
299 if (pos->flags&SWP_NOMOVE) strcat(buffer," NOMOVE");
300 if (pos->flags&SWP_NOOWNERZORDER) strcat(buffer," NOOWNERZORDER");
301 if (pos->flags&SWP_NOSIZE) strcat(buffer," NOSIZE");
302 if (pos->flags&SWP_NOREDRAW) strcat(buffer," NOREDRAW");
303 if (pos->flags&SWP_NOZORDER) strcat(buffer," NOZORDER");
304 if (pos->flags&SWP_SHOWWINDOW) strcat(buffer," SHOWWINDOW");
311 switch (wParam&0xFFF0) {
312 #define CASE(x) case SC_##x: cmd=#x; break;
332 Logf("%04d[%s(%d):%s]%s(%s+%x,%08x)",tick,StateName[state],Rec,
333 name,msgname,cmd,wParam&0xF,lParam);
334 } else goto GENERIC_MSG;
341 switch (LOWORD(wParam)) {
342 #define CASE(x) case SB_##x: cmd=#x; break;
343 #define CASE2(h,v) case SB_##h: if (msg==WM_HSCROLL) cmd=#h; else cmd=#v; break;
346 CASE2(LINELEFT,LINEUP)
347 CASE2(LINERIGHT,LINEDOWN)
348 CASE2(PAGELEFT,PAGEUP)
349 CASE2(PAGERIGHT,PAGEDOWN)
357 Logf("%04d[%s(%d):%s]%s(%s,%04x,%s)",tick,StateName[state],Rec,
358 name,msgname,cmd,HIWORD(wParam),WndName((HWND)lParam,State));
360 Logf("%04d[%s(%d):%s]%s(%04x,%04x,%s)",tick,StateName[state],Rec,
361 name,msgname,cmd,LOWORD(lParam),WndName((HWND)HIWORD(lParam),State));
363 } else goto GENERIC_MSG;
369 Logf("%04d[%s(%d):%s]%s(%08x,%08x)",tick,StateName[state],Rec,
370 name,msgname,wParam,lParam);
372 Logf("%04d[%s(%d):%s]%s(%04x,%08x)",tick,StateName[state],Rec,
373 name,msgname,wParam,lParam);
378 /***************************/
379 /*** GRAPHICS FACILITIES ***/
380 /***************************/
382 void Paint(HWND hWnd)
386 dc=BeginPaint(hWnd,&ps);
390 void FillPattern(HWND hWnd,HDC pdc)
392 HDC dc=pdc?pdc:GetDC(hWnd);
396 Logf("failed to acquire DC for window %s",WndName(hWnd,State));
399 Logf("acquired DC for %s window %s, painting",
400 IsWindowVisible(hWnd)?"visible":"invisible",WndName(hWnd,State));
402 GetClientRect(hWnd,&rect);
403 oldbrush=SelectObject(dc,GetStockObject(LTGRAY_BRUSH));
404 PatBlt(dc,0,0,rect.right,rect.bottom,PATCOPY);
405 SelectObject(dc,oldbrush);
406 if (!pdc) ReleaseDC(hWnd,dc);
409 void PaintPattern(HWND hWnd)
413 dc=BeginPaint(hWnd,&ps);
414 FillPattern(hWnd,dc);
418 /*************************/
419 /*** WINDOW PROCEDURES ***/
420 /*************************/
423 LRESULT FAR CALLBACK _export MainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
429 State=STATE_RECURS; Rec++;
430 if (!Clicked) LogMessage(OldState,hWnd,msg,wParam,lParam,NULL);
433 lResult=DefWindowProc(hWnd,msg,wParam,lParam);
438 SetParent(hListBox,hWnd);
439 GetClientRect(hWnd,&rect);
440 MoveWindow(hListBox,0,0,rect.right,rect.bottom,TRUE);
441 ShowWindow(hListBox,SW_SHOW);
447 GetClientRect(hWnd,&rect);
449 MoveWindow(hListBox,0,0,rect.right,rect.bottom,TRUE);
451 MoveWindow(hSubWnd,0,rect.bottom/2,rect.right,rect.bottom-(rect.bottom/2),TRUE);
460 lResult=DefWindowProc(hWnd,msg,wParam,lParam);
462 State=OldState; Rec--;
467 LRESULT FAR CALLBACK _export SubWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
473 State=STATE_RECURS; Rec++;
474 if (!Clicked) LogMessage(OldState,hWnd,msg,wParam,lParam,NULL);
480 lResult=DefWindowProc(hWnd,msg,wParam,lParam);
482 State=OldState; Rec--;
486 BOOL FAR CALLBACK _export SubDialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
488 /* SUBCLASSED CONTROLS */
489 LRESULT FAR CALLBACK _export SubClassWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
496 if (hWnd==hButton[0]) But=0; else
497 if (hWnd==hButton[1]) But=1; else
498 if (hWnd==hButton[2]) But=2; else
499 if (hWnd==hButton[3]) But=3;
501 State=STATE_RECURS; Rec++;
503 LogMessage(OldState,hWnd,msg,wParam,lParam,NULL);
505 lResult=CallWindowProc((FARPROC)wndButton[But],hWnd,msg,wParam,lParam);
506 if (msg==WM_LBUTTONUP) {
507 LogChildOrder(GetParent(hWnd));
510 else if (hWnd==hDialog) {
511 lResult=CallWindowProc((FARPROC)wndDialog,hWnd,msg,wParam,lParam);
513 else if (hWnd==hSubDlg) {
514 lResult=CallWindowProc((FARPROC)wndSubDlg,hWnd,msg,wParam,lParam);
516 else if (hWnd==hGroup) {
517 lResult=CallWindowProc((FARPROC)wndGroup,hWnd,msg,wParam,lParam);
518 if (msg==WM_SETFOCUS) {
519 /* create subdialog */
522 SetRect(&rect,0,0,1,1);
523 InvalidateRect(hWnd,&rect,FALSE);
526 #ifdef TEST_SUBDIALOG
528 hSubDlg=CreateDialog(hInst,MAKEINTRESOURCE(2),hWnd,(FARPROC)SubDialogProc);
532 GetWindowRect(GetParent(hWnd),&rect);
534 SetWindowPos(GetParent(hWnd),0,0,0,
535 rect.right-rect.left,rect.bottom-rect.top,
536 SWP_NOMOVE|SWP_NOZORDER);
543 State=OldState; Rec--;
547 /* MAIN DIALOG PROCEDURE */
548 BOOL FAR CALLBACK _export TestDialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
555 State=STATE_RECURS; Rec++;
556 if (!Clicked) LogMessage(OldState,hWndDlg,msg,wParam,lParam,"dlgp");
560 /* subclass dialog window proc */
561 wndDialog = (WNDPROC)SetWindowLong(hDialog,GWL_WNDPROC,(LONG)SubClassWindowProc);
562 Logf("dialog visible=%s",IsWindowVisible(hWndDlg)?"TRUE":"FALSE");
563 /* subclass OK button */
564 hButton[3] = GetDlgItem(hWndDlg,IDOK);
565 wndButton[3] = (WNDPROC)SetWindowLong(hButton[3],GWL_WNDPROC,(LONG)SubClassWindowProc);
566 /* subclass group box */
567 hGroup = GetDlgItem(hWndDlg,IDC_GROUPBOX1);
568 wndGroup = (WNDPROC)SetWindowLong(hGroup,GWL_WNDPROC,(LONG)SubClassWindowProc);
571 GetWindowRect(hWndDlg,&rect);
573 SetWindowPos(hWndDlg,0,0,0,
574 rect.right-rect.left,rect.bottom-rect.top,
575 SWP_NOMOVE|SWP_NOZORDER);
576 // ShowWindow(GetDlgItem(hWndDlg,IDCANCEL),SW_HIDE);
579 bResult=TRUE; /* we don't do SetFocus */
582 PaintPattern(hWndDlg);
586 EndDialog(hWndDlg,LOWORD(wParam));
590 EndDialog(hWndDlg,IDCANCEL);
597 State=OldState; Rec--;
601 /* SUBDIALOG PROCEDURE */
602 BOOL FAR CALLBACK _export SubDialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
609 State=STATE_RECURS; Rec++;
610 if (!Clicked) LogMessage(OldState,hWndDlg,msg,wParam,lParam,NULL);
614 /* subclass dialog window proc */
615 wndSubDlg = (WNDPROC)SetWindowLong(hDialog,GWL_WNDPROC,(LONG)SubClassWindowProc);
617 bResult=TRUE; /* we don't do SetFocus */
623 State=OldState; Rec--;
627 /********************/
628 /*** MAIN PROGRAM ***/
629 /********************/
635 wclass.style = CS_HREDRAW|CS_VREDRAW;
636 wclass.lpfnWndProc = MainWindowProc;
637 wclass.cbClsExtra = 0;
638 wclass.cbWndExtra = 0;
639 wclass.hInstance = hInst;
640 wclass.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(1));
641 wclass.hCursor = LoadCursor(0,IDC_ARROW);
642 wclass.hbrBackground = GetStockObject(WHITE_BRUSH);
643 wclass.lpszMenuName = NULL;
644 wclass.lpszClassName = wclassname;
645 if (!RegisterClass(&wclass)) return FALSE;
646 wclass.lpfnWndProc = SubWindowProc;
647 wclass.lpszClassName = wcclassname;
648 if (!RegisterClass(&wclass)) return FALSE;
652 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
653 LPSTR lpszCmdLine, int nCmdShow)
663 StartTime=GetTickCount();
664 hListBox = CreateWindow("LISTBOX","Messages",WS_BORDER|WS_VSCROLL|WS_CHILD|
665 LBS_HASSTRINGS|LBS_NOTIFY|LBS_WANTKEYBOARDINPUT,
666 0,0,0,0,GetDesktopWindow(),0,hInst,0);
668 MessageBox(0,"Could not create list box","Error",MB_OK);
672 hMainWnd = CreateWindowEx(MAIN_EXSTYLE,wclassname,winname,MAIN_STYLE,
673 CW_USEDEFAULT,0,400,300,0,0,hInst,0);
674 if (!hMainWnd) return 0;
676 ShowWindow(hMainWnd,nCmdShow);
677 #ifdef TEST_DESTROY_MAIN
679 DestroyWindow(hMainWnd);
681 while (GetMessage(&msg,0,0,0)) {
682 TranslateMessage(&msg);
683 State=STATE_DISPATCH;
684 DispatchMessage(&msg);
688 hMainWnd = CreateWindowEx(MAIN_EXSTYLE,wclassname,winname,MAIN_STYLE,
689 CW_USEDEFAULT,0,400,300,0,0,hInst,0);
690 if (!hMainWnd) return 0;
692 ShowWindow(hMainWnd,nCmdShow);
694 /* update, so no WM_PAINTs are pending */
696 // UpdateWindow(hMainWnd);
698 /* fill client area with a pattern */
699 FillPattern(hMainWnd,0);
700 /* create subwindow */
702 GetClientRect(hMainWnd,&rect);
703 hSubWnd = CreateWindow(wcclassname,winname,WS_CHILD|WS_BORDER|WS_CLIPSIBLINGS,
704 0,rect.bottom/2,rect.right,rect.bottom-(rect.bottom/2),hMainWnd,0,hInst,0);
705 if (!hSubWnd) return 0;
707 hButton[0] = CreateWindow("BUTTON","1",WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
708 8,8,48,20,hMainWnd,0,hInst,0);
709 hButton[1] = CreateWindow("BUTTON","2",WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
710 32,12,48,20,hMainWnd,0,hInst,0);
711 hButton[2] = CreateWindow("BUTTON","3",WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
712 56,16,48,20,hMainWnd,0,hInst,0);
714 wndButton[0] = (WNDPROC)SetWindowLong(hButton[0],GWL_WNDPROC,(LONG)SubClassWindowProc);
715 wndButton[1] = (WNDPROC)SetWindowLong(hButton[1],GWL_WNDPROC,(LONG)SubClassWindowProc);
716 wndButton[2] = (WNDPROC)SetWindowLong(hButton[2],GWL_WNDPROC,(LONG)SubClassWindowProc);
719 UpdateWindow(hButton[0]);
720 LogChildOrder(hMainWnd);
721 Logf("but1 visible=%d",IsWindowVisible(hButton[0]));
723 /* now reparent the button to our (invisible) subwindow */
725 /* in different order, seeing who gets topmost */
726 SetParent(hButton[0],hSubWnd);
727 SetParent(hButton[2],hSubWnd);
728 SetParent(hButton[1],hSubWnd);
729 LogChildOrder(hSubWnd);
730 /* the button should now be invisible */
731 Logf("but1 visible=%d",IsWindowVisible(hButton[0]));
732 /* see if we can draw on them */
733 FillPattern(hButton[0],0);
737 ShowWindow(hSubWnd,SW_SHOWNORMAL);
739 UpdateWindow(hSubWnd);
740 FillPattern(hSubWnd,0);
741 // InvalidateRect(hMainWnd,NULL,TRUE);
742 Logf("but1 visible=%d",IsWindowVisible(hButton[0]));
747 DialogBox(hInst,MAKEINTRESOURCE(1),hMainWnd,(FARPROC)TestDialogProc);
752 CHOOSECOLOR cc={sizeof(cc),0,hInst,0,arr,0};
758 while (GetMessage(&msg,0,0,0)) {
759 TranslateMessage(&msg);
760 State=STATE_DISPATCH;
761 DispatchMessage(&msg);