Cleanup thread stack allocation. Use a single VirtualAlloc for TEB and
[wine] / libtest / guitest.c
1 /* Windows GUI Behaviour Tester */
2 /* by Ove Kåven */
3
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdarg.h>
7 #include <windows.h>
8
9 #include "guitest.rh"
10
11 /* checks to include */
12 #define LOGGING /* can be undefined under Wine and use -debugmsg +message instead */
13 #define MAIN_STYLE WS_OVERLAPPEDWINDOW|WS_HSCROLL
14 #define MAIN_EXSTYLE 0
15 #undef TEST_DESTROY_MAIN
16 #define SHOW_SUB
17 #undef TEST_DIALOG
18 #define RESIZE_DIALOG
19 #undef TEST_SUBDIALOG
20 #undef TEST_COMMCTL
21
22 /************************/
23 /*** GLOBAL VARIABLES ***/
24 /************************/
25
26 HINSTANCE hInst;
27 DWORD StartTime;
28 HWND hListBox,hMainWnd,hSubWnd;
29 HWND hButton[4]={0,0,0,0};
30 HWND hDialog=0,hGroup=0,hSubDlg=0;
31 WNDPROC wndButton[4],wndDialog,wndGroup,wndSubDlg;
32 BOOL Clicked=0,Ready=0;
33 int State=0,Rec=0;
34 #define STATE_CREATE 0
35 #define STATE_DESTROY 1
36 #define STATE_SHOW 2
37 #define STATE_UPDATE 3
38 #define STATE_DIALOG 4
39 #define STATE_TEST 5
40 #define STATE_DIRECT 6
41 #define STATE_DISPATCH 7
42 #define STATE_RECURS 8
43 char*StateName[]={
44  "Creat",
45  "Destr",
46  "Show ",
47  "Updat",
48  "Dialg",
49  "Test ",
50  "Call ",
51  "Disp ",
52  "RCall"
53 };
54
55 static char wclassname[] = "GUITestClass";
56 static char wcclassname[] = "GUITestChildClass";
57 static char winname[] = "GUITest";
58
59 /**************************/
60 /*** LOGGING FACILITIES ***/
61 /**************************/
62
63 struct MSGNAMES {
64  int msg;
65  char*name;
66 } MsgNames[]={
67 #define MSG(x) {x,#x},
68 #define MSG2(x,y) {y,#x},
69 #define ENDMSG {0}
70
71 /* we get these in CreateWindow */
72 MSG(WM_GETMINMAXINFO)
73 MSG(WM_NCCREATE)
74 MSG(WM_NCCALCSIZE)
75 MSG(WM_CREATE)
76 MSG(WM_PARENTNOTIFY)
77
78 /* we get these in ShowWindow */
79 MSG(WM_SHOWWINDOW)
80 MSG(WM_WINDOWPOSCHANGING)
81 MSG(WM_QUERYNEWPALETTE)
82 MSG(WM_ACTIVATEAPP)
83 MSG(WM_NCACTIVATE)
84 MSG(WM_GETTEXT)
85 MSG(WM_ACTIVATE)
86 MSG(WM_SETFOCUS)
87 MSG(WM_NCPAINT)
88 MSG(WM_ERASEBKGND)
89 MSG(WM_WINDOWPOSCHANGED)
90 MSG(WM_SIZE)
91 MSG(WM_MOVE)
92
93 /* we get these in DestroyWindow */
94 MSG(WM_KILLFOCUS)
95 MSG(WM_DESTROY)
96 MSG(WM_NCDESTROY)
97
98 /* we get these directly sent */
99 MSG(WM_NCHITTEST)
100 MSG(WM_SETCURSOR)
101 MSG(WM_MOUSEACTIVATE)
102 MSG(WM_CHILDACTIVATE)
103 MSG(WM_COMMAND)
104 MSG(WM_SYSCOMMAND)
105
106 /* posted events */
107 MSG(WM_MOUSEMOVE)
108 MSG(WM_NCMOUSEMOVE)
109 MSG(WM_PAINT)
110 MSG(WM_LBUTTONDOWN)
111 MSG(WM_LBUTTONUP)
112 MSG(WM_LBUTTONDBLCLK)
113 MSG(WM_NCLBUTTONDOWN)
114 MSG(WM_NCLBUTTONUP)
115 MSG(WM_NCLBUTTONDBLCLK)
116
117 MSG(WM_KEYDOWN)
118 MSG(WM_KEYUP)
119 MSG(WM_CHAR)
120
121 #ifdef WIN32
122 MSG(WM_CTLCOLORBTN)
123 MSG(WM_CTLCOLORDLG)
124 MSG(WM_CTLCOLORSTATIC)
125 #else
126 MSG(WM_CTLCOLOR)
127 #endif
128
129 /* moving and sizing */
130 MSG2(WM_ENTERSIZEMOVE,0x0231)
131 MSG2(WM_EXITSIZEMOVE,0x0232)
132 #ifdef WIN32
133 MSG(WM_SIZING)
134 #endif
135
136 /* menus/dialog boxes */
137 MSG(WM_CANCELMODE)
138 MSG(WM_ENABLE)
139 MSG(WM_SETFONT)
140 MSG(WM_INITDIALOG)
141 MSG(WM_GETDLGCODE)
142 MSG(WM_ENTERIDLE)
143
144 /* scroll bars */
145 MSG(WM_HSCROLL)
146 MSG(WM_VSCROLL)
147
148 /* getting these from Wine but not from Windows */
149 MSG2(WM_SETVISIBLE,0x0009) /* unheard of in BC++ 4.52 */
150 #ifdef WIN32
151 MSG(WM_CAPTURECHANGED)
152 #endif
153
154 ENDMSG};
155
156 struct MSGNAMES ButMsgs[]={
157 MSG(BM_SETSTATE)
158 MSG(BM_SETSTYLE)
159
160 ENDMSG};
161
162 char*MsgName(UINT msg,HWND hWnd)
163 {
164  int i;
165  static char buffer[64],wclass[64];
166  GetClassName(hWnd,wclass,sizeof(wclass));
167
168 #define MSGSEARCH(msgs) { \
169   for (i=0; msgs[i].name&&msgs[i].msg!=msg; i++); \
170   if (msgs[i].name) return msgs[i].name; \
171  }
172
173  if (!stricmp(wclass,"Button")) MSGSEARCH(ButMsgs);
174  MSGSEARCH(MsgNames);
175  /* WM_USER */
176  if (msg>=WM_USER) {
177   sprintf(buffer,"WM_USER+%04x{%s}",msg-WM_USER,wclass);
178   return buffer;
179  }
180  /* message not found */
181  sprintf(buffer,"%04x{%s}",msg,wclass);
182  return buffer;
183 }
184
185 char*WndName(HWND hWnd,int state)
186 {
187  static char buffer[16];
188  if (!hWnd) return "0000";
189  if (hWnd==hMainWnd || (state==STATE_CREATE && !hMainWnd)) return "main";
190  if (hWnd==hSubWnd || (state==STATE_CREATE && !hSubWnd)) return "chld";
191  if (hWnd==hDialog || (state==STATE_DIALOG && !hDialog)) return "tdlg";
192  if (hWnd==hGroup) return "tgrp";
193  if (hWnd==hButton[0]) return "but1";
194  if (hWnd==hButton[1]) return "but2";
195  if (hWnd==hButton[2]) return "but3";
196  if (hWnd==hButton[3]) return "but4";
197  if (hWnd==hSubDlg || (state==STATE_CREATE && !hSubDlg)) return "sdlg";
198  if (hDialog) {
199   int id=GetDlgCtrlID(hWnd);
200   if (id) {
201    sprintf(buffer,"dlgitem(%d)",id);
202    return buffer;
203   }
204  }
205  sprintf(buffer,"%04x",hWnd);
206  return buffer;
207 }
208
209 void Log(const char*fmt)
210 {
211 #ifdef LOGGING
212  if (!Clicked) SendMessage(hListBox,LB_ADDSTRING,0,(LPARAM)fmt);
213 #endif
214 }
215
216 void Logf(const char*fmt,...)
217 {
218  va_list par;
219  static char buffer[256];
220
221  va_start(par,fmt);
222  vsprintf(buffer,fmt,par);
223  va_end(par);
224  Log(buffer);
225 }
226
227 void LogChildOrder(HWND hWnd)
228 {
229  HWND hWndChild = GetWindow(hWnd,GW_CHILD);
230  static char buffer[256];
231
232  strcpy(buffer,"child list:");
233  while (hWndChild) {
234   strcat(strcat(buffer," "),WndName(hWndChild,State));
235   hWndChild=GetWindow(hWndChild,GW_HWNDNEXT);
236  }
237  Log(buffer);
238 }
239
240 void LogMessage(int state,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam,char*name)
241 {
242  static char buffer[256];
243  DWORD tick=GetTickCount()-StartTime;
244  char*msgname=MsgName(msg,hWnd);
245  if (!name) name=WndName(hWnd,state);
246  switch (msg) {
247   case WM_SETFOCUS:
248   case WM_KILLFOCUS:
249   case WM_SETCURSOR:
250    Logf("%04d[%s(%d):%s]%s(%s,%08x)",tick,StateName[state],Rec,
251         name,msgname,WndName((HWND)wParam,State),lParam);
252    break;
253 #ifdef WIN32
254   case WM_ENTERIDLE:
255   case WM_CTLCOLORBTN:
256   case WM_CTLCOLORDLG:
257    Logf("%04d[%s(%d):%s]%s(%08x,%s)",tick,StateName[state],Rec,
258         name,msgname,wParam,WndName((HWND)lParam,State));
259    break;
260 #else
261   case WM_ENTERIDLE:
262   case WM_CTLCOLOR:
263    Logf("%04d[%s(%d):%s]%s(%08x,%04x:%s)",tick,StateName[state],Rec,
264         name,msgname,wParam,HIWORD(lParam),WndName((HWND)LOWORD(lParam),State));
265    break;
266 #endif
267   case WM_WINDOWPOSCHANGING:
268   case WM_WINDOWPOSCHANGED:
269    {
270     WINDOWPOS*pos=(WINDOWPOS*)lParam;
271 #ifdef WIN32
272          Logf("%04d[%s(%d):%s]%s(%08x,%p)",tick,StateName[state],Rec,
273                         name,msgname,wParam,pos);
274 #else
275          Logf("%04d[%s(%d):%s]%s(%04x,%p)",tick,StateName[state],Rec,
276                         name,msgname,wParam,pos);
277 #endif
278          strcpy(buffer,"FLAGS:");
279          if (pos->flags&SWP_DRAWFRAME) strcat(buffer," DRAWFRAME");
280          if (pos->flags&SWP_HIDEWINDOW) strcat(buffer," HIDEWINDOW");
281          if (pos->flags&SWP_NOACTIVATE) strcat(buffer," NOACTIVATE");
282          if (pos->flags&SWP_NOCOPYBITS) strcat(buffer," NOCOPYBITS");
283          if (pos->flags&SWP_NOMOVE) strcat(buffer," NOMOVE");
284          if (pos->flags&SWP_NOOWNERZORDER) strcat(buffer," NOOWNERZORDER");
285          if (pos->flags&SWP_NOSIZE) strcat(buffer," NOSIZE");
286          if (pos->flags&SWP_NOREDRAW) strcat(buffer," NOREDRAW");
287          if (pos->flags&SWP_NOZORDER) strcat(buffer," NOZORDER");
288          if (pos->flags&SWP_SHOWWINDOW) strcat(buffer," SHOWWINDOW");
289          Log(buffer);
290         }
291         break;
292   case WM_SYSCOMMAND:
293         {
294          char*cmd=NULL;
295          switch (wParam&0xFFF0) {
296 #define CASE(x) case SC_##x: cmd=#x; break;
297           CASE(CLOSE)
298           CASE(DEFAULT)
299           CASE(HOTKEY)
300           CASE(HSCROLL)
301           CASE(KEYMENU)
302           CASE(MAXIMIZE)
303           CASE(MINIMIZE)
304           CASE(MOUSEMENU)
305           CASE(MOVE)
306           CASE(NEXTWINDOW)
307           CASE(PREVWINDOW)
308           CASE(RESTORE)
309           CASE(SCREENSAVE)
310           CASE(SIZE)
311           CASE(TASKLIST)
312           CASE(VSCROLL)
313 #undef CASE
314          }
315          if (cmd) {
316           Logf("%04d[%s(%d):%s]%s(%s+%x,%08x)",tick,StateName[state],Rec,
317                          name,msgname,cmd,wParam&0xF,lParam);
318          } else goto GENERIC_MSG;
319         }
320         break;
321   case WM_HSCROLL:
322   case WM_VSCROLL:
323         {
324          char*cmd=NULL;
325          switch (LOWORD(wParam)) {
326 #define CASE(x) case SB_##x: cmd=#x; break;
327 #define CASE2(h,v) case SB_##h: if (msg==WM_HSCROLL) cmd=#h; else cmd=#v; break;
328           CASE(BOTTOM)
329           CASE(ENDSCROLL)
330           CASE2(LINELEFT,LINEUP)
331           CASE2(LINERIGHT,LINEDOWN)
332           CASE2(PAGELEFT,PAGEUP)
333           CASE2(PAGERIGHT,PAGEDOWN)
334           CASE(THUMBPOSITION)
335           CASE(THUMBTRACK)
336      CASE(TOP)
337 #undef CASE
338          }
339          if (cmd) {
340 #ifdef WIN32
341           Logf("%04d[%s(%d):%s]%s(%s,%04x,%s)",tick,StateName[state],Rec,
342                          name,msgname,cmd,HIWORD(wParam),WndName((HWND)lParam,State));
343 #else
344           Logf("%04d[%s(%d):%s]%s(%04x,%04x,%s)",tick,StateName[state],Rec,
345                          name,msgname,cmd,LOWORD(lParam),WndName((HWND)HIWORD(lParam),State));
346 #endif
347          } else goto GENERIC_MSG;
348         }
349         break;
350   default:
351 GENERIC_MSG:
352 #ifdef WIN32
353         Logf("%04d[%s(%d):%s]%s(%08x,%08x)",tick,StateName[state],Rec,
354                   name,msgname,wParam,lParam);
355 #else
356         Logf("%04d[%s(%d):%s]%s(%04x,%08x)",tick,StateName[state],Rec,
357                   name,msgname,wParam,lParam);
358 #endif
359  }
360 }
361
362 /***************************/
363 /*** GRAPHICS FACILITIES ***/
364 /***************************/
365
366 void Paint(HWND hWnd)
367 {
368  HDC dc;
369  PAINTSTRUCT ps;
370  dc=BeginPaint(hWnd,&ps);
371  EndPaint(hWnd,&ps);
372 }
373
374 void FillPattern(HWND hWnd,HDC pdc)
375 {
376  HDC dc=pdc?pdc:GetDC(hWnd);
377  HBRUSH oldbrush;
378  RECT rect;
379  if (!dc) {
380   Logf("failed to acquire DC for window %s",WndName(hWnd,State));
381   return;
382  } else {
383   Logf("acquired DC for %s window %s, painting",
384        IsWindowVisible(hWnd)?"visible":"invisible",WndName(hWnd,State));
385  }
386  GetClientRect(hWnd,&rect);
387  oldbrush=SelectObject(dc,GetStockObject(LTGRAY_BRUSH));
388  PatBlt(dc,0,0,rect.right,rect.bottom,PATCOPY);
389  SelectObject(dc,oldbrush);
390  if (!pdc) ReleaseDC(hWnd,dc);
391 }
392
393 void PaintPattern(HWND hWnd)
394 {
395  HDC dc;
396  PAINTSTRUCT ps;
397  dc=BeginPaint(hWnd,&ps);
398  FillPattern(hWnd,dc);
399  EndPaint(hWnd,&ps);
400 }
401
402 /*************************/
403 /*** WINDOW PROCEDURES ***/
404 /*************************/
405
406 /* MAIN WINDOW */
407 LRESULT FAR CALLBACK _export MainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
408 {
409  LRESULT lResult=0;
410  RECT rect;
411  int OldState=State;
412
413  State=STATE_RECURS; Rec++;
414  if (!Clicked) LogMessage(OldState,hWnd,msg,wParam,lParam,NULL);
415  switch (msg) {
416   case WM_NCHITTEST:
417    lResult=DefWindowProc(hWnd,msg,wParam,lParam);
418    break;
419   case WM_LBUTTONDOWN:
420   case WM_CHAR:
421    if (!Clicked) {
422     SetParent(hListBox,hWnd);
423     GetClientRect(hWnd,&rect);
424     MoveWindow(hListBox,0,0,rect.right,rect.bottom,TRUE);
425     ShowWindow(hListBox,SW_SHOW);
426     SetFocus(hListBox);
427     Clicked=TRUE;
428    }
429    break;
430   case WM_SIZE:
431    GetClientRect(hWnd,&rect);
432    if (Clicked) {
433     MoveWindow(hListBox,0,0,rect.right,rect.bottom,TRUE);
434    }
435    MoveWindow(hSubWnd,0,rect.bottom/2,rect.right,rect.bottom-(rect.bottom/2),TRUE);
436    break;
437   case WM_PAINT:
438    Paint(hWnd);
439    break;
440   case WM_DESTROY:
441    PostQuitMessage(0);
442    break;
443   default:
444    lResult=DefWindowProc(hWnd,msg,wParam,lParam);
445  }
446  State=OldState; Rec--;
447  return lResult;
448 }
449
450 /* CHILD WINDOW */
451 LRESULT FAR CALLBACK _export SubWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
452 {
453  LRESULT lResult=0;
454  RECT rect;
455  int OldState=State;
456
457  State=STATE_RECURS; Rec++;
458  if (!Clicked) LogMessage(OldState,hWnd,msg,wParam,lParam,NULL);
459  switch (msg) {
460   case WM_PAINT:
461    Paint(hWnd);
462    break;
463   default:
464    lResult=DefWindowProc(hWnd,msg,wParam,lParam);
465  }
466  State=OldState; Rec--;
467  return lResult;
468 }
469
470 BOOL FAR CALLBACK _export SubDialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
471
472 /* SUBCLASSED CONTROLS */
473 LRESULT FAR CALLBACK _export SubClassWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
474 {
475  LRESULT lResult=0;
476  RECT rect;
477  int OldState=State;
478  int But=-1;
479
480  if (hWnd==hButton[0]) But=0; else
481  if (hWnd==hButton[1]) But=1; else
482  if (hWnd==hButton[2]) But=2; else
483  if (hWnd==hButton[3]) But=3;
484
485  State=STATE_RECURS; Rec++;
486  if (!Clicked) {
487   LogMessage(OldState,hWnd,msg,wParam,lParam,NULL);
488   if (But!=-1) {
489    lResult=CallWindowProc((FARPROC)wndButton[But],hWnd,msg,wParam,lParam);
490    if (msg==WM_LBUTTONUP) {
491     LogChildOrder(GetParent(hWnd));
492    }
493   }
494   else if (hWnd==hDialog) {
495    lResult=CallWindowProc((FARPROC)wndDialog,hWnd,msg,wParam,lParam);
496   }
497   else if (hWnd==hSubDlg) {
498    lResult=CallWindowProc((FARPROC)wndSubDlg,hWnd,msg,wParam,lParam);
499   }
500   else if (hWnd==hGroup) {
501    lResult=CallWindowProc((FARPROC)wndGroup,hWnd,msg,wParam,lParam);
502    if (msg==WM_SETFOCUS) {
503     /* create subdialog */
504     if (hSubDlg) {
505 #if 0
506      SetRect(&rect,0,0,1,1);
507      InvalidateRect(hWnd,&rect,FALSE);
508 #endif
509     } else {
510 #ifdef TEST_SUBDIALOG
511      State=STATE_CREATE;
512      hSubDlg=CreateDialog(hInst,MAKEINTRESOURCE(2),hWnd,(FARPROC)SubDialogProc);
513      State=STATE_RECURS;
514 #else
515 #ifdef RESIZE_DIALOG
516      GetWindowRect(GetParent(hWnd),&rect);
517      rect.right++;
518      SetWindowPos(GetParent(hWnd),0,0,0,
519                   rect.right-rect.left,rect.bottom-rect.top,
520                   SWP_NOMOVE|SWP_NOZORDER);
521 #endif
522 #endif
523     }
524    }
525   }
526  }
527  State=OldState; Rec--;
528  return lResult;
529 }
530
531 /* MAIN DIALOG PROCEDURE */
532 BOOL FAR CALLBACK _export TestDialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
533 {
534  BOOL bResult=0;
535  RECT rect;
536  int OldState=State;
537  int But=-1;
538
539  State=STATE_RECURS; Rec++;
540  if (!Clicked) LogMessage(OldState,hWndDlg,msg,wParam,lParam,"dlgp");
541  switch (msg) {
542   case WM_INITDIALOG:
543    hDialog = hWndDlg;
544    /* subclass dialog window proc */
545    wndDialog = (WNDPROC)SetWindowLong(hDialog,GWL_WNDPROC,(LONG)SubClassWindowProc);
546    Logf("dialog visible=%s",IsWindowVisible(hWndDlg)?"TRUE":"FALSE");
547    /* subclass OK button */
548    hButton[3] = GetDlgItem(hWndDlg,IDOK);
549    wndButton[3] = (WNDPROC)SetWindowLong(hButton[3],GWL_WNDPROC,(LONG)SubClassWindowProc);
550    /* subclass group box */
551    hGroup = GetDlgItem(hWndDlg,IDC_GROUPBOX1);
552    wndGroup = (WNDPROC)SetWindowLong(hGroup,GWL_WNDPROC,(LONG)SubClassWindowProc);
553
554 #ifdef RESIZE_DIALOG
555    GetWindowRect(hWndDlg,&rect);
556    rect.right--;
557    SetWindowPos(hWndDlg,0,0,0,
558                 rect.right-rect.left,rect.bottom-rect.top,
559                 SWP_NOMOVE|SWP_NOZORDER);
560 //   ShowWindow(GetDlgItem(hWndDlg,IDCANCEL),SW_HIDE);
561 #endif
562
563    bResult=TRUE; /* we don't do SetFocus */
564    break;
565   case WM_PAINT:
566    PaintPattern(hWndDlg);
567    bResult=TRUE;
568    break;
569   case WM_COMMAND:
570    EndDialog(hWndDlg,LOWORD(wParam));
571    bResult=TRUE;
572    break;
573   case WM_CLOSE:
574    EndDialog(hWndDlg,IDCANCEL);
575    bResult=TRUE;
576    break;
577   case WM_NCDESTROY:
578    hDialog = 0;
579    break;
580  }
581  State=OldState; Rec--;
582  return bResult;
583 }
584
585 /* SUBDIALOG PROCEDURE */
586 BOOL FAR CALLBACK _export SubDialogProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
587 {
588  BOOL bResult=0;
589  RECT rect;
590  int OldState=State;
591  int But=-1;
592
593  State=STATE_RECURS; Rec++;
594  if (!Clicked) LogMessage(OldState,hWndDlg,msg,wParam,lParam,NULL);
595  switch (msg) {
596   case WM_INITDIALOG:
597    hSubDlg = hWndDlg;
598    /* subclass dialog window proc */
599    wndSubDlg = (WNDPROC)SetWindowLong(hDialog,GWL_WNDPROC,(LONG)SubClassWindowProc);
600
601    bResult=TRUE; /* we don't do SetFocus */
602    break;
603   case WM_NCDESTROY:
604    hSubDlg = 0;
605    break;
606  }
607  State=OldState; Rec--;
608  return bResult;
609 }
610
611 /********************/
612 /*** MAIN PROGRAM ***/
613 /********************/
614
615 BOOL AppInit(void)
616 {
617  WNDCLASS wclass;
618
619  wclass.style = CS_HREDRAW|CS_VREDRAW;
620  wclass.lpfnWndProc = MainWindowProc;
621  wclass.cbClsExtra = 0;
622  wclass.cbWndExtra = 0;
623  wclass.hInstance = hInst;
624  wclass.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(1));
625  wclass.hCursor = LoadCursor(0,IDC_ARROW);
626  wclass.hbrBackground = GetStockObject(WHITE_BRUSH);
627  wclass.lpszMenuName = NULL;
628  wclass.lpszClassName = wclassname;
629  if (!RegisterClass(&wclass)) return FALSE;
630  wclass.lpfnWndProc = SubWindowProc;
631  wclass.lpszClassName = wcclassname;
632  if (!RegisterClass(&wclass)) return FALSE;
633  return TRUE;
634 }
635
636 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
637                    LPSTR lpszCmdLine, int nCmdShow)
638 {
639  MSG msg;
640  RECT rect;
641
642  hInst = hInstance;
643  if (!hPrevInstance)
644   if (!AppInit())
645    return 0;
646
647  StartTime=GetTickCount();
648  hListBox = CreateWindow("LISTBOX","Messages",WS_BORDER|WS_VSCROLL|WS_CHILD|
649                                               LBS_HASSTRINGS|LBS_NOTIFY|LBS_WANTKEYBOARDINPUT,
650                          0,0,0,0,GetDesktopWindow(),0,hInst,0);
651  if (!hListBox) {
652   MessageBox(0,"Could not create list box","Error",MB_OK);
653  }
654
655  State=STATE_CREATE;
656  hMainWnd = CreateWindowEx(MAIN_EXSTYLE,wclassname,winname,MAIN_STYLE,
657                            CW_USEDEFAULT,0,400,300,0,0,hInst,0);
658  if (!hMainWnd) return 0;
659  State=STATE_SHOW;
660  ShowWindow(hMainWnd,nCmdShow);
661 #ifdef TEST_DESTROY_MAIN
662  State=STATE_DESTROY;
663  DestroyWindow(hMainWnd);
664  State=STATE_DIRECT;
665  while (GetMessage(&msg,0,0,0)) {
666   TranslateMessage(&msg);
667   State=STATE_DISPATCH;
668   DispatchMessage(&msg);
669   State=STATE_DIRECT;
670  }
671  State=STATE_CREATE;
672  hMainWnd = CreateWindowEx(MAIN_EXSTYLE,wclassname,winname,MAIN_STYLE,
673                            CW_USEDEFAULT,0,400,300,0,0,hInst,0);
674  if (!hMainWnd) return 0;
675  State=STATE_SHOW;
676  ShowWindow(hMainWnd,nCmdShow);
677 #endif
678 /* update, so no WM_PAINTs are pending */
679  State=STATE_UPDATE;
680 // UpdateWindow(hMainWnd);
681  Ready=TRUE;
682 /* fill client area with a pattern */
683  FillPattern(hMainWnd,0);
684 /* create subwindow */
685  State=STATE_CREATE;
686  GetClientRect(hMainWnd,&rect);
687  hSubWnd = CreateWindow(wcclassname,winname,WS_CHILD|WS_BORDER|WS_CLIPSIBLINGS,
688                         0,rect.bottom/2,rect.right,rect.bottom-(rect.bottom/2),hMainWnd,0,hInst,0);
689  if (!hSubWnd) return 0;
690 /* create buttons */
691  hButton[0] = CreateWindow("BUTTON","1",WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
692                            8,8,48,20,hMainWnd,0,hInst,0);
693  hButton[1] = CreateWindow("BUTTON","2",WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
694                            32,12,48,20,hMainWnd,0,hInst,0);
695  hButton[2] = CreateWindow("BUTTON","3",WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE,
696                            56,16,48,20,hMainWnd,0,hInst,0);
697 /* subclass them */
698  wndButton[0] = (WNDPROC)SetWindowLong(hButton[0],GWL_WNDPROC,(LONG)SubClassWindowProc);
699  wndButton[1] = (WNDPROC)SetWindowLong(hButton[1],GWL_WNDPROC,(LONG)SubClassWindowProc);
700  wndButton[2] = (WNDPROC)SetWindowLong(hButton[2],GWL_WNDPROC,(LONG)SubClassWindowProc);
701 /* show them */
702  State=STATE_UPDATE;
703  UpdateWindow(hButton[0]);
704  LogChildOrder(hMainWnd);
705  Logf("but1 visible=%d",IsWindowVisible(hButton[0]));
706
707 /* now reparent the button to our (invisible) subwindow */
708  State=STATE_TEST;
709  /* in different order, seeing who gets topmost */
710  SetParent(hButton[0],hSubWnd);
711  SetParent(hButton[2],hSubWnd);
712  SetParent(hButton[1],hSubWnd);
713  LogChildOrder(hSubWnd);
714 /* the button should now be invisible */
715  Logf("but1 visible=%d",IsWindowVisible(hButton[0]));
716 /* see if we can draw on them */
717  FillPattern(hButton[0],0);
718
719 #ifdef SHOW_SUB
720  State=STATE_SHOW;
721  ShowWindow(hSubWnd,SW_SHOWNORMAL);
722  State=STATE_UPDATE;
723  UpdateWindow(hSubWnd);
724  FillPattern(hSubWnd,0);
725 // InvalidateRect(hMainWnd,NULL,TRUE);
726  Logf("but1 visible=%d",IsWindowVisible(hButton[0]));
727 #endif
728
729 #ifdef TEST_DIALOG
730  State=STATE_DIALOG;
731  DialogBox(hInst,MAKEINTRESOURCE(1),hMainWnd,(FARPROC)TestDialogProc);
732 #endif
733 #ifdef TEST_COMMCTL
734  {
735   DWORD arr[16];
736   CHOOSECOLOR cc={sizeof(cc),0,hInst,0,arr,0};
737   ChooseColor(&cc);
738  }
739 #endif
740
741  State=STATE_DIRECT;
742  while (GetMessage(&msg,0,0,0)) {
743   TranslateMessage(&msg);
744   State=STATE_DISPATCH;
745   DispatchMessage(&msg);
746   State=STATE_DIRECT;
747  }
748  return 0;
749 }
750
751