user32: Pre-allocate the window procedure for the message class.
[wine] / dlls / user32 / defwnd.c
1 /*
2  * Default window procedure
3  *
4  * Copyright 1993, 1996 Alexandre Julliard
5  *           1995 Alex Korobka
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <string.h>
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winnls.h"
32 #include "win.h"
33 #include "user_private.h"
34 #include "controls.h"
35 #include "wine/unicode.h"
36 #include "wine/winuser16.h"
37 #include "wine/server.h"
38 #include "wine/exception.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
42
43   /* bits in the dwKeyData */
44 #define KEYDATA_ALT             0x2000
45 #define KEYDATA_PREVSTATE       0x4000
46
47 static short iF10Key = 0;
48 static short iMenuSysKey = 0;
49 static const WCHAR imm32W[] = { 'i','m','m','3','2','\0' };
50
51 /***********************************************************************
52  *           DEFWND_HandleWindowPosChanged
53  *
54  * Handle the WM_WINDOWPOSCHANGED message.
55  */
56 static void DEFWND_HandleWindowPosChanged( HWND hwnd, const WINDOWPOS *winpos )
57 {
58     RECT rect;
59     WND *wndPtr = WIN_GetPtr( hwnd );
60
61     rect = wndPtr->rectClient;
62     WIN_ReleasePtr( wndPtr );
63
64     if (!(winpos->flags & SWP_NOCLIENTMOVE))
65         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG(rect.left, rect.top));
66
67     if (!(winpos->flags & SWP_NOCLIENTSIZE) || (winpos->flags & SWP_STATECHANGED))
68     {
69         if (IsIconic( hwnd ))
70         {
71             SendMessageW( hwnd, WM_SIZE, SIZE_MINIMIZED, 0 );
72         }
73         else
74         {
75             WPARAM wp = IsZoomed( hwnd ) ? SIZE_MAXIMIZED : SIZE_RESTORED;
76
77             SendMessageW( hwnd, WM_SIZE, wp, MAKELONG(rect.right-rect.left, rect.bottom-rect.top) );
78         }
79     }
80 }
81
82
83 /***********************************************************************
84  *           DEFWND_SetTextA
85  *
86  * Set the window text.
87  */
88 static void DEFWND_SetTextA( HWND hwnd, LPCSTR text )
89 {
90     int count;
91     WCHAR *textW;
92     WND *wndPtr;
93
94     if (!text) text = "";
95     count = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 );
96
97     if (!(wndPtr = WIN_GetPtr( hwnd ))) return;
98     if ((textW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
99     {
100         HeapFree(GetProcessHeap(), 0, wndPtr->text);
101         wndPtr->text = textW;
102         MultiByteToWideChar( CP_ACP, 0, text, -1, textW, count );
103         SERVER_START_REQ( set_window_text )
104         {
105             req->handle = wine_server_user_handle( hwnd );
106             wine_server_add_data( req, textW, (count-1) * sizeof(WCHAR) );
107             wine_server_call( req );
108         }
109         SERVER_END_REQ;
110     }
111     else
112         ERR("Not enough memory for window text\n");
113     WIN_ReleasePtr( wndPtr );
114
115     USER_Driver->pSetWindowText( hwnd, textW );
116 }
117
118 /***********************************************************************
119  *           DEFWND_SetTextW
120  *
121  * Set the window text.
122  */
123 static void DEFWND_SetTextW( HWND hwnd, LPCWSTR text )
124 {
125     static const WCHAR empty_string[] = {0};
126     WND *wndPtr;
127     int count;
128
129     if (!text) text = empty_string;
130     count = strlenW(text) + 1;
131
132     if (!(wndPtr = WIN_GetPtr( hwnd ))) return;
133     HeapFree(GetProcessHeap(), 0, wndPtr->text);
134     if ((wndPtr->text = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
135     {
136         strcpyW( wndPtr->text, text );
137         SERVER_START_REQ( set_window_text )
138         {
139             req->handle = wine_server_user_handle( hwnd );
140             wine_server_add_data( req, wndPtr->text, (count-1) * sizeof(WCHAR) );
141             wine_server_call( req );
142         }
143         SERVER_END_REQ;
144     }
145     else
146         ERR("Not enough memory for window text\n");
147     text = wndPtr->text;
148     WIN_ReleasePtr( wndPtr );
149
150     USER_Driver->pSetWindowText( hwnd, text );
151 }
152
153 /***********************************************************************
154  *           DEFWND_ControlColor
155  *
156  * Default colors for control painting.
157  */
158 HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType )
159 {
160     if( ctlType == CTLCOLOR_SCROLLBAR)
161     {
162         HBRUSH hb = GetSysColorBrush(COLOR_SCROLLBAR);
163         COLORREF bk = GetSysColor(COLOR_3DHILIGHT);
164         SetTextColor( hDC, GetSysColor(COLOR_3DFACE));
165         SetBkColor( hDC, bk);
166
167         /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
168          * we better use 0x55aa bitmap brush to make scrollbar's background
169          * look different from the window background.
170          */
171         if (bk == GetSysColor(COLOR_WINDOW))
172             return SYSCOLOR_55AABrush;
173
174         UnrealizeObject( hb );
175         return hb;
176     }
177
178     SetTextColor( hDC, GetSysColor(COLOR_WINDOWTEXT));
179
180     if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX))
181         SetBkColor( hDC, GetSysColor(COLOR_WINDOW) );
182     else {
183         SetBkColor( hDC, GetSysColor(COLOR_3DFACE) );
184         return GetSysColorBrush(COLOR_3DFACE);
185     }
186     return GetSysColorBrush(COLOR_WINDOW);
187 }
188
189
190 /***********************************************************************
191  *           DEFWND_Print
192  *
193  * This method handles the default behavior for the WM_PRINT message.
194  */
195 static void DEFWND_Print( HWND hwnd, HDC hdc, ULONG uFlags)
196 {
197   /*
198    * Visibility flag.
199    */
200   if ( (uFlags & PRF_CHECKVISIBLE) &&
201        !IsWindowVisible(hwnd) )
202       return;
203
204   /*
205    * Unimplemented flags.
206    */
207   if ( (uFlags & PRF_CHILDREN) ||
208        (uFlags & PRF_OWNED)    ||
209        (uFlags & PRF_NONCLIENT) )
210   {
211     WARN("WM_PRINT message with unsupported flags\n");
212   }
213
214   /*
215    * Background
216    */
217   if ( uFlags & PRF_ERASEBKGND)
218     SendMessageW(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
219
220   /*
221    * Client area
222    */
223   if ( uFlags & PRF_CLIENT)
224     SendMessageW(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, uFlags);
225 }
226
227
228 /*
229  * helpers for calling IMM32
230  *
231  * WM_IME_* messages are generated only by IMM32,
232  * so I assume imm32 is already LoadLibrary-ed.
233  */
234 static HWND DEFWND_ImmGetDefaultIMEWnd( HWND hwnd )
235 {
236     HINSTANCE hInstIMM = GetModuleHandleW( imm32W );
237     HWND (WINAPI *pFunc)(HWND);
238     HWND hwndRet = 0;
239
240     if (!hInstIMM)
241     {
242         ERR( "cannot get IMM32 handle\n" );
243         return 0;
244     }
245
246     pFunc = (void*)GetProcAddress(hInstIMM,"ImmGetDefaultIMEWnd");
247     if ( pFunc != NULL )
248         hwndRet = (*pFunc)( hwnd );
249
250     return hwndRet;
251 }
252
253 static BOOL DEFWND_ImmIsUIMessageA( HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam )
254 {
255     HINSTANCE hInstIMM = GetModuleHandleW( imm32W );
256     BOOL (WINAPI *pFunc)(HWND,UINT,WPARAM,LPARAM);
257     BOOL fRet = FALSE;
258
259     if (!hInstIMM)
260     {
261         ERR( "cannot get IMM32 handle\n" );
262         return FALSE;
263     }
264
265     pFunc = (void*)GetProcAddress(hInstIMM,"ImmIsUIMessageA");
266     if ( pFunc != NULL )
267         fRet = (*pFunc)( hwndIME, msg, wParam, lParam );
268
269     return fRet;
270 }
271
272 static BOOL DEFWND_ImmIsUIMessageW( HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam )
273 {
274     HINSTANCE hInstIMM = GetModuleHandleW( imm32W );
275     BOOL (WINAPI *pFunc)(HWND,UINT,WPARAM,LPARAM);
276     BOOL fRet = FALSE;
277
278     if (!hInstIMM)
279     {
280         ERR( "cannot get IMM32 handle\n" );
281         return FALSE;
282     }
283
284     pFunc = (void*)GetProcAddress(hInstIMM,"ImmIsUIMessageW");
285     if ( pFunc != NULL )
286         fRet = (*pFunc)( hwndIME, msg, wParam, lParam );
287
288     return fRet;
289 }
290
291
292
293 /***********************************************************************
294  *           DEFWND_DefWinProc
295  *
296  * Default window procedure for messages that are the same in Ansi and Unicode.
297  */
298 static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
299 {
300     switch(msg)
301     {
302     case WM_NCPAINT:
303         return NC_HandleNCPaint( hwnd, (HRGN)wParam );
304
305     case WM_NCHITTEST:
306         {
307             POINT pt;
308             pt.x = (short)LOWORD(lParam);
309             pt.y = (short)HIWORD(lParam);
310             return NC_HandleNCHitTest( hwnd, pt );
311         }
312
313     case WM_NCCALCSIZE:
314         return NC_HandleNCCalcSize( hwnd, (RECT *)lParam );
315
316     case WM_WINDOWPOSCHANGING:
317         return WINPOS_HandleWindowPosChanging( hwnd, (WINDOWPOS *)lParam );
318
319     case WM_WINDOWPOSCHANGED:
320         DEFWND_HandleWindowPosChanged( hwnd, (const WINDOWPOS *)lParam );
321         break;
322
323     case WM_LBUTTONDOWN:
324     case WM_RBUTTONDOWN:
325     case WM_MBUTTONDOWN:
326         iF10Key = iMenuSysKey = 0;
327         break;
328
329     case WM_NCLBUTTONDOWN:
330         return NC_HandleNCLButtonDown( hwnd, wParam, lParam );
331
332     case WM_LBUTTONDBLCLK:
333         return NC_HandleNCLButtonDblClk( hwnd, HTCLIENT, lParam );
334
335     case WM_NCLBUTTONDBLCLK:
336         return NC_HandleNCLButtonDblClk( hwnd, wParam, lParam );
337
338     case WM_NCRBUTTONDOWN:
339         /* in Windows, capture is taken when right-clicking on the caption bar */
340         if (wParam==HTCAPTION)
341         {
342             SetCapture(hwnd);
343         }
344         break;
345
346     case WM_RBUTTONUP:
347         {
348             POINT pt;
349
350             if (hwnd == GetCapture())
351                 /* release capture if we took it on WM_NCRBUTTONDOWN */
352                 ReleaseCapture();
353
354             pt.x = (short)LOWORD(lParam);
355             pt.y = (short)HIWORD(lParam);
356             ClientToScreen(hwnd, &pt);
357             SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(pt.x, pt.y) );
358         }
359         break;
360
361     case WM_NCRBUTTONUP:
362         /*
363          * FIXME : we must NOT send WM_CONTEXTMENU on a WM_NCRBUTTONUP (checked
364          * in Windows), but what _should_ we do? According to MSDN :
365          * "If it is appropriate to do so, the system sends the WM_SYSCOMMAND
366          * message to the window". When is it appropriate?
367          */
368         break;
369
370     case WM_CONTEXTMENU:
371         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)
372             SendMessageW( GetParent(hwnd), msg, wParam, lParam );
373         else
374         {
375             LONG hitcode;
376             POINT pt;
377             WND *wndPtr = WIN_GetPtr( hwnd );
378             HMENU hMenu = wndPtr->hSysMenu;
379             WIN_ReleasePtr( wndPtr );
380             if (!hMenu) return 0;
381             pt.x = (short)LOWORD(lParam);
382             pt.y = (short)HIWORD(lParam);
383             hitcode = NC_HandleNCHitTest(hwnd, pt);
384
385             /* Track system popup if click was in the caption area. */
386             if (hitcode==HTCAPTION || hitcode==HTSYSMENU)
387                TrackPopupMenu(GetSystemMenu(hwnd, FALSE),
388                                TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
389                                pt.x, pt.y, 0, hwnd, NULL);
390         }
391         break;
392
393     case WM_POPUPSYSTEMMENU:
394         {
395             /* This is an undocumented message used by the windows taskbar to
396                display the system menu of windows that belong to other processes. */
397             HMENU menu = GetSystemMenu(hwnd, FALSE);
398
399             if (menu)
400                 TrackPopupMenu(menu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
401                                LOWORD(lParam), HIWORD(lParam), 0, hwnd, NULL);
402             return 0;
403         }
404
405     case WM_NCACTIVATE:
406         return NC_HandleNCActivate( hwnd, wParam, lParam );
407
408     case WM_NCDESTROY:
409         {
410             WND *wndPtr = WIN_GetPtr( hwnd );
411             if (!wndPtr) return 0;
412             HeapFree( GetProcessHeap(), 0, wndPtr->text );
413             wndPtr->text = NULL;
414             HeapFree( GetProcessHeap(), 0, wndPtr->pScroll );
415             wndPtr->pScroll = NULL;
416             WIN_ReleasePtr( wndPtr );
417             return 0;
418         }
419
420     case WM_PRINT:
421         DEFWND_Print(hwnd, (HDC)wParam, lParam);
422         return 0;
423
424     case WM_PAINTICON:
425     case WM_PAINT:
426         {
427             PAINTSTRUCT ps;
428             HDC hdc = BeginPaint( hwnd, &ps );
429             if( hdc )
430             {
431               HICON hIcon;
432               if (IsIconic(hwnd) && ((hIcon = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON))) )
433               {
434                   RECT rc;
435                   int x, y;
436
437                   GetClientRect( hwnd, &rc );
438                   x = (rc.right - rc.left - GetSystemMetrics(SM_CXICON))/2;
439                   y = (rc.bottom - rc.top - GetSystemMetrics(SM_CYICON))/2;
440                   TRACE("Painting class icon: vis rect=(%s)\n",
441                         wine_dbgstr_rect(&ps.rcPaint));
442                   DrawIcon( hdc, x, y, hIcon );
443               }
444               EndPaint( hwnd, &ps );
445             }
446             return 0;
447         }
448
449     case WM_SYNCPAINT:
450         RedrawWindow ( hwnd, NULL, 0, RDW_ERASENOW | RDW_ERASE | RDW_ALLCHILDREN );
451         return 0;
452
453     case WM_SETREDRAW:
454         if (wParam) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
455         else
456         {
457             RedrawWindow( hwnd, NULL, 0, RDW_ALLCHILDREN | RDW_VALIDATE );
458             WIN_SetStyle( hwnd, 0, WS_VISIBLE );
459         }
460         return 0;
461
462     case WM_CLOSE:
463         DestroyWindow( hwnd );
464         return 0;
465
466     case WM_MOUSEACTIVATE:
467         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)
468         {
469             LONG ret = SendMessageW( GetParent(hwnd), WM_MOUSEACTIVATE, wParam, lParam );
470             if (ret) return ret;
471         }
472
473         /* Caption clicks are handled by NC_HandleNCLButtonDown() */
474         return MA_ACTIVATE;
475
476     case WM_ACTIVATE:
477         /* The default action in Windows is to set the keyboard focus to
478          * the window, if it's being activated and not minimized */
479         if (LOWORD(wParam) != WA_INACTIVE) {
480             if (!IsIconic(hwnd)) SetFocus(hwnd);
481         }
482         break;
483
484     case WM_MOUSEWHEEL:
485         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)
486             return SendMessageW( GetParent(hwnd), WM_MOUSEWHEEL, wParam, lParam );
487         break;
488
489     case WM_ERASEBKGND:
490     case WM_ICONERASEBKGND:
491         {
492             RECT rect;
493             HDC hdc = (HDC)wParam;
494             HBRUSH hbr = (HBRUSH)GetClassLongPtrW( hwnd, GCLP_HBRBACKGROUND );
495             if (!hbr) return 0;
496
497             if (GetClassLongW( hwnd, GCL_STYLE ) & CS_PARENTDC)
498             {
499                 /* can't use GetClipBox with a parent DC or we fill the whole parent */
500                 GetClientRect( hwnd, &rect );
501                 DPtoLP( hdc, (LPPOINT)&rect, 2 );
502             }
503             else GetClipBox( hdc, &rect );
504             FillRect( hdc, &rect, hbr );
505             return 1;
506         }
507
508     case WM_GETDLGCODE:
509         return 0;
510
511     case WM_CTLCOLORMSGBOX:
512     case WM_CTLCOLOREDIT:
513     case WM_CTLCOLORLISTBOX:
514     case WM_CTLCOLORBTN:
515     case WM_CTLCOLORDLG:
516     case WM_CTLCOLORSTATIC:
517     case WM_CTLCOLORSCROLLBAR:
518         return (LRESULT)DEFWND_ControlColor( (HDC)wParam, msg - WM_CTLCOLORMSGBOX );
519
520     case WM_CTLCOLOR:
521         return (LRESULT)DEFWND_ControlColor( (HDC)wParam, HIWORD(lParam) );
522
523     case WM_SETCURSOR:
524         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)
525         {
526             /* with the exception of the border around a resizable wnd,
527              * give the parent first chance to set the cursor */
528             if ((LOWORD(lParam) < HTSIZEFIRST) || (LOWORD(lParam) > HTSIZELAST))
529             {
530                 if (SendMessageW(GetParent(hwnd), WM_SETCURSOR, wParam, lParam)) return TRUE;
531             }
532         }
533         NC_HandleSetCursor( hwnd, wParam, lParam );
534         break;
535
536     case WM_SYSCOMMAND:
537         return NC_HandleSysCommand( hwnd, wParam, lParam );
538
539     case WM_KEYDOWN:
540         if(wParam == VK_F10) iF10Key = VK_F10;
541         break;
542
543     case WM_SYSKEYDOWN:
544         if( HIWORD(lParam) & KEYDATA_ALT )
545         {
546             /* if( HIWORD(lParam) & ~KEYDATA_PREVSTATE ) */
547               if ( (wParam == VK_MENU || wParam == VK_LMENU
548                     || wParam == VK_RMENU) && !iMenuSysKey )
549                 iMenuSysKey = 1;
550               else
551                 iMenuSysKey = 0;
552
553             iF10Key = 0;
554
555             if( wParam == VK_F4 )       /* try to close the window */
556             {
557                 HWND top = GetAncestor( hwnd, GA_ROOT );
558                 if (!(GetClassLongW( top, GCL_STYLE ) & CS_NOCLOSE))
559                     PostMessageW( top, WM_SYSCOMMAND, SC_CLOSE, 0 );
560             }
561         }
562         else if( wParam == VK_F10 )
563             iF10Key = 1;
564         else if( wParam == VK_ESCAPE && (GetKeyState(VK_SHIFT) & 0x8000))
565             SendMessageW( hwnd, WM_SYSCOMMAND, SC_KEYMENU, ' ' );
566         break;
567
568     case WM_KEYUP:
569     case WM_SYSKEYUP:
570         /* Press and release F10 or ALT */
571         if (((wParam == VK_MENU || wParam == VK_LMENU || wParam == VK_RMENU)
572              && iMenuSysKey) || ((wParam == VK_F10) && iF10Key))
573               SendMessageW( GetAncestor( hwnd, GA_ROOT ), WM_SYSCOMMAND, SC_KEYMENU, 0L );
574         iMenuSysKey = iF10Key = 0;
575         break;
576
577     case WM_SYSCHAR:
578     {
579         iMenuSysKey = 0;
580         if (wParam == '\r' && IsIconic(hwnd))
581         {
582             PostMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0L );
583             break;
584         }
585         if ((HIWORD(lParam) & KEYDATA_ALT) && wParam)
586         {
587             if (wParam == '\t' || wParam == '\x1b') break;
588             if (wParam == ' ' && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD))
589                 SendMessageW( GetParent(hwnd), msg, wParam, lParam );
590             else
591                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_KEYMENU, wParam );
592         }
593         else /* check for Ctrl-Esc */
594             if (wParam != '\x1b') MessageBeep(0);
595         break;
596     }
597
598     case WM_SHOWWINDOW:
599         {
600             LONG style = GetWindowLongW( hwnd, GWL_STYLE );
601             WND *pWnd;
602             if (!lParam) return 0; /* sent from ShowWindow */
603             if ((style & WS_VISIBLE) && wParam) return 0;
604             if (!(style & WS_VISIBLE) && !wParam) return 0;
605             if (!GetWindow( hwnd, GW_OWNER )) return 0;
606             if (!(pWnd = WIN_GetPtr( hwnd ))) return 0;
607             if (pWnd == WND_OTHER_PROCESS) return 0;
608             if (wParam)
609             {
610                 if (!(pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP))
611                 {
612                     WIN_ReleasePtr( pWnd );
613                     return 0;
614                 }
615                 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
616             }
617             else pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
618             WIN_ReleasePtr( pWnd );
619             ShowWindow( hwnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE );
620             break;
621         }
622
623     case WM_CANCELMODE:
624         iMenuSysKey = 0;
625         MENU_EndMenu( hwnd );
626         if (GetCapture() == hwnd) ReleaseCapture();
627         break;
628
629     case WM_VKEYTOITEM:
630     case WM_CHARTOITEM:
631         return -1;
632
633     case WM_DROPOBJECT:
634         return DRAG_FILE;
635
636     case WM_QUERYDROPOBJECT:
637         return (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
638
639     case WM_QUERYDRAGICON:
640         {
641             UINT len;
642
643             HICON hIcon = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON );
644             HINSTANCE instance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
645             if (hIcon) return (LRESULT)hIcon;
646             for(len=1; len<64; len++)
647                 if((hIcon = LoadIconW(instance, MAKEINTRESOURCEW(len))))
648                     return (LRESULT)hIcon;
649             return (LRESULT)LoadIconW(0, (LPWSTR)IDI_APPLICATION);
650         }
651         break;
652
653     case WM_ISACTIVEICON:
654         {
655             WND *wndPtr = WIN_GetPtr( hwnd );
656             BOOL ret = (wndPtr->flags & WIN_NCACTIVATED) != 0;
657             WIN_ReleasePtr( wndPtr );
658             return ret;
659         }
660
661     case WM_NOTIFYFORMAT:
662       if (IsWindowUnicode(hwnd)) return NFR_UNICODE;
663       else return NFR_ANSI;
664
665     case WM_QUERYOPEN:
666     case WM_QUERYENDSESSION:
667         return 1;
668
669     case WM_SETICON:
670         {
671             HICON ret;
672             WND *wndPtr = WIN_GetPtr( hwnd );
673
674             switch(wParam)
675             {
676             case ICON_SMALL:
677                 ret = wndPtr->hIconSmall;
678                 wndPtr->hIconSmall = (HICON)lParam;
679                 break;
680             case ICON_BIG:
681                 ret = wndPtr->hIcon;
682                 wndPtr->hIcon = (HICON)lParam;
683                 break;
684             default:
685                 ret = 0;
686                 break;
687             }
688             WIN_ReleasePtr( wndPtr );
689
690             USER_Driver->pSetWindowIcon( hwnd, wParam, (HICON)lParam );
691
692             if( (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION )
693                 NC_HandleNCPaint( hwnd , (HRGN)1 );  /* Repaint caption */
694
695             return (LRESULT)ret;
696         }
697
698     case WM_GETICON:
699         {
700             HICON ret;
701             WND *wndPtr = WIN_GetPtr( hwnd );
702
703             switch(wParam)
704             {
705             case ICON_SMALL:
706                 ret = wndPtr->hIconSmall;
707                 break;
708             case ICON_BIG:
709                 ret = wndPtr->hIcon;
710                 break;
711             case ICON_SMALL2:
712                 ret = wndPtr->hIconSmall;
713                 if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICONSM );
714                 /* FIXME: should have a default here if class icon is null */
715                 break;
716             default:
717                 ret = 0;
718                 break;
719             }
720             WIN_ReleasePtr( wndPtr );
721             return (LRESULT)ret;
722         }
723
724     case WM_HELP:
725         SendMessageW( GetParent(hwnd), msg, wParam, lParam );
726         break;
727
728     case WM_APPCOMMAND:
729         {
730             HWND parent = GetParent(hwnd);
731             if(!parent)
732                 HOOK_CallHooks(WH_SHELL, HSHELL_APPCOMMAND, wParam, lParam, TRUE);
733             else
734                 SendMessageW( parent, msg, wParam, lParam );
735             break;
736         }
737     case WM_KEYF1:
738         {
739             HELPINFO hi;
740
741             hi.cbSize = sizeof(HELPINFO);
742             GetCursorPos( &hi.MousePos );
743             if (MENU_IsMenuActive())
744             {
745                 hi.iContextType = HELPINFO_MENUITEM;
746                 hi.hItemHandle = MENU_IsMenuActive();
747                 hi.iCtrlId = MenuItemFromPoint( hwnd, hi.hItemHandle, hi.MousePos );
748                 hi.dwContextId = GetMenuContextHelpId( hi.hItemHandle );
749             }
750             else
751             {
752                 hi.iContextType = HELPINFO_WINDOW;
753                 hi.hItemHandle = hwnd;
754                 hi.iCtrlId = GetWindowLongPtrA( hwnd, GWLP_ID );
755                 hi.dwContextId = GetWindowContextHelpId( hwnd );
756             }
757             SendMessageW( hwnd, WM_HELP, 0, (LPARAM)&hi );
758             break;
759         }
760
761     case WM_INPUTLANGCHANGEREQUEST:
762         ActivateKeyboardLayout( (HKL)lParam, 0 );
763         break;
764
765     case WM_INPUTLANGCHANGE:
766         {
767             int count = 0;
768             HWND *win_array = WIN_ListChildren( hwnd );
769
770             if (!win_array)
771                 break;
772             while (win_array[count])
773                 SendMessageW( win_array[count++], WM_INPUTLANGCHANGE, wParam, lParam);
774             HeapFree(GetProcessHeap(),0,win_array);
775             break;
776         }
777
778     }
779
780     return 0;
781 }
782
783 static LPARAM DEFWND_GetTextA( WND *wndPtr, LPSTR dest, WPARAM wParam )
784 {
785     LPARAM result = 0;
786
787     __TRY
788     {
789         if (wndPtr->text)
790         {
791             if (!WideCharToMultiByte( CP_ACP, 0, wndPtr->text, -1,
792                                       dest, wParam, NULL, NULL )) dest[wParam-1] = 0;
793             result = strlen( dest );
794         }
795         else dest[0] = '\0';
796     }
797     __EXCEPT_PAGE_FAULT
798     {
799         return 0;
800     }
801     __ENDTRY
802     return result;
803 }
804
805 /***********************************************************************
806  *              DefWindowProcA (USER32.@)
807  *
808  * See DefWindowProcW.
809  */
810 LRESULT WINAPI DefWindowProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
811 {
812     LRESULT result = 0;
813     HWND full_handle;
814
815     if (!(full_handle = WIN_IsCurrentProcess( hwnd )))
816     {
817         if (!IsWindow( hwnd )) return 0;
818         ERR( "called for other process window %p\n", hwnd );
819         return 0;
820     }
821     hwnd = full_handle;
822
823     SPY_EnterMessage( SPY_DEFWNDPROC, hwnd, msg, wParam, lParam );
824
825     switch(msg)
826     {
827     case WM_NCCREATE:
828         if (lParam)
829         {
830             CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam;
831             /* check for string, as static icons, bitmaps (SS_ICON, SS_BITMAP)
832              * may have child window IDs instead of window name */
833             if (HIWORD(cs->lpszName))
834                 DEFWND_SetTextA( hwnd, cs->lpszName );
835             result = 1;
836         }
837         break;
838
839     case WM_GETTEXTLENGTH:
840         {
841             WND *wndPtr = WIN_GetPtr( hwnd );
842             if (wndPtr && wndPtr->text)
843                 result = WideCharToMultiByte( CP_ACP, 0, wndPtr->text, strlenW(wndPtr->text),
844                                               NULL, 0, NULL, NULL );
845             WIN_ReleasePtr( wndPtr );
846         }
847         break;
848
849     case WM_GETTEXT:
850         if (wParam)
851         {
852             LPSTR dest = (LPSTR)lParam;
853             WND *wndPtr = WIN_GetPtr( hwnd );
854
855             if (!wndPtr) break;
856             result = DEFWND_GetTextA( wndPtr, dest, wParam );
857
858             WIN_ReleasePtr( wndPtr );
859         }
860         break;
861
862     case WM_SETTEXT:
863         DEFWND_SetTextA( hwnd, (LPCSTR)lParam );
864         if( (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION )
865             NC_HandleNCPaint( hwnd , (HRGN)1 );  /* Repaint caption */
866         result = 1; /* success. FIXME: check text length */
867         break;
868
869     case WM_IME_CHAR:
870         if (HIBYTE(wParam)) PostMessageA( hwnd, WM_CHAR, HIBYTE(wParam), lParam );
871         PostMessageA( hwnd, WM_CHAR, LOBYTE(wParam), lParam );
872         break;
873
874     case WM_IME_KEYDOWN:
875         result = PostMessageA( hwnd, WM_KEYDOWN, wParam, lParam );
876         break;
877
878     case WM_IME_KEYUP:
879         result = PostMessageA( hwnd, WM_KEYUP, wParam, lParam );
880         break;
881
882     case WM_IME_STARTCOMPOSITION:
883     case WM_IME_COMPOSITION:
884     case WM_IME_ENDCOMPOSITION:
885     case WM_IME_SELECT:
886     case WM_IME_NOTIFY:
887         {
888             HWND hwndIME;
889
890             hwndIME = DEFWND_ImmGetDefaultIMEWnd( hwnd );
891             if (hwndIME)
892                 result = SendMessageA( hwndIME, msg, wParam, lParam );
893         }
894         break;
895     case WM_IME_SETCONTEXT:
896         {
897             HWND hwndIME;
898
899             hwndIME = DEFWND_ImmGetDefaultIMEWnd( hwnd );
900             if (hwndIME)
901                 result = DEFWND_ImmIsUIMessageA( hwndIME, msg, wParam, lParam );
902         }
903         break;
904
905     case WM_SYSCHAR:
906     {
907         CHAR ch = LOWORD(wParam);
908         WCHAR wch;
909         MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
910         wParam = MAKEWPARAM( wch, HIWORD(wParam) );
911     }
912     /* fall through */
913     default:
914         result = DEFWND_DefWinProc( hwnd, msg, wParam, lParam );
915         break;
916     }
917
918     SPY_ExitMessage( SPY_RESULT_DEFWND, hwnd, msg, result, wParam, lParam );
919     return result;
920 }
921
922
923 static LPARAM DEFWND_GetTextW( WND *wndPtr, LPWSTR dest, WPARAM wParam )
924 {
925     LPARAM result = 0;
926
927     __TRY
928     {
929         if (wndPtr->text)
930         {
931             lstrcpynW( dest, wndPtr->text, wParam );
932             result = strlenW( dest );
933         }
934         else dest[0] = '\0';
935     }
936     __EXCEPT_PAGE_FAULT
937     {
938         return 0;
939     }
940     __ENDTRY
941
942     return result;
943 }
944
945 /***********************************************************************
946  *              DefWindowProcW (USER32.@) Calls default window message handler
947  *
948  * Calls default window procedure for messages not processed
949  *  by application.
950  *
951  *  RETURNS
952  *     Return value is dependent upon the message.
953 */
954 LRESULT WINAPI DefWindowProcW(
955     HWND hwnd,      /* [in] window procedure receiving message */
956     UINT msg,       /* [in] message identifier */
957     WPARAM wParam,  /* [in] first message parameter */
958     LPARAM lParam )   /* [in] second message parameter */
959 {
960     LRESULT result = 0;
961     HWND full_handle;
962
963     if (!(full_handle = WIN_IsCurrentProcess( hwnd )))
964     {
965         if (!IsWindow( hwnd )) return 0;
966         ERR( "called for other process window %p\n", hwnd );
967         return 0;
968     }
969     hwnd = full_handle;
970     SPY_EnterMessage( SPY_DEFWNDPROC, hwnd, msg, wParam, lParam );
971
972     switch(msg)
973     {
974     case WM_NCCREATE:
975         if (lParam)
976         {
977             CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
978             /* check for string, as static icons, bitmaps (SS_ICON, SS_BITMAP)
979              * may have child window IDs instead of window name */
980             if (HIWORD(cs->lpszName))
981                 DEFWND_SetTextW( hwnd, cs->lpszName );
982             result = 1;
983         }
984         break;
985
986     case WM_GETTEXTLENGTH:
987         {
988             WND *wndPtr = WIN_GetPtr( hwnd );
989             if (wndPtr && wndPtr->text) result = (LRESULT)strlenW(wndPtr->text);
990             WIN_ReleasePtr( wndPtr );
991         }
992         break;
993
994     case WM_GETTEXT:
995         if (wParam)
996         {
997             LPWSTR dest = (LPWSTR)lParam;
998             WND *wndPtr = WIN_GetPtr( hwnd );
999
1000             if (!wndPtr) break;
1001             result = DEFWND_GetTextW( wndPtr, dest, wParam );
1002             WIN_ReleasePtr( wndPtr );
1003         }
1004         break;
1005
1006     case WM_SETTEXT:
1007         DEFWND_SetTextW( hwnd, (LPCWSTR)lParam );
1008         if( (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CAPTION) == WS_CAPTION )
1009             NC_HandleNCPaint( hwnd , (HRGN)1 );  /* Repaint caption */
1010         result = 1; /* success. FIXME: check text length */
1011         break;
1012
1013     case WM_IME_CHAR:
1014         PostMessageW( hwnd, WM_CHAR, wParam, lParam );
1015         break;
1016
1017     case WM_IME_KEYDOWN:
1018         result = PostMessageW( hwnd, WM_KEYDOWN, wParam, lParam );
1019         break;
1020
1021     case WM_IME_KEYUP:
1022         result = PostMessageW( hwnd, WM_KEYUP, wParam, lParam );
1023         break;
1024
1025     case WM_IME_SETCONTEXT:
1026         {
1027             HWND hwndIME;
1028
1029             hwndIME = DEFWND_ImmGetDefaultIMEWnd( hwnd );
1030             if (hwndIME)
1031                 result = DEFWND_ImmIsUIMessageW( hwndIME, msg, wParam, lParam );
1032         }
1033         break;
1034
1035     case WM_IME_STARTCOMPOSITION:
1036     case WM_IME_COMPOSITION:
1037     case WM_IME_ENDCOMPOSITION:
1038     case WM_IME_SELECT:
1039     case WM_IME_NOTIFY:
1040         {
1041             HWND hwndIME;
1042
1043             hwndIME = DEFWND_ImmGetDefaultIMEWnd( hwnd );
1044             if (hwndIME)
1045                 result = SendMessageW( hwndIME, msg, wParam, lParam );
1046         }
1047         break;
1048
1049     default:
1050         result = DEFWND_DefWinProc( hwnd, msg, wParam, lParam );
1051         break;
1052     }
1053     SPY_ExitMessage( SPY_RESULT_DEFWND, hwnd, msg, result, wParam, lParam );
1054     return result;
1055 }