Added a few more Unicode digits from Unicode version 4.1.
[wine] / dlls / user / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "user_private.h"
37 #include "controls.h"
38 #include "winpos.h"
39 #include "winerror.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(win);
43
44 #define NB_USER_HANDLES  ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
45 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
46
47 /**********************************************************************/
48
49
50 static void *user_handles[NB_USER_HANDLES];
51
52 /***********************************************************************
53  *           create_window_handle
54  *
55  * Create a window handle with the server.
56  */
57 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
58                                   HINSTANCE instance, WINDOWPROCTYPE type )
59 {
60     WORD index;
61     WND *win;
62     struct tagCLASS *class = NULL;
63     user_handle_t handle = 0;
64     int extra_bytes = 0;
65
66     /* if 16-bit instance, map to module handle */
67     if (instance && !HIWORD(instance))
68         instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
69
70     SERVER_START_REQ( create_window )
71     {
72         req->parent   = parent;
73         req->owner    = owner;
74         req->atom     = atom;
75         req->instance = instance;
76         if (!wine_server_call_err( req ))
77         {
78             handle = reply->handle;
79             extra_bytes = reply->extra;
80             class = reply->class_ptr;
81         }
82     }
83     SERVER_END_REQ;
84
85     if (!handle)
86     {
87         WARN( "error %ld creating window\n", GetLastError() );
88         return NULL;
89     }
90
91     if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
92     {
93         SERVER_START_REQ( destroy_window )
94         {
95             req->handle = handle;
96             wine_server_call( req );
97         }
98         SERVER_END_REQ;
99         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
100         return NULL;
101     }
102
103     USER_Lock();
104
105     index = USER_HANDLE_TO_INDEX(handle);
106     assert( index < NB_USER_HANDLES );
107     user_handles[index] = win;
108     win->hwndSelf   = handle;
109     win->dwMagic    = WND_MAGIC;
110     win->cbWndExtra = extra_bytes;
111     memset( win->wExtra, 0, extra_bytes );
112     CLASS_AddWindow( class, win, type );
113     return win;
114 }
115
116
117 /***********************************************************************
118  *           free_window_handle
119  *
120  * Free a window handle.
121  */
122 static WND *free_window_handle( HWND hwnd )
123 {
124     WND *ptr;
125     WORD index = USER_HANDLE_TO_INDEX(hwnd);
126
127     if (index >= NB_USER_HANDLES) return NULL;
128     USER_Lock();
129     if ((ptr = user_handles[index]))
130     {
131         SERVER_START_REQ( destroy_window )
132         {
133             req->handle = hwnd;
134             if (!wine_server_call_err( req ))
135             {
136                 user_handles[index] = NULL;
137                 ptr->dwMagic = 0;
138             }
139             else
140                 ptr = NULL;
141         }
142         SERVER_END_REQ;
143     }
144     USER_Unlock();
145     HeapFree( GetProcessHeap(), 0, ptr );
146     return ptr;
147 }
148
149
150 /*******************************************************************
151  *           list_window_children
152  *
153  * Build an array of the children of a given window. The array must be
154  * freed with HeapFree. Returns NULL when no windows are found.
155  */
156 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
157 {
158     HWND *list;
159     int size = 32;
160
161     for (;;)
162     {
163         int count = 0;
164
165         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
166
167         SERVER_START_REQ( get_window_children )
168         {
169             req->parent = hwnd;
170             req->atom = atom;
171             req->tid = tid;
172             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
173             if (!wine_server_call( req )) count = reply->count;
174         }
175         SERVER_END_REQ;
176         if (count && count < size)
177         {
178             list[count] = 0;
179             return list;
180         }
181         HeapFree( GetProcessHeap(), 0, list );
182         if (!count) break;
183         size = count + 1;  /* restart with a large enough buffer */
184     }
185     return NULL;
186 }
187
188
189 /*******************************************************************
190  *           list_window_parents
191  *
192  * Build an array of all parents of a given window, starting with
193  * the immediate parent. The array must be freed with HeapFree.
194  * Returns NULL if window is a top-level window.
195  */
196 static HWND *list_window_parents( HWND hwnd )
197 {
198     WND *win;
199     HWND current, *list;
200     int pos = 0, size = 16, count = 0;
201
202     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
203
204     current = hwnd;
205     for (;;)
206     {
207         if (!(win = WIN_GetPtr( current ))) goto empty;
208         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
209         if (win == WND_DESKTOP)
210         {
211             if (!pos) goto empty;
212             list[pos] = 0;
213             return list;
214         }
215         list[pos] = current = win->parent;
216         WIN_ReleasePtr( win );
217         if (++pos == size - 1)
218         {
219             /* need to grow the list */
220             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
221             if (!new_list) goto empty;
222             list = new_list;
223             size += 16;
224         }
225     }
226
227     /* at least one parent belongs to another process, have to query the server */
228
229     for (;;)
230     {
231         count = 0;
232         SERVER_START_REQ( get_window_parents )
233         {
234             req->handle = hwnd;
235             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
236             if (!wine_server_call( req )) count = reply->count;
237         }
238         SERVER_END_REQ;
239         if (!count) goto empty;
240         if (size > count)
241         {
242             list[count] = 0;
243             return list;
244         }
245         HeapFree( GetProcessHeap(), 0, list );
246         size = count + 1;
247         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
248     }
249
250  empty:
251     HeapFree( GetProcessHeap(), 0, list );
252     return NULL;
253 }
254
255
256 /*******************************************************************
257  *           send_parent_notify
258  */
259 static void send_parent_notify( HWND hwnd, UINT msg )
260 {
261     if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
262         !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
263         SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
264                       MAKEWPARAM( msg, GetWindowLongPtrW( hwnd, GWLP_ID )), (LPARAM)hwnd );
265 }
266
267
268 /*******************************************************************
269  *              get_server_window_text
270  *
271  * Retrieve the window text from the server.
272  */
273 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
274 {
275     size_t len = 0;
276
277     SERVER_START_REQ( get_window_text )
278     {
279         req->handle = hwnd;
280         wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
281         if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
282     }
283     SERVER_END_REQ;
284     text[len / sizeof(WCHAR)] = 0;
285 }
286
287
288 /***********************************************************************
289  *           WIN_GetPtr
290  *
291  * Return a pointer to the WND structure if local to the process,
292  * or WND_OTHER_PROCESS if handle may be valid in other process.
293  * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
294  */
295 WND *WIN_GetPtr( HWND hwnd )
296 {
297     WND * ptr;
298     WORD index = USER_HANDLE_TO_INDEX(hwnd);
299
300     if (index >= NB_USER_HANDLES) return NULL;
301
302     USER_Lock();
303     if ((ptr = user_handles[index]))
304     {
305         if (ptr->dwMagic == WND_MAGIC &&
306             (hwnd == ptr->hwndSelf || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff))
307             return ptr;
308         ptr = NULL;
309     }
310     else if (index == USER_HANDLE_TO_INDEX(GetDesktopWindow()))
311     {
312         if (hwnd == GetDesktopWindow() || !HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) ptr = WND_DESKTOP;
313         else ptr = NULL;
314     }
315     else ptr = WND_OTHER_PROCESS;
316     USER_Unlock();
317     return ptr;
318 }
319
320
321 /***********************************************************************
322  *           WIN_IsCurrentProcess
323  *
324  * Check whether a given window belongs to the current process (and return the full handle).
325  */
326 HWND WIN_IsCurrentProcess( HWND hwnd )
327 {
328     WND *ptr;
329     HWND ret;
330
331     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
332     ret = ptr->hwndSelf;
333     WIN_ReleasePtr( ptr );
334     return ret;
335 }
336
337
338 /***********************************************************************
339  *           WIN_IsCurrentThread
340  *
341  * Check whether a given window belongs to the current thread (and return the full handle).
342  */
343 HWND WIN_IsCurrentThread( HWND hwnd )
344 {
345     WND *ptr;
346     HWND ret = 0;
347
348     if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS || ptr == WND_DESKTOP) return 0;
349     if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
350     WIN_ReleasePtr( ptr );
351     return ret;
352 }
353
354
355 /***********************************************************************
356  *           WIN_Handle32
357  *
358  * Convert a 16-bit window handle to a full 32-bit handle.
359  */
360 HWND WIN_Handle32( HWND16 hwnd16 )
361 {
362     WND *ptr;
363     HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
364
365     if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
366     /* do sign extension for -2 and -3 */
367     if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
368
369     if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
370
371     if (ptr == WND_DESKTOP) return GetDesktopWindow();
372
373     if (ptr != WND_OTHER_PROCESS)
374     {
375         hwnd = ptr->hwndSelf;
376         WIN_ReleasePtr( ptr );
377     }
378     else  /* may belong to another process */
379     {
380         SERVER_START_REQ( get_window_info )
381         {
382             req->handle = hwnd;
383             if (!wine_server_call_err( req )) hwnd = reply->full_handle;
384         }
385         SERVER_END_REQ;
386     }
387     return hwnd;
388 }
389
390
391 /***********************************************************************
392  *           WIN_SetOwner
393  *
394  * Change the owner of a window.
395  */
396 HWND WIN_SetOwner( HWND hwnd, HWND owner )
397 {
398     WND *win = WIN_GetPtr( hwnd );
399     HWND ret = 0;
400
401     if (!win || win == WND_DESKTOP) return 0;
402     if (win == WND_OTHER_PROCESS)
403     {
404         if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
405         return 0;
406     }
407     SERVER_START_REQ( set_window_owner )
408     {
409         req->handle = hwnd;
410         req->owner  = owner;
411         if (!wine_server_call( req ))
412         {
413             win->owner = reply->full_owner;
414             ret = reply->prev_owner;
415         }
416     }
417     SERVER_END_REQ;
418     WIN_ReleasePtr( win );
419     return ret;
420 }
421
422
423 /***********************************************************************
424  *           WIN_SetStyle
425  *
426  * Change the style of a window.
427  */
428 ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits )
429 {
430     BOOL ok;
431     ULONG new_style, old_style = 0;
432     WND *win = WIN_GetPtr( hwnd );
433
434     if (!win || win == WND_DESKTOP) return 0;
435     if (win == WND_OTHER_PROCESS)
436     {
437         if (IsWindow(hwnd))
438             ERR( "cannot set style %lx/%lx on other process window %p\n",
439                  set_bits, clear_bits, hwnd );
440         return 0;
441     }
442     new_style = (win->dwStyle | set_bits) & ~clear_bits;
443     if (new_style == win->dwStyle)
444     {
445         WIN_ReleasePtr( win );
446         return new_style;
447     }
448     SERVER_START_REQ( set_window_info )
449     {
450         req->handle = hwnd;
451         req->flags  = SET_WIN_STYLE;
452         req->style  = new_style;
453         req->extra_offset = -1;
454         if ((ok = !wine_server_call( req )))
455         {
456             old_style = reply->old_style;
457             win->dwStyle = new_style;
458         }
459     }
460     SERVER_END_REQ;
461     WIN_ReleasePtr( win );
462     if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style );
463     return old_style;
464 }
465
466
467 /***********************************************************************
468  *           WIN_GetRectangles
469  *
470  * Get the window and client rectangles.
471  */
472 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
473 {
474     WND *win = WIN_GetPtr( hwnd );
475     BOOL ret = TRUE;
476
477     if (!win) return FALSE;
478     if (win == WND_DESKTOP)
479     {
480         RECT rect;
481         rect.left = rect.top = 0;
482         rect.right  = GetSystemMetrics(SM_CXSCREEN);
483         rect.bottom = GetSystemMetrics(SM_CYSCREEN);
484         if (rectWindow) *rectWindow = rect;
485         if (rectClient) *rectClient = rect;
486     }
487     else if (win == WND_OTHER_PROCESS)
488     {
489         SERVER_START_REQ( get_window_rectangles )
490         {
491             req->handle = hwnd;
492             if ((ret = !wine_server_call( req )))
493             {
494                 if (rectWindow)
495                 {
496                     rectWindow->left   = reply->window.left;
497                     rectWindow->top    = reply->window.top;
498                     rectWindow->right  = reply->window.right;
499                     rectWindow->bottom = reply->window.bottom;
500                 }
501                 if (rectClient)
502                 {
503                     rectClient->left   = reply->client.left;
504                     rectClient->top    = reply->client.top;
505                     rectClient->right  = reply->client.right;
506                     rectClient->bottom = reply->client.bottom;
507                 }
508             }
509         }
510         SERVER_END_REQ;
511     }
512     else
513     {
514         if (rectWindow) *rectWindow = win->rectWindow;
515         if (rectClient) *rectClient = win->rectClient;
516         WIN_ReleasePtr( win );
517     }
518     return ret;
519 }
520
521
522 /***********************************************************************
523  *           WIN_DestroyWindow
524  *
525  * Destroy storage associated to a window. "Internals" p.358
526  */
527 LRESULT WIN_DestroyWindow( HWND hwnd )
528 {
529     WND *wndPtr;
530     HWND *list;
531     HMENU menu = 0, sys_menu;
532
533     TRACE("%p\n", hwnd );
534
535     /* free child windows */
536     if ((list = WIN_ListChildren( hwnd )))
537     {
538         int i;
539         for (i = 0; list[i]; i++)
540         {
541             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
542             else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
543         }
544         HeapFree( GetProcessHeap(), 0, list );
545     }
546
547     /* Unlink now so we won't bother with the children later on */
548     SERVER_START_REQ( set_parent )
549     {
550         req->handle = hwnd;
551         req->parent = 0;
552         wine_server_call( req );
553     }
554     SERVER_END_REQ;
555
556     /*
557      * Send the WM_NCDESTROY to the window being destroyed.
558      */
559     SendMessageW( hwnd, WM_NCDESTROY, 0, 0 );
560
561     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
562
563     WINPOS_CheckInternalPos( hwnd );
564
565     /* free resources associated with the window */
566
567     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
568     if (!(wndPtr->dwStyle & WS_CHILD)) menu = (HMENU)wndPtr->wIDmenu;
569     sys_menu = wndPtr->hSysMenu;
570     WIN_ReleasePtr( wndPtr );
571
572     if (menu) DestroyMenu( menu );
573     if (sys_menu) DestroyMenu( sys_menu );
574
575     USER_Driver->pDestroyWindow( hwnd );
576
577     free_window_handle( hwnd );
578     return 0;
579 }
580
581 /***********************************************************************
582  *           WIN_DestroyThreadWindows
583  *
584  * Destroy all children of 'wnd' owned by the current thread.
585  * Return TRUE if something was done.
586  */
587 void WIN_DestroyThreadWindows( HWND hwnd )
588 {
589     HWND *list;
590     int i;
591
592     if (!(list = WIN_ListChildren( hwnd ))) return;
593     for (i = 0; list[i]; i++)
594     {
595         if (WIN_IsCurrentThread( list[i] ))
596             DestroyWindow( list[i] );
597         else
598             WIN_DestroyThreadWindows( list[i] );
599     }
600     HeapFree( GetProcessHeap(), 0, list );
601 }
602
603
604 /***********************************************************************
605  *           WIN_FixCoordinates
606  *
607  * Fix the coordinates - Helper for WIN_CreateWindowEx.
608  * returns default show mode in sw.
609  * Note: the feature presented as undocumented *is* in the MSDN since 1993.
610  */
611 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
612 {
613     POINT pos[2];
614
615     if (cs->dwExStyle & WS_EX_MDICHILD)
616     {
617         UINT id = 0;
618
619         MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0, &id);
620         if (!(cs->style & WS_POPUP)) cs->hMenu = (HMENU)id;
621
622         TRACE("MDI child id %04x\n", id);
623     }
624
625     if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
626         cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
627     {
628         if (cs->style & (WS_CHILD | WS_POPUP))
629         {
630             if (cs->dwExStyle & WS_EX_MDICHILD)
631             {
632                 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
633                 {
634                     cs->x = pos[0].x;
635                     cs->y = pos[0].y;
636                 }
637                 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
638                     cs->cx = pos[1].x;
639                 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
640                     cs->cy = pos[1].y;
641             }
642             else
643             {
644                 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
645                     cs->x = cs->y = 0;
646                 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
647                     cs->cx = cs->cy = 0;
648             }
649         }
650         else  /* overlapped window */
651         {
652             STARTUPINFOW info;
653
654             GetStartupInfoW( &info );
655
656             if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
657             {
658                 /* Never believe Microsoft's documentation... CreateWindowEx doc says
659                  * that if an overlapped window is created with WS_VISIBLE style bit
660                  * set and the x parameter is set to CW_USEDEFAULT, the system ignores
661                  * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
662                  * reveals that
663                  *
664                  * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
665                  * 2) it does not ignore the y parameter as the docs claim; instead, it
666                  *    uses it as second parameter to ShowWindow() unless y is either
667                  *    CW_USEDEFAULT or CW_USEDEFAULT16.
668                  *
669                  * The fact that we didn't do 2) caused bogus windows pop up when wine
670                  * was running apps that were using this obscure feature. Example -
671                  * calc.exe that comes with Win98 (only Win98, it's different from
672                  * the one that comes with Win95 and NT)
673                  */
674                 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
675                 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
676                 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
677             }
678
679             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
680             {
681                 if (info.dwFlags & STARTF_USESIZE)
682                 {
683                     cs->cx = info.dwXSize;
684                     cs->cy = info.dwYSize;
685                 }
686                 else  /* if no other hint from the app, pick 3/4 of the screen real estate */
687                 {
688                     RECT r;
689                     SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0);
690                     cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
691                     cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
692                 }
693             }
694             /* Handle case where only the cy values is set to default */
695             else if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16)
696             {
697                 RECT r;
698                 SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0);
699                 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
700             }
701         }
702     }
703     else
704     {
705         /* neither x nor cx are default. Check the y values .
706          * In the trace we see Outlook and Outlook Express using
707          * cy set to CW_USEDEFAULT when opening the address book.
708          */
709         if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
710             RECT r;
711             FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
712             SystemParametersInfoW( SPI_GETWORKAREA, 0, &r, 0);
713             cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
714         }
715     }
716 }
717
718 /***********************************************************************
719  *           dump_window_styles
720  */
721 static void dump_window_styles( DWORD style, DWORD exstyle )
722 {
723     TRACE( "style:" );
724     if(style & WS_POPUP) TRACE(" WS_POPUP");
725     if(style & WS_CHILD) TRACE(" WS_CHILD");
726     if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
727     if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
728     if(style & WS_DISABLED) TRACE(" WS_DISABLED");
729     if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
730     if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
731     if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
732     if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
733     else
734     {
735         if(style & WS_BORDER) TRACE(" WS_BORDER");
736         if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
737     }
738     if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
739     if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
740     if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
741     if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
742     if(style & WS_GROUP) TRACE(" WS_GROUP");
743     if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
744     if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
745     if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
746
747     /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
748 #define DUMPED_STYLES \
749     (WS_POPUP | \
750      WS_CHILD | \
751      WS_MINIMIZE | \
752      WS_VISIBLE | \
753      WS_DISABLED | \
754      WS_CLIPSIBLINGS | \
755      WS_CLIPCHILDREN | \
756      WS_MAXIMIZE | \
757      WS_BORDER | \
758      WS_DLGFRAME | \
759      WS_VSCROLL | \
760      WS_HSCROLL | \
761      WS_SYSMENU | \
762      WS_THICKFRAME | \
763      WS_GROUP | \
764      WS_TABSTOP | \
765      WS_MINIMIZEBOX | \
766      WS_MAXIMIZEBOX)
767
768     if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
769     TRACE("\n");
770 #undef DUMPED_STYLES
771
772     TRACE( "exstyle:" );
773     if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
774     if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
775     if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
776     if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
777     if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
778     if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
779     if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
780     if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
781     if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
782     if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
783     if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
784     if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
785     if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
786     if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
787     if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
788     if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
789     if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
790     if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
791
792 #define DUMPED_EX_STYLES \
793     (WS_EX_DLGMODALFRAME | \
794      WS_EX_DRAGDETECT | \
795      WS_EX_NOPARENTNOTIFY | \
796      WS_EX_TOPMOST | \
797      WS_EX_ACCEPTFILES | \
798      WS_EX_TRANSPARENT | \
799      WS_EX_MDICHILD | \
800      WS_EX_TOOLWINDOW | \
801      WS_EX_WINDOWEDGE | \
802      WS_EX_CLIENTEDGE | \
803      WS_EX_CONTEXTHELP | \
804      WS_EX_RIGHT | \
805      WS_EX_RTLREADING | \
806      WS_EX_LEFTSCROLLBAR | \
807      WS_EX_CONTROLPARENT | \
808      WS_EX_STATICEDGE | \
809      WS_EX_APPWINDOW | \
810      WS_EX_LAYERED)
811
812     if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
813     TRACE("\n");
814 #undef DUMPED_EX_STYLES
815 }
816
817
818 /***********************************************************************
819  *           WIN_CreateWindowEx
820  *
821  * Implementation of CreateWindowEx().
822  */
823 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
824                                 WINDOWPROCTYPE type )
825 {
826     INT sw = SW_SHOW;
827     WND *wndPtr;
828     HWND hwnd, parent, owner, top_child = 0;
829     BOOL unicode = (type == WIN_PROC_32W);
830
831     TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
832           (type == WIN_PROC_32W) ? debugstr_w((LPCWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
833           (type == WIN_PROC_32W) ? debugstr_w((LPCWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
834           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
835           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
836
837     if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
838
839     TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
840             ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
841
842     /* Fix the styles for MDI children */
843     if (cs->dwExStyle & WS_EX_MDICHILD)
844     {
845         MDICREATESTRUCTA mdi_cs;
846         UINT flags = 0;
847
848         wndPtr = WIN_GetPtr(cs->hwndParent);
849         if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
850         {
851             flags = wndPtr->flags;
852             WIN_ReleasePtr(wndPtr);
853         }
854
855         if (!(flags & WIN_ISMDICLIENT))
856         {
857             WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
858             return 0;
859         }
860
861         /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
862          * MDICREATESTRUCT members have the originally passed values.
863          *
864          * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
865          * have the same layout.
866          */
867         mdi_cs.szClass = cs->lpszClass;
868         mdi_cs.szTitle = cs->lpszName;
869         mdi_cs.hOwner = cs->hInstance;
870         mdi_cs.x = cs->x;
871         mdi_cs.y = cs->y;
872         mdi_cs.cx = cs->cx;
873         mdi_cs.cy = cs->cy;
874         mdi_cs.style = cs->style;
875         mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
876
877         cs->lpCreateParams = (LPVOID)&mdi_cs;
878
879         if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
880         {
881             if (cs->style & WS_POPUP)
882             {
883                 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
884                 return 0;
885             }
886             cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
887         }
888         else
889         {
890             cs->style &= ~WS_POPUP;
891             cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
892                 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
893         }
894
895         top_child = GetWindow(cs->hwndParent, GW_CHILD);
896
897         if (top_child)
898         {
899             /* Restore current maximized child */
900             if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
901             {
902                 TRACE("Restoring current maximized child %p\n", top_child);
903                 SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
904                 ShowWindow(top_child, SW_RESTORE);
905                 SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
906             }
907         }
908     }
909
910     /* Find the parent window */
911
912     parent = GetDesktopWindow();
913     owner = 0;
914
915     if (cs->hwndParent == HWND_MESSAGE)
916     {
917       /* native ole32.OleInitialize uses HWND_MESSAGE to create the
918        * message window (style: WS_POPUP|WS_DISABLED)
919        */
920       FIXME("Parent is HWND_MESSAGE\n");
921     }
922     else if (cs->hwndParent)
923     {
924         /* Make sure parent is valid */
925         if (!IsWindow( cs->hwndParent ))
926         {
927             WARN("Bad parent %p\n", cs->hwndParent );
928             return 0;
929         }
930         if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
931             parent = WIN_GetFullHandle(cs->hwndParent);
932         else
933             owner = GetAncestor( cs->hwndParent, GA_ROOT );
934     }
935     else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
936     {
937         WARN("No parent for child window\n" );
938         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
939     }
940
941     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
942
943     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
944         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
945           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
946         cs->dwExStyle |= WS_EX_WINDOWEDGE;
947     else
948         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
949
950     /* Create the window structure */
951
952     if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
953     {
954         TRACE("out of memory\n" );
955         return 0;
956     }
957     hwnd = wndPtr->hwndSelf;
958
959     /* Fill the window structure */
960
961     wndPtr->tid            = GetCurrentThreadId();
962     wndPtr->owner          = owner;
963     wndPtr->parent         = parent;
964     wndPtr->hInstance      = cs->hInstance;
965     wndPtr->text           = NULL;
966     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
967     wndPtr->dwExStyle      = cs->dwExStyle;
968     wndPtr->wIDmenu        = 0;
969     wndPtr->helpContext    = 0;
970     wndPtr->flags          = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
971     wndPtr->pVScroll       = NULL;
972     wndPtr->pHScroll       = NULL;
973     wndPtr->userdata       = 0;
974     wndPtr->hIcon          = 0;
975     wndPtr->hIconSmall     = 0;
976     wndPtr->hSysMenu       = 0;
977
978     if (wndPtr->dwStyle & WS_SYSMENU) SetSystemMenu( hwnd, 0 );
979
980     /*
981      * Correct the window styles.
982      *
983      * It affects only the style loaded into the WIN structure.
984      */
985
986     if (!(wndPtr->dwStyle & WS_CHILD))
987     {
988         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
989         if (!(wndPtr->dwStyle & WS_POPUP))
990             wndPtr->dwStyle |= WS_CAPTION;
991     }
992
993     /*
994      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
995      * why does the user get to set it?
996      */
997
998     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
999           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1000         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1001     else
1002         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1003
1004     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1005         wndPtr->flags |= WIN_NEED_SIZE;
1006
1007     SERVER_START_REQ( set_window_info )
1008     {
1009         req->handle    = hwnd;
1010         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1011         req->style     = wndPtr->dwStyle;
1012         req->ex_style  = wndPtr->dwExStyle;
1013         req->instance  = (void *)wndPtr->hInstance;
1014         req->is_unicode = (type == WIN_PROC_32W);
1015         req->extra_offset = -1;
1016         wine_server_call( req );
1017     }
1018     SERVER_END_REQ;
1019
1020     /* Set the window menu */
1021
1022     if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1023         (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1024     {
1025         if (cs->hMenu)
1026         {
1027             if (!MENU_SetMenu(hwnd, cs->hMenu))
1028             {
1029                 WIN_ReleasePtr( wndPtr );
1030                 free_window_handle( hwnd );
1031                 return 0;
1032             }
1033         }
1034         else
1035         {
1036             LPCSTR menuName = (LPCSTR)GetClassLongPtrA( hwnd, GCLP_MENUNAME );
1037             if (menuName)
1038             {
1039                 if (!cs->hInstance || HIWORD(cs->hInstance))
1040                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1041                 else
1042                     cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1043
1044                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1045             }
1046         }
1047     }
1048     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1049     WIN_ReleasePtr( wndPtr );
1050
1051     if (!USER_Driver->pCreateWindow( hwnd, cs, unicode))
1052     {
1053         WIN_DestroyWindow( hwnd );
1054         return 0;
1055     }
1056
1057     /* Notify the parent window only */
1058
1059     send_parent_notify( hwnd, WM_CREATE );
1060     if (!IsWindow( hwnd )) return 0;
1061
1062     if (cs->style & WS_VISIBLE)
1063     {
1064         if (cs->style & WS_MAXIMIZE)
1065             sw = SW_SHOWMAXIMIZED;
1066         else if (cs->style & WS_MINIMIZE)
1067             sw = SW_SHOWMINIMIZED;
1068
1069         ShowWindow( hwnd, sw );
1070         if (cs->dwExStyle & WS_EX_MDICHILD)
1071         {
1072             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1073             /* ShowWindow won't activate child windows */
1074             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1075         }
1076     }
1077
1078     /* Call WH_SHELL hook */
1079
1080     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1081         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1082
1083     TRACE("created window %p\n", hwnd);
1084     return hwnd;
1085 }
1086
1087
1088 /***********************************************************************
1089  *              CreateWindow (USER.41)
1090  */
1091 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1092                               DWORD style, INT16 x, INT16 y, INT16 width,
1093                               INT16 height, HWND16 parent, HMENU16 menu,
1094                               HINSTANCE16 instance, LPVOID data )
1095 {
1096     return CreateWindowEx16( 0, className, windowName, style,
1097                              x, y, width, height, parent, menu, instance, data );
1098 }
1099
1100
1101 /***********************************************************************
1102  *              CreateWindowEx (USER.452)
1103  */
1104 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1105                                 LPCSTR windowName, DWORD style, INT16 x,
1106                                 INT16 y, INT16 width, INT16 height,
1107                                 HWND16 parent, HMENU16 menu,
1108                                 HINSTANCE16 instance, LPVOID data )
1109 {
1110     ATOM classAtom;
1111     CREATESTRUCTA cs;
1112     char buffer[256];
1113
1114     /* Find the class atom */
1115
1116     if (HIWORD(className))
1117     {
1118         if (!(classAtom = GlobalFindAtomA( className )))
1119         {
1120             ERR( "bad class name %s\n", debugstr_a(className) );
1121             return 0;
1122         }
1123     }
1124     else
1125     {
1126         classAtom = LOWORD(className);
1127         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1128         {
1129             ERR( "bad atom %x\n", classAtom);
1130             return 0;
1131         }
1132         className = buffer;
1133     }
1134
1135     /* Fix the coordinates */
1136
1137     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1138     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1139     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1140     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1141
1142     /* Create the window */
1143
1144     cs.lpCreateParams = data;
1145     cs.hInstance      = HINSTANCE_32(instance);
1146     cs.hMenu          = HMENU_32(menu);
1147     cs.hwndParent     = WIN_Handle32( parent );
1148     cs.style          = style;
1149     cs.lpszName       = windowName;
1150     cs.lpszClass      = className;
1151     cs.dwExStyle      = exStyle;
1152
1153     return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1154 }
1155
1156
1157 /***********************************************************************
1158  *              CreateWindowExA (USER32.@)
1159  */
1160 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1161                                  LPCSTR windowName, DWORD style, INT x,
1162                                  INT y, INT width, INT height,
1163                                  HWND parent, HMENU menu,
1164                                  HINSTANCE instance, LPVOID data )
1165 {
1166     ATOM classAtom;
1167     CREATESTRUCTA cs;
1168     char buffer[256];
1169
1170     /* Find the class atom */
1171
1172     if (HIWORD(className))
1173     {
1174         if (!(classAtom = GlobalFindAtomA( className )))
1175         {
1176             ERR( "bad class name %s\n", debugstr_a(className) );
1177             return 0;
1178         }
1179     }
1180     else
1181     {
1182         classAtom = LOWORD(className);
1183         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1184         {
1185             ERR( "bad atom %x\n", classAtom);
1186             return 0;
1187         }
1188         className = buffer;
1189     }
1190
1191     /* Create the window */
1192
1193     cs.lpCreateParams = data;
1194     cs.hInstance      = instance;
1195     cs.hMenu          = menu;
1196     cs.hwndParent     = parent;
1197     cs.x              = x;
1198     cs.y              = y;
1199     cs.cx             = width;
1200     cs.cy             = height;
1201     cs.style          = style;
1202     cs.lpszName       = windowName;
1203     cs.lpszClass      = className;
1204     cs.dwExStyle      = exStyle;
1205
1206     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1207 }
1208
1209
1210 /***********************************************************************
1211  *              CreateWindowExW (USER32.@)
1212  */
1213 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1214                                  LPCWSTR windowName, DWORD style, INT x,
1215                                  INT y, INT width, INT height,
1216                                  HWND parent, HMENU menu,
1217                                  HINSTANCE instance, LPVOID data )
1218 {
1219     ATOM classAtom;
1220     CREATESTRUCTW cs;
1221     WCHAR buffer[256];
1222
1223     /* Find the class atom */
1224
1225     if (HIWORD(className))
1226     {
1227         if (!(classAtom = GlobalFindAtomW( className )))
1228         {
1229             ERR( "bad class name %s\n", debugstr_w(className) );
1230             return 0;
1231         }
1232     }
1233     else
1234     {
1235         classAtom = LOWORD(className);
1236         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1237         {
1238             ERR( "bad atom %x\n", classAtom);
1239             return 0;
1240         }
1241         className = buffer;
1242     }
1243
1244     /* Create the window */
1245
1246     cs.lpCreateParams = data;
1247     cs.hInstance      = instance;
1248     cs.hMenu          = menu;
1249     cs.hwndParent     = parent;
1250     cs.x              = x;
1251     cs.y              = y;
1252     cs.cx             = width;
1253     cs.cy             = height;
1254     cs.style          = style;
1255     cs.lpszName       = windowName;
1256     cs.lpszClass      = className;
1257     cs.dwExStyle      = exStyle;
1258
1259     /* Note: we rely on the fact that CREATESTRUCTA and */
1260     /* CREATESTRUCTW have the same layout. */
1261     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1262 }
1263
1264
1265 /***********************************************************************
1266  *           WIN_SendDestroyMsg
1267  */
1268 static void WIN_SendDestroyMsg( HWND hwnd )
1269 {
1270     GUITHREADINFO info;
1271
1272     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1273     {
1274         if (hwnd == info.hwndCaret) DestroyCaret();
1275         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1276     }
1277     USER_Driver->pResetSelectionOwner( hwnd, TRUE );
1278
1279     /*
1280      * Send the WM_DESTROY to the window.
1281      */
1282     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1283
1284     /*
1285      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1286      * make sure that the window still exists when we come back.
1287      */
1288     if (IsWindow(hwnd))
1289     {
1290         HWND* pWndArray;
1291         int i;
1292
1293         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1294
1295         for (i = 0; pWndArray[i]; i++)
1296         {
1297             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1298         }
1299         HeapFree( GetProcessHeap(), 0, pWndArray );
1300     }
1301     else
1302       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1303 }
1304
1305
1306 /***********************************************************************
1307  *              DestroyWindow (USER32.@)
1308  */
1309 BOOL WINAPI DestroyWindow( HWND hwnd )
1310 {
1311     BOOL is_child;
1312
1313     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1314     {
1315         SetLastError( ERROR_ACCESS_DENIED );
1316         return FALSE;
1317     }
1318
1319     TRACE("(%p)\n", hwnd);
1320
1321       /* Call hooks */
1322
1323     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1324
1325     if (MENU_IsMenuActive() == hwnd)
1326         EndMenu();
1327
1328     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1329
1330     if (is_child)
1331     {
1332         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1333             send_parent_notify( hwnd, WM_DESTROY );
1334     }
1335     else if (!GetWindow( hwnd, GW_OWNER ))
1336     {
1337         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1338         /* FIXME: clean up palette - see "Internals" p.352 */
1339     }
1340
1341     if (!IsWindow(hwnd)) return TRUE;
1342
1343     USER_Driver->pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1344
1345       /* Hide the window */
1346     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1347     {
1348         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1349         if (is_child)
1350             ShowWindow( hwnd, SW_HIDE );
1351         else
1352             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1353                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1354     }
1355
1356     if (!IsWindow(hwnd)) return TRUE;
1357
1358       /* Recursively destroy owned windows */
1359
1360     if (!is_child)
1361     {
1362         for (;;)
1363         {
1364             int i, got_one = 0;
1365             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1366             if (list)
1367             {
1368                 for (i = 0; list[i]; i++)
1369                 {
1370                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1371                     if (WIN_IsCurrentThread( list[i] ))
1372                     {
1373                         DestroyWindow( list[i] );
1374                         got_one = 1;
1375                         continue;
1376                     }
1377                     WIN_SetOwner( list[i], 0 );
1378                 }
1379                 HeapFree( GetProcessHeap(), 0, list );
1380             }
1381             if (!got_one) break;
1382         }
1383     }
1384
1385       /* Send destroy messages */
1386
1387     WIN_SendDestroyMsg( hwnd );
1388     if (!IsWindow( hwnd )) return TRUE;
1389
1390     if (GetClipboardOwner() == hwnd)
1391         CLIPBOARD_ReleaseOwner();
1392
1393       /* Destroy the window storage */
1394
1395     WIN_DestroyWindow( hwnd );
1396     return TRUE;
1397 }
1398
1399
1400 /***********************************************************************
1401  *              CloseWindow (USER32.@)
1402  */
1403 BOOL WINAPI CloseWindow( HWND hwnd )
1404 {
1405     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1406     ShowWindow( hwnd, SW_MINIMIZE );
1407     return TRUE;
1408 }
1409
1410
1411 /***********************************************************************
1412  *              OpenIcon (USER32.@)
1413  */
1414 BOOL WINAPI OpenIcon( HWND hwnd )
1415 {
1416     if (!IsIconic( hwnd )) return FALSE;
1417     ShowWindow( hwnd, SW_SHOWNORMAL );
1418     return TRUE;
1419 }
1420
1421
1422 /***********************************************************************
1423  *           WIN_FindWindow
1424  *
1425  * Implementation of FindWindow() and FindWindowEx().
1426  */
1427 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1428 {
1429     HWND *list = NULL;
1430     HWND retvalue = 0;
1431     int i = 0, len = 0;
1432     WCHAR *buffer = NULL;
1433
1434     if (!parent) parent = GetDesktopWindow();
1435     if (title)
1436     {
1437         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1438         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1439     }
1440
1441     if (!(list = list_window_children( parent, className, 0 ))) goto done;
1442
1443     if (child)
1444     {
1445         child = WIN_GetFullHandle( child );
1446         while (list[i] && list[i] != child) i++;
1447         if (!list[i]) goto done;
1448         i++;  /* start from next window */
1449     }
1450
1451     if (title)
1452     {
1453         while (list[i])
1454         {
1455             if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1456             i++;
1457         }
1458     }
1459     retvalue = list[i];
1460
1461  done:
1462     HeapFree( GetProcessHeap(), 0, list );
1463     HeapFree( GetProcessHeap(), 0, buffer );
1464     return retvalue;
1465 }
1466
1467
1468
1469 /***********************************************************************
1470  *              FindWindowA (USER32.@)
1471  */
1472 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1473 {
1474     HWND ret = FindWindowExA( 0, 0, className, title );
1475     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1476     return ret;
1477 }
1478
1479
1480 /***********************************************************************
1481  *              FindWindowExA (USER32.@)
1482  */
1483 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1484                                LPCSTR className, LPCSTR title )
1485 {
1486     ATOM atom = 0;
1487     LPWSTR buffer;
1488     HWND hwnd;
1489     INT len;
1490
1491     if (className)
1492     {
1493         /* If the atom doesn't exist, then no class */
1494         /* with this name exists either. */
1495         if (!(atom = GlobalFindAtomA( className )))
1496         {
1497             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1498             return 0;
1499         }
1500     }
1501     if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1502
1503     len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1504     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1505     MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1506     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1507     HeapFree( GetProcessHeap(), 0, buffer );
1508     return hwnd;
1509 }
1510
1511
1512 /***********************************************************************
1513  *              FindWindowExW (USER32.@)
1514  */
1515 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1516                                LPCWSTR className, LPCWSTR title )
1517 {
1518     ATOM atom = 0;
1519
1520     if (className)
1521     {
1522         /* If the atom doesn't exist, then no class */
1523         /* with this name exists either. */
1524         if (!(atom = GlobalFindAtomW( className )))
1525         {
1526             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1527             return 0;
1528         }
1529     }
1530     return WIN_FindWindow( parent, child, atom, title );
1531 }
1532
1533
1534 /***********************************************************************
1535  *              FindWindowW (USER32.@)
1536  */
1537 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1538 {
1539     return FindWindowExW( 0, 0, className, title );
1540 }
1541
1542
1543 /**********************************************************************
1544  *              GetDesktopWindow (USER32.@)
1545  */
1546 HWND WINAPI GetDesktopWindow(void)
1547 {
1548     struct user_thread_info *thread_info = get_user_thread_info();
1549
1550     if (!thread_info->desktop)
1551     {
1552         SERVER_START_REQ( get_desktop_window )
1553         {
1554             if (!wine_server_call( req )) thread_info->desktop = reply->handle;
1555         }
1556         SERVER_END_REQ;
1557         if (!thread_info->desktop || !USER_Driver->pCreateDesktopWindow( thread_info->desktop ))
1558             ERR( "failed to create desktop window\n" );
1559     }
1560     return thread_info->desktop;
1561 }
1562
1563
1564 /*******************************************************************
1565  *              EnableWindow (USER32.@)
1566  */
1567 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1568 {
1569     BOOL retvalue;
1570     HWND full_handle;
1571
1572     if (is_broadcast(hwnd))
1573     {
1574         SetLastError( ERROR_INVALID_PARAMETER );
1575         return FALSE;
1576     }
1577
1578     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1579         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1580
1581     hwnd = full_handle;
1582
1583     TRACE("( %p, %d )\n", hwnd, enable);
1584
1585     retvalue = !IsWindowEnabled( hwnd );
1586
1587     if (enable && retvalue)
1588     {
1589         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1590         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1591     }
1592     else if (!enable && !retvalue)
1593     {
1594         HWND capture_wnd;
1595
1596         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1597
1598         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1599
1600         if (hwnd == GetFocus())
1601             SetFocus( 0 );  /* A disabled window can't have the focus */
1602
1603         capture_wnd = GetCapture();
1604         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1605             ReleaseCapture();  /* A disabled window can't capture the mouse */
1606
1607         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1608     }
1609     return retvalue;
1610 }
1611
1612
1613 /***********************************************************************
1614  *              IsWindowEnabled (USER32.@)
1615  */
1616 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1617 {
1618     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1619 }
1620
1621
1622 /***********************************************************************
1623  *              IsWindowUnicode (USER32.@)
1624  */
1625 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1626 {
1627     WND * wndPtr;
1628     BOOL retvalue = FALSE;
1629
1630     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1631
1632     if (wndPtr == WND_DESKTOP) return TRUE;
1633
1634     if (wndPtr != WND_OTHER_PROCESS)
1635     {
1636         retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1637         WIN_ReleasePtr( wndPtr );
1638     }
1639     else
1640     {
1641         SERVER_START_REQ( get_window_info )
1642         {
1643             req->handle = hwnd;
1644             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
1645         }
1646         SERVER_END_REQ;
1647     }
1648     return retvalue;
1649 }
1650
1651
1652 /**********************************************************************
1653  *              GetWindowWord (USER32.@)
1654  */
1655 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1656 {
1657     if (offset >= 0)
1658     {
1659         WORD retvalue = 0;
1660         WND *wndPtr = WIN_GetPtr( hwnd );
1661         if (!wndPtr)
1662         {
1663             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1664             return 0;
1665         }
1666         if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1667         {
1668             SERVER_START_REQ( set_window_info )
1669             {
1670                 req->handle = hwnd;
1671                 req->flags  = 0;  /* don't set anything, just retrieve */
1672                 req->extra_offset = offset;
1673                 req->extra_size = sizeof(retvalue);
1674                 if (!wine_server_call_err( req ))
1675                     memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1676             }
1677             SERVER_END_REQ;
1678             return retvalue;
1679         }
1680         if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1681         {
1682             WARN("Invalid offset %d\n", offset );
1683             SetLastError( ERROR_INVALID_INDEX );
1684         }
1685         else memcpy( &retvalue,  (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1686         WIN_ReleasePtr( wndPtr );
1687         return retvalue;
1688     }
1689
1690     switch(offset)
1691     {
1692     case GWLP_HWNDPARENT:
1693         return GetWindowLongPtrW( hwnd, offset );
1694     case GWLP_ID:
1695     case GWLP_HINSTANCE:
1696         {
1697             LONG_PTR ret = GetWindowLongPtrW( hwnd, offset );
1698             if (HIWORD(ret))
1699                 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1700             return LOWORD(ret);
1701         }
1702     default:
1703         WARN("Invalid offset %d\n", offset );
1704         return 0;
1705     }
1706 }
1707
1708
1709 /**********************************************************************
1710  *              SetWindowWord (USER32.@)
1711  */
1712 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1713 {
1714     WORD retval = 0;
1715     WND * wndPtr;
1716
1717     switch(offset)
1718     {
1719     case GWLP_ID:
1720     case GWLP_HINSTANCE:
1721     case GWLP_HWNDPARENT:
1722         return SetWindowLongPtrW( hwnd, offset, (ULONG_PTR)newval );
1723     default:
1724         if (offset < 0)
1725         {
1726             WARN("Invalid offset %d\n", offset );
1727             SetLastError( ERROR_INVALID_INDEX );
1728             return 0;
1729         }
1730     }
1731
1732     wndPtr = WIN_GetPtr( hwnd );
1733     if (wndPtr == WND_DESKTOP)
1734     {
1735         SetLastError( ERROR_ACCESS_DENIED );
1736         return 0;
1737     }
1738     if (wndPtr == WND_OTHER_PROCESS)
1739     {
1740         if (IsWindow(hwnd))
1741             FIXME( "set %d <- %x not supported yet on other process window %p\n",
1742                    offset, newval, hwnd );
1743         wndPtr = NULL;
1744     }
1745     if (!wndPtr)
1746     {
1747        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1748        return 0;
1749     }
1750
1751     if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1752     {
1753         WARN("Invalid offset %d\n", offset );
1754         WIN_ReleasePtr(wndPtr);
1755         SetLastError( ERROR_INVALID_INDEX );
1756         return 0;
1757     }
1758
1759     SERVER_START_REQ( set_window_info )
1760     {
1761         req->handle = hwnd;
1762         req->flags = SET_WIN_EXTRA;
1763         req->extra_offset = offset;
1764         req->extra_size = sizeof(newval);
1765         memcpy( &req->extra_value, &newval, sizeof(newval) );
1766         if (!wine_server_call_err( req ))
1767         {
1768             void *ptr = (char *)wndPtr->wExtra + offset;
1769             memcpy( &retval, ptr, sizeof(retval) );
1770             memcpy( ptr, &newval, sizeof(newval) );
1771         }
1772     }
1773     SERVER_END_REQ;
1774     WIN_ReleasePtr( wndPtr );
1775     return retval;
1776 }
1777
1778
1779 /**********************************************************************
1780  *           WIN_GetWindowLong
1781  *
1782  * Helper function for GetWindowLong().
1783  */
1784 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1785 {
1786     LONG_PTR retvalue = 0;
1787     WND *wndPtr;
1788
1789     if (offset == GWLP_HWNDPARENT)
1790     {
1791         HWND parent = GetAncestor( hwnd, GA_PARENT );
1792         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1793         return (ULONG_PTR)parent;
1794     }
1795
1796     if (!(wndPtr = WIN_GetPtr( hwnd )))
1797     {
1798         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1799         return 0;
1800     }
1801
1802     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
1803     {
1804         if (offset == GWLP_WNDPROC)
1805         {
1806             SetLastError( ERROR_ACCESS_DENIED );
1807             return 0;
1808         }
1809         SERVER_START_REQ( set_window_info )
1810         {
1811             req->handle = hwnd;
1812             req->flags  = 0;  /* don't set anything, just retrieve */
1813             req->extra_offset = (offset >= 0) ? offset : -1;
1814             req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1815             if (!wine_server_call_err( req ))
1816             {
1817                 switch(offset)
1818                 {
1819                 case GWL_STYLE:      retvalue = reply->old_style; break;
1820                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
1821                 case GWLP_ID:        retvalue = reply->old_id; break;
1822                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1823                 case GWLP_USERDATA:  retvalue = (ULONG_PTR)reply->old_user_data; break;
1824                 default:
1825                     if (offset >= 0) retvalue = reply->old_extra_value;
1826                     else SetLastError( ERROR_INVALID_INDEX );
1827                     break;
1828                 }
1829             }
1830         }
1831         SERVER_END_REQ;
1832         return retvalue;
1833     }
1834
1835     /* now we have a valid wndPtr */
1836
1837     if (offset >= 0)
1838     {
1839         if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1840         {
1841           /*
1842             * Some programs try to access last element from 16 bit
1843             * code using illegal offset value. Hopefully this is
1844             * what those programs really expect.
1845             */
1846            if (type == WIN_PROC_16 &&
1847                wndPtr->cbWndExtra >= 4 &&
1848                offset == wndPtr->cbWndExtra - sizeof(WORD))
1849            {
1850                INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1851
1852                ERR( "- replaced invalid offset %d with %d\n",
1853                     offset, offset2 );
1854
1855                 retvalue = *(LONG_PTR *)(((char *)wndPtr->wExtra) + offset2);
1856                 WIN_ReleasePtr( wndPtr );
1857                 return retvalue;
1858             }
1859             WARN("Invalid offset %d\n", offset );
1860             WIN_ReleasePtr( wndPtr );
1861             SetLastError( ERROR_INVALID_INDEX );
1862             return 0;
1863         }
1864         retvalue = *(LONG_PTR *)(((char *)wndPtr->wExtra) + offset);
1865         /* Special case for dialog window procedure */
1866         if ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1867             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, type );
1868         WIN_ReleasePtr( wndPtr );
1869         return retvalue;
1870     }
1871
1872     switch(offset)
1873     {
1874     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
1875     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1876     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1877     case GWLP_ID:        retvalue = (ULONG_PTR)wndPtr->wIDmenu; break;
1878     case GWLP_WNDPROC:   retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type ); break;
1879     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
1880     default:
1881         WARN("Unknown offset %d\n", offset );
1882         SetLastError( ERROR_INVALID_INDEX );
1883         break;
1884     }
1885     WIN_ReleasePtr(wndPtr);
1886     return retvalue;
1887 }
1888
1889
1890 /**********************************************************************
1891  *           WIN_SetWindowLong
1892  *
1893  * Helper function for SetWindowLong().
1894  *
1895  * 0 is the failure code. However, in the case of failure SetLastError
1896  * must be set to distinguish between a 0 return value and a failure.
1897  */
1898 static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval,
1899                                    WINDOWPROCTYPE type )
1900 {
1901     STYLESTRUCT style;
1902     BOOL ok;
1903     LONG_PTR retval = 0;
1904     WND *wndPtr;
1905
1906     TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
1907
1908     if (is_broadcast(hwnd))
1909     {
1910         SetLastError( ERROR_INVALID_PARAMETER );
1911         return FALSE;
1912     }
1913
1914     if (!(wndPtr = WIN_GetPtr( hwnd )))
1915     {
1916         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1917         return 0;
1918     }
1919     if (wndPtr == WND_DESKTOP)
1920     {
1921         /* can't change anything on the desktop window */
1922         SetLastError( ERROR_ACCESS_DENIED );
1923         return 0;
1924     }
1925     if (wndPtr == WND_OTHER_PROCESS)
1926     {
1927         if (offset == GWLP_WNDPROC)
1928         {
1929             SetLastError( ERROR_ACCESS_DENIED );
1930             return 0;
1931         }
1932         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1933     }
1934
1935     /* first some special cases */
1936     switch( offset )
1937     {
1938     case GWL_STYLE:
1939     case GWL_EXSTYLE:
1940         style.styleOld =
1941             offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
1942         style.styleNew = newval;
1943         WIN_ReleasePtr( wndPtr );
1944         SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1945         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1946         newval = style.styleNew;
1947         break;
1948     case GWLP_HWNDPARENT:
1949         if (wndPtr->parent == GetDesktopWindow())
1950         {
1951             WIN_ReleasePtr( wndPtr );
1952             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
1953         }
1954         else
1955         {
1956             WIN_ReleasePtr( wndPtr );
1957             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
1958         }
1959     case GWLP_WNDPROC:
1960     {
1961         WINDOWPROCTYPE old_type = WINPROC_GetProcType( wndPtr->winproc );
1962         retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type );
1963         wndPtr->winproc = WINPROC_AllocProc( (WNDPROC)newval, type );
1964         if (old_type == type)
1965         {
1966             WIN_ReleasePtr( wndPtr );
1967             return retval;
1968         }
1969         /* update is_unicode flag on the server side */
1970         break;
1971     }
1972     case GWLP_ID:
1973     case GWLP_HINSTANCE:
1974     case GWLP_USERDATA:
1975         break;
1976     case DWLP_DLGPROC:
1977         if ((wndPtr->cbWndExtra + sizeof(LONG_PTR) >= DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1978         {
1979             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
1980             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, type );
1981             *ptr = WINPROC_AllocProc( (WNDPROC)newval, type );
1982             WIN_ReleasePtr( wndPtr );
1983             return retval;
1984         }
1985         /* fall through */
1986     default:
1987         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG_PTR)))
1988         {
1989             WARN("Invalid offset %d\n", offset );
1990             WIN_ReleasePtr( wndPtr );
1991             SetLastError( ERROR_INVALID_INDEX );
1992             return 0;
1993         }
1994         else
1995         {
1996             LONG_PTR *ptr = (LONG_PTR *)((char *)wndPtr->wExtra + offset);
1997             if (*ptr == newval)  /* already set to the same value */
1998             {
1999                 WIN_ReleasePtr( wndPtr );
2000                 return newval;
2001             }
2002         }
2003         break;
2004     }
2005
2006     SERVER_START_REQ( set_window_info )
2007     {
2008         req->handle = hwnd;
2009         req->extra_offset = -1;
2010         switch(offset)
2011         {
2012         case GWL_STYLE:
2013             req->flags = SET_WIN_STYLE;
2014             req->style = newval;
2015             break;
2016         case GWL_EXSTYLE:
2017             req->flags = SET_WIN_EXSTYLE;
2018             req->ex_style = newval;
2019             break;
2020         case GWLP_ID:
2021             req->flags = SET_WIN_ID;
2022             req->id = newval;
2023             break;
2024         case GWLP_HINSTANCE:
2025             req->flags = SET_WIN_INSTANCE;
2026             req->instance = (void *)newval;
2027             break;
2028         case GWLP_WNDPROC:
2029             req->flags = SET_WIN_UNICODE;
2030             req->is_unicode = (type == WIN_PROC_32W);
2031             break;
2032         case GWLP_USERDATA:
2033             req->flags = SET_WIN_USERDATA;
2034             req->user_data = (void *)newval;
2035             break;
2036         default:
2037             req->flags = SET_WIN_EXTRA;
2038             req->extra_offset = offset;
2039             req->extra_size = sizeof(newval);
2040             memcpy( &req->extra_value, &newval, sizeof(newval) );
2041         }
2042         if ((ok = !wine_server_call_err( req )))
2043         {
2044             switch(offset)
2045             {
2046             case GWL_STYLE:
2047                 wndPtr->dwStyle = newval;
2048                 retval = reply->old_style;
2049                 break;
2050             case GWL_EXSTYLE:
2051                 wndPtr->dwExStyle = newval;
2052                 retval = reply->old_ex_style;
2053                 break;
2054             case GWLP_ID:
2055                 wndPtr->wIDmenu = newval;
2056                 retval = reply->old_id;
2057                 break;
2058             case GWLP_HINSTANCE:
2059                 wndPtr->hInstance = (HINSTANCE)newval;
2060                 retval = (ULONG_PTR)reply->old_instance;
2061                 break;
2062             case GWLP_WNDPROC:
2063                 break;
2064             case GWLP_USERDATA:
2065                 wndPtr->userdata = newval;
2066                 retval = (ULONG_PTR)reply->old_user_data;
2067                 break;
2068             default:
2069                 {
2070                     void *ptr = (char *)wndPtr->wExtra + offset;
2071                     memcpy( &retval, ptr, sizeof(retval) );
2072                     memcpy( ptr, &newval, sizeof(newval) );
2073                 }
2074                 break;
2075             }
2076         }
2077     }
2078     SERVER_END_REQ;
2079     WIN_ReleasePtr( wndPtr );
2080
2081     if (!ok) return 0;
2082
2083     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2084
2085     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2086         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2087
2088     return retval;
2089 }
2090
2091
2092 /**********************************************************************
2093  *              GetWindowLong (USER.135)
2094  */
2095 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2096 {
2097     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2098 }
2099
2100
2101 /**********************************************************************
2102  *              GetWindowLongA (USER32.@)
2103  */
2104 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2105 {
2106     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2107 }
2108
2109
2110 /**********************************************************************
2111  *              GetWindowLongW (USER32.@)
2112  */
2113 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2114 {
2115     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2116 }
2117
2118
2119 /**********************************************************************
2120  *              SetWindowLong (USER.136)
2121  */
2122 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2123 {
2124     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2125 }
2126
2127
2128 /**********************************************************************
2129  *              SetWindowLongA (USER32.@)
2130  *
2131  * See SetWindowLongW.
2132  */
2133 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2134 {
2135     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2136 }
2137
2138
2139 /**********************************************************************
2140  *              SetWindowLongW (USER32.@) Set window attribute
2141  *
2142  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2143  * value in a window's extra memory.
2144  *
2145  * The _hwnd_ parameter specifies the window.  is the handle to a
2146  * window that has extra memory. The _newval_ parameter contains the
2147  * new attribute or extra memory value.  If positive, the _offset_
2148  * parameter is the byte-addressed location in the window's extra
2149  * memory to set.  If negative, _offset_ specifies the window
2150  * attribute to set, and should be one of the following values:
2151  *
2152  * GWL_EXSTYLE      The window's extended window style
2153  *
2154  * GWL_STYLE        The window's window style.
2155  *
2156  * GWLP_WNDPROC     Pointer to the window's window procedure.
2157  *
2158  * GWLP_HINSTANCE   The window's pplication instance handle.
2159  *
2160  * GWLP_ID          The window's identifier.
2161  *
2162  * GWLP_USERDATA    The window's user-specified data.
2163  *
2164  * If the window is a dialog box, the _offset_ parameter can be one of
2165  * the following values:
2166  *
2167  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2168  *
2169  * DWLP_MSGRESULT   The return value of a message
2170  *                  that the dialog box procedure processed.
2171  *
2172  * DWLP_USER        Application specific information.
2173  *
2174  * RETURNS
2175  *
2176  * If successful, returns the previous value located at _offset_. Otherwise,
2177  * returns 0.
2178  *
2179  * NOTES
2180  *
2181  * Extra memory for a window class is specified by a nonzero cbWndExtra
2182  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2183  * time of class creation.
2184  *
2185  * Using GWL_WNDPROC to set a new window procedure effectively creates
2186  * a window subclass. Use CallWindowProc() in the new windows procedure
2187  * to pass messages to the superclass's window procedure.
2188  *
2189  * The user data is reserved for use by the application which created
2190  * the window.
2191  *
2192  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2193  * instead, call the EnableWindow() function to change the window's
2194  * disabled state.
2195  *
2196  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2197  * SetParent() instead.
2198  *
2199  * Win95:
2200  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2201  * it sends WM_STYLECHANGING before changing the settings
2202  * and WM_STYLECHANGED afterwards.
2203  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2204  */
2205 LONG WINAPI SetWindowLongW(
2206     HWND hwnd,  /* [in] window to alter */
2207     INT offset, /* [in] offset, in bytes, of location to alter */
2208     LONG newval /* [in] new value of location */
2209 ) {
2210     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2211 }
2212
2213
2214 /*******************************************************************
2215  *              GetWindowTextA (USER32.@)
2216  */
2217 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2218 {
2219     WCHAR *buffer;
2220
2221     if (!lpString) return 0;
2222
2223     if (WIN_IsCurrentProcess( hwnd ))
2224         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2225
2226     /* when window belongs to other process, don't send a message */
2227     if (nMaxCount <= 0) return 0;
2228     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2229     get_server_window_text( hwnd, buffer, nMaxCount );
2230     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2231         lpString[nMaxCount-1] = 0;
2232     HeapFree( GetProcessHeap(), 0, buffer );
2233     return strlen(lpString);
2234 }
2235
2236
2237 /*******************************************************************
2238  *              InternalGetWindowText (USER32.@)
2239  */
2240 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2241 {
2242     WND *win;
2243
2244     if (nMaxCount <= 0) return 0;
2245     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2246     if (win == WND_DESKTOP) lpString[0] = 0;
2247     else if (win != WND_OTHER_PROCESS)
2248     {
2249         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2250         else lpString[0] = 0;
2251         WIN_ReleasePtr( win );
2252     }
2253     else
2254     {
2255         get_server_window_text( hwnd, lpString, nMaxCount );
2256     }
2257     return strlenW(lpString);
2258 }
2259
2260
2261 /*******************************************************************
2262  *              GetWindowTextW (USER32.@)
2263  */
2264 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2265 {
2266     if (!lpString) return 0;
2267
2268     if (WIN_IsCurrentProcess( hwnd ))
2269         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2270
2271     /* when window belongs to other process, don't send a message */
2272     if (nMaxCount <= 0) return 0;
2273     get_server_window_text( hwnd, lpString, nMaxCount );
2274     return strlenW(lpString);
2275 }
2276
2277
2278 /*******************************************************************
2279  *              SetWindowTextA (USER32.@)
2280  *              SetWindowText  (USER32.@)
2281  */
2282 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2283 {
2284     if (is_broadcast(hwnd))
2285     {
2286         SetLastError( ERROR_INVALID_PARAMETER );
2287         return FALSE;
2288     }
2289     if (!WIN_IsCurrentProcess( hwnd ))
2290         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2291                debugstr_a(lpString), hwnd );
2292     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2293 }
2294
2295
2296 /*******************************************************************
2297  *              SetWindowTextW (USER32.@)
2298  */
2299 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2300 {
2301     if (is_broadcast(hwnd))
2302     {
2303         SetLastError( ERROR_INVALID_PARAMETER );
2304         return FALSE;
2305     }
2306     if (!WIN_IsCurrentProcess( hwnd ))
2307         FIXME( "setting text %s of other process window %p should not use SendMessage\n",
2308                debugstr_w(lpString), hwnd );
2309     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2310 }
2311
2312
2313 /*******************************************************************
2314  *              GetWindowTextLengthA (USER32.@)
2315  */
2316 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2317 {
2318     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2319 }
2320
2321 /*******************************************************************
2322  *              GetWindowTextLengthW (USER32.@)
2323  */
2324 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2325 {
2326     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2327 }
2328
2329
2330 /*******************************************************************
2331  *              IsWindow (USER32.@)
2332  */
2333 BOOL WINAPI IsWindow( HWND hwnd )
2334 {
2335     WND *ptr;
2336     BOOL ret;
2337
2338     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2339     if (ptr == WND_DESKTOP) return TRUE;
2340
2341     if (ptr != WND_OTHER_PROCESS)
2342     {
2343         WIN_ReleasePtr( ptr );
2344         return TRUE;
2345     }
2346
2347     /* check other processes */
2348     SERVER_START_REQ( get_window_info )
2349     {
2350         req->handle = hwnd;
2351         ret = !wine_server_call_err( req );
2352     }
2353     SERVER_END_REQ;
2354     return ret;
2355 }
2356
2357
2358 /***********************************************************************
2359  *              GetWindowThreadProcessId (USER32.@)
2360  */
2361 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2362 {
2363     WND *ptr;
2364     DWORD tid = 0;
2365
2366     if (!(ptr = WIN_GetPtr( hwnd )))
2367     {
2368         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2369         return 0;
2370     }
2371
2372     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2373     {
2374         /* got a valid window */
2375         tid = ptr->tid;
2376         if (process) *process = GetCurrentProcessId();
2377         WIN_ReleasePtr( ptr );
2378         return tid;
2379     }
2380
2381     /* check other processes */
2382     SERVER_START_REQ( get_window_info )
2383     {
2384         req->handle = hwnd;
2385         if (!wine_server_call_err( req ))
2386         {
2387             tid = (DWORD)reply->tid;
2388             if (process) *process = (DWORD)reply->pid;
2389         }
2390     }
2391     SERVER_END_REQ;
2392     return tid;
2393 }
2394
2395
2396 /*****************************************************************
2397  *              GetParent (USER32.@)
2398  */
2399 HWND WINAPI GetParent( HWND hwnd )
2400 {
2401     WND *wndPtr;
2402     HWND retvalue = 0;
2403
2404     if (!(wndPtr = WIN_GetPtr( hwnd )))
2405     {
2406         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2407         return 0;
2408     }
2409     if (wndPtr == WND_DESKTOP) return 0;
2410     if (wndPtr == WND_OTHER_PROCESS)
2411     {
2412         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2413         if (style & (WS_POPUP | WS_CHILD))
2414         {
2415             SERVER_START_REQ( get_window_tree )
2416             {
2417                 req->handle = hwnd;
2418                 if (!wine_server_call_err( req ))
2419                 {
2420                     if (style & WS_POPUP) retvalue = reply->owner;
2421                     else if (style & WS_CHILD) retvalue = reply->parent;
2422                 }
2423             }
2424             SERVER_END_REQ;
2425         }
2426     }
2427     else
2428     {
2429         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2430         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2431         WIN_ReleasePtr( wndPtr );
2432     }
2433     return retvalue;
2434 }
2435
2436
2437 /*****************************************************************
2438  *              GetAncestor (USER32.@)
2439  */
2440 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2441 {
2442     WND *win;
2443     HWND *list, ret = 0;
2444
2445     switch(type)
2446     {
2447     case GA_PARENT:
2448         if (!(win = WIN_GetPtr( hwnd )))
2449         {
2450             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2451             return 0;
2452         }
2453         if (win == WND_DESKTOP) return 0;
2454         if (win != WND_OTHER_PROCESS)
2455         {
2456             ret = win->parent;
2457             WIN_ReleasePtr( win );
2458         }
2459         else /* need to query the server */
2460         {
2461             SERVER_START_REQ( get_window_tree )
2462             {
2463                 req->handle = hwnd;
2464                 if (!wine_server_call_err( req )) ret = reply->parent;
2465             }
2466             SERVER_END_REQ;
2467         }
2468         break;
2469
2470     case GA_ROOT:
2471         if (!(list = list_window_parents( hwnd ))) return 0;
2472
2473         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2474         else
2475         {
2476             int count = 2;
2477             while (list[count]) count++;
2478             ret = list[count - 2];  /* get the one before the desktop */
2479         }
2480         HeapFree( GetProcessHeap(), 0, list );
2481         break;
2482
2483     case GA_ROOTOWNER:
2484         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2485         for (;;)
2486         {
2487             HWND parent = GetParent( ret );
2488             if (!parent) break;
2489             ret = parent;
2490         }
2491         break;
2492     }
2493     return ret;
2494 }
2495
2496
2497 /*****************************************************************
2498  *              SetParent (USER32.@)
2499  */
2500 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2501 {
2502     HWND full_handle;
2503
2504     if (is_broadcast(hwnd) || is_broadcast(parent))
2505     {
2506         SetLastError(ERROR_INVALID_PARAMETER);
2507         return 0;
2508     }
2509
2510     if (!parent) parent = GetDesktopWindow();
2511     else parent = WIN_GetFullHandle( parent );
2512
2513     if (!IsWindow( parent ))
2514     {
2515         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2516         return 0;
2517     }
2518
2519     /* Some applications try to set a child as a parent */
2520     if (IsChild(hwnd, parent))
2521     {
2522         SetLastError( ERROR_INVALID_PARAMETER );
2523         return 0;
2524     }
2525
2526     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2527         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2528
2529     return USER_Driver->pSetParent( full_handle, parent );
2530 }
2531
2532
2533 /*******************************************************************
2534  *              IsChild (USER32.@)
2535  */
2536 BOOL WINAPI IsChild( HWND parent, HWND child )
2537 {
2538     HWND *list = list_window_parents( child );
2539     int i;
2540     BOOL ret;
2541
2542     if (!list) return FALSE;
2543     parent = WIN_GetFullHandle( parent );
2544     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2545     ret = (list[i] != 0);
2546     HeapFree( GetProcessHeap(), 0, list );
2547     return ret;
2548 }
2549
2550
2551 /***********************************************************************
2552  *              IsWindowVisible (USER32.@)
2553  */
2554 BOOL WINAPI IsWindowVisible( HWND hwnd )
2555 {
2556     HWND *list;
2557     BOOL retval;
2558     int i;
2559
2560     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2561     if (!(list = list_window_parents( hwnd ))) return TRUE;
2562     for (i = 0; list[i]; i++)
2563         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2564     retval = !list[i];
2565     HeapFree( GetProcessHeap(), 0, list );
2566     return retval;
2567 }
2568
2569
2570 /***********************************************************************
2571  *           WIN_IsWindowDrawable
2572  *
2573  * hwnd is drawable when it is visible, all parents are not
2574  * minimized, and it is itself not minimized unless we are
2575  * trying to draw its default class icon.
2576  */
2577 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2578 {
2579     HWND *list;
2580     BOOL retval;
2581     int i;
2582     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2583
2584     if (!(style & WS_VISIBLE)) return FALSE;
2585     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2586
2587     if (!(list = list_window_parents( hwnd ))) return TRUE;
2588     for (i = 0; list[i]; i++)
2589         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2590             break;
2591     retval = !list[i];
2592     HeapFree( GetProcessHeap(), 0, list );
2593     return retval;
2594 }
2595
2596
2597 /*******************************************************************
2598  *              GetTopWindow (USER32.@)
2599  */
2600 HWND WINAPI GetTopWindow( HWND hwnd )
2601 {
2602     if (!hwnd) hwnd = GetDesktopWindow();
2603     return GetWindow( hwnd, GW_CHILD );
2604 }
2605
2606
2607 /*******************************************************************
2608  *              GetWindow (USER32.@)
2609  */
2610 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2611 {
2612     HWND retval = 0;
2613
2614     if (rel == GW_OWNER)  /* this one may be available locally */
2615     {
2616         WND *wndPtr = WIN_GetPtr( hwnd );
2617         if (!wndPtr)
2618         {
2619             SetLastError( ERROR_INVALID_HANDLE );
2620             return 0;
2621         }
2622         if (wndPtr == WND_DESKTOP) return 0;
2623         if (wndPtr != WND_OTHER_PROCESS)
2624         {
2625             retval = wndPtr->owner;
2626             WIN_ReleasePtr( wndPtr );
2627             return retval;
2628         }
2629         /* else fall through to server call */
2630     }
2631
2632     SERVER_START_REQ( get_window_tree )
2633     {
2634         req->handle = hwnd;
2635         if (!wine_server_call_err( req ))
2636         {
2637             switch(rel)
2638             {
2639             case GW_HWNDFIRST:
2640                 retval = reply->first_sibling;
2641                 break;
2642             case GW_HWNDLAST:
2643                 retval = reply->last_sibling;
2644                 break;
2645             case GW_HWNDNEXT:
2646                 retval = reply->next_sibling;
2647                 break;
2648             case GW_HWNDPREV:
2649                 retval = reply->prev_sibling;
2650                 break;
2651             case GW_OWNER:
2652                 retval = reply->owner;
2653                 break;
2654             case GW_CHILD:
2655                 retval = reply->first_child;
2656                 break;
2657             }
2658         }
2659     }
2660     SERVER_END_REQ;
2661     return retval;
2662 }
2663
2664
2665 /*******************************************************************
2666  *              ShowOwnedPopups (USER32.@)
2667  */
2668 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2669 {
2670     int count = 0;
2671     WND *pWnd;
2672     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2673
2674     if (!win_array) return TRUE;
2675
2676     while (win_array[count]) count++;
2677     while (--count >= 0)
2678     {
2679         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2680         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2681         if (pWnd == WND_OTHER_PROCESS) continue;
2682         if (fShow)
2683         {
2684             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2685             {
2686                 WIN_ReleasePtr( pWnd );
2687                 /* In Windows, ShowOwnedPopups(TRUE) generates
2688                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2689                  * regardless of the state of the owner
2690                  */
2691                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2692                 continue;
2693             }
2694         }
2695         else
2696         {
2697             if (pWnd->dwStyle & WS_VISIBLE)
2698             {
2699                 WIN_ReleasePtr( pWnd );
2700                 /* In Windows, ShowOwnedPopups(FALSE) generates
2701                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2702                  * regardless of the state of the owner
2703                  */
2704                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2705                 continue;
2706             }
2707         }
2708         WIN_ReleasePtr( pWnd );
2709     }
2710     HeapFree( GetProcessHeap(), 0, win_array );
2711     return TRUE;
2712 }
2713
2714
2715 /*******************************************************************
2716  *              GetLastActivePopup (USER32.@)
2717  */
2718 HWND WINAPI GetLastActivePopup( HWND hwnd )
2719 {
2720     HWND retval = hwnd;
2721
2722     SERVER_START_REQ( get_window_info )
2723     {
2724         req->handle = hwnd;
2725         if (!wine_server_call_err( req )) retval = reply->last_active;
2726     }
2727     SERVER_END_REQ;
2728     return retval;
2729 }
2730
2731
2732 /*******************************************************************
2733  *           WIN_ListChildren
2734  *
2735  * Build an array of the children of a given window. The array must be
2736  * freed with HeapFree. Returns NULL when no windows are found.
2737  */
2738 HWND *WIN_ListChildren( HWND hwnd )
2739 {
2740     return list_window_children( hwnd, 0, 0 );
2741 }
2742
2743
2744 /*******************************************************************
2745  *              EnumWindows (USER32.@)
2746  */
2747 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2748 {
2749     HWND *list;
2750     BOOL ret = TRUE;
2751     int i;
2752
2753     USER_CheckNotLock();
2754
2755     /* We have to build a list of all windows first, to avoid */
2756     /* unpleasant side-effects, for instance if the callback */
2757     /* function changes the Z-order of the windows.          */
2758
2759     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2760
2761     /* Now call the callback function for every window */
2762
2763     for (i = 0; list[i]; i++)
2764     {
2765         /* Make sure that the window still exists */
2766         if (!IsWindow( list[i] )) continue;
2767         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2768     }
2769     HeapFree( GetProcessHeap(), 0, list );
2770     return ret;
2771 }
2772
2773
2774 /**********************************************************************
2775  *              EnumThreadWindows (USER32.@)
2776  */
2777 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2778 {
2779     HWND *list;
2780     int i;
2781
2782     USER_CheckNotLock();
2783
2784     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2785
2786     /* Now call the callback function for every window */
2787
2788     for (i = 0; list[i]; i++)
2789         if (!func( list[i], lParam )) break;
2790     HeapFree( GetProcessHeap(), 0, list );
2791     return TRUE;
2792 }
2793
2794
2795 /**********************************************************************
2796  *           WIN_EnumChildWindows
2797  *
2798  * Helper function for EnumChildWindows().
2799  */
2800 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2801 {
2802     HWND *childList;
2803     BOOL ret = FALSE;
2804
2805     for ( ; *list; list++)
2806     {
2807         /* Make sure that the window still exists */
2808         if (!IsWindow( *list )) continue;
2809         /* skip owned windows */
2810         if (GetWindow( *list, GW_OWNER )) continue;
2811         /* Build children list first */
2812         childList = WIN_ListChildren( *list );
2813
2814         ret = func( *list, lParam );
2815
2816         if (childList)
2817         {
2818             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2819             HeapFree( GetProcessHeap(), 0, childList );
2820         }
2821         if (!ret) return FALSE;
2822     }
2823     return TRUE;
2824 }
2825
2826
2827 /**********************************************************************
2828  *              EnumChildWindows (USER32.@)
2829  */
2830 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2831 {
2832     HWND *list;
2833
2834     USER_CheckNotLock();
2835
2836     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2837     WIN_EnumChildWindows( list, func, lParam );
2838     HeapFree( GetProcessHeap(), 0, list );
2839     return TRUE;
2840 }
2841
2842
2843 /*******************************************************************
2844  *              AnyPopup (USER.52)
2845  */
2846 BOOL16 WINAPI AnyPopup16(void)
2847 {
2848     return AnyPopup();
2849 }
2850
2851
2852 /*******************************************************************
2853  *              AnyPopup (USER32.@)
2854  */
2855 BOOL WINAPI AnyPopup(void)
2856 {
2857     int i;
2858     BOOL retvalue;
2859     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2860
2861     if (!list) return FALSE;
2862     for (i = 0; list[i]; i++)
2863     {
2864         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2865     }
2866     retvalue = (list[i] != 0);
2867     HeapFree( GetProcessHeap(), 0, list );
2868     return retvalue;
2869 }
2870
2871
2872 /*******************************************************************
2873  *              FlashWindow (USER32.@)
2874  */
2875 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2876 {
2877     WND *wndPtr;
2878
2879     TRACE("%p\n", hWnd);
2880
2881     if (IsIconic( hWnd ))
2882     {
2883         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2884
2885         wndPtr = WIN_GetPtr(hWnd);
2886         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2887         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2888         {
2889             wndPtr->flags |= WIN_NCACTIVATED;
2890         }
2891         else
2892         {
2893             wndPtr->flags &= ~WIN_NCACTIVATED;
2894         }
2895         WIN_ReleasePtr( wndPtr );
2896         return TRUE;
2897     }
2898     else
2899     {
2900         WPARAM wparam;
2901
2902         wndPtr = WIN_GetPtr(hWnd);
2903         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2904         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2905
2906         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2907         else wparam = (hWnd == GetForegroundWindow());
2908
2909         WIN_ReleasePtr( wndPtr );
2910         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2911         return wparam;
2912     }
2913 }
2914
2915 /*******************************************************************
2916  *              FlashWindowEx (USER32.@)
2917  */
2918 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
2919 {
2920     FIXME("%p\n", pfwi);
2921     return TRUE;
2922 }
2923
2924 /*******************************************************************
2925  *              GetWindowContextHelpId (USER32.@)
2926  */
2927 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2928 {
2929     DWORD retval;
2930     WND *wnd = WIN_GetPtr( hwnd );
2931     if (!wnd || wnd == WND_DESKTOP) return 0;
2932     if (wnd == WND_OTHER_PROCESS)
2933     {
2934         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2935         return 0;
2936     }
2937     retval = wnd->helpContext;
2938     WIN_ReleasePtr( wnd );
2939     return retval;
2940 }
2941
2942
2943 /*******************************************************************
2944  *              SetWindowContextHelpId (USER32.@)
2945  */
2946 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2947 {
2948     WND *wnd = WIN_GetPtr( hwnd );
2949     if (!wnd || wnd == WND_DESKTOP) return FALSE;
2950     if (wnd == WND_OTHER_PROCESS)
2951     {
2952         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
2953         return 0;
2954     }
2955     wnd->helpContext = id;
2956     WIN_ReleasePtr( wnd );
2957     return TRUE;
2958 }
2959
2960
2961 /*******************************************************************
2962  *              DragDetect (USER32.@)
2963  */
2964 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2965 {
2966     MSG msg;
2967     RECT rect;
2968     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
2969     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
2970
2971     rect.left = pt.x - wDragWidth;
2972     rect.right = pt.x + wDragWidth;
2973
2974     rect.top = pt.y - wDragHeight;
2975     rect.bottom = pt.y + wDragHeight;
2976
2977     SetCapture(hWnd);
2978
2979     while(1)
2980     {
2981         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
2982         {
2983             if( msg.message == WM_LBUTTONUP )
2984             {
2985                 ReleaseCapture();
2986                 return 0;
2987             }
2988             if( msg.message == WM_MOUSEMOVE )
2989             {
2990                 POINT tmp;
2991                 tmp.x = LOWORD(msg.lParam);
2992                 tmp.y = HIWORD(msg.lParam);
2993                 if( !PtInRect( &rect, tmp ))
2994                 {
2995                     ReleaseCapture();
2996                     return 1;
2997                 }
2998             }
2999         }
3000         WaitMessage();
3001     }
3002     return 0;
3003 }
3004
3005 /******************************************************************************
3006  *              GetWindowModuleFileNameA (USER32.@)
3007  */
3008 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3009 {
3010     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3011           hwnd, lpszFileName, cchFileNameMax);
3012     return 0;
3013 }
3014
3015 /******************************************************************************
3016  *              GetWindowModuleFileNameW (USER32.@)
3017  */
3018 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3019 {
3020     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3021           hwnd, lpszFileName, cchFileNameMax);
3022     return 0;
3023 }
3024
3025 /******************************************************************************
3026  *              GetWindowInfo (USER32.@)
3027  *
3028  * Note: tests show that Windows doesn't check cbSize of the structure.
3029  */
3030 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3031 {
3032     if (!pwi) return FALSE;
3033     if (!IsWindow(hwnd)) return FALSE;
3034
3035     GetWindowRect(hwnd, &pwi->rcWindow);
3036     GetClientRect(hwnd, &pwi->rcClient);
3037     /* translate to screen coordinates */
3038     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3039
3040     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3041     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3042     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3043
3044     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3045     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3046
3047     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3048     pwi->wCreatorVersion = 0x0400;
3049
3050     return TRUE;
3051 }
3052
3053 /******************************************************************************
3054  *              SwitchDesktop (USER32.@)
3055  *
3056  * NOTES: Sets the current input or interactive desktop.
3057  */
3058 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3059 {
3060     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3061     return TRUE;
3062 }
3063
3064 /*****************************************************************************
3065  *              SetLayeredWindowAttributes (USER32.@)
3066  */
3067 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3068                                         BYTE bAlpha, DWORD dwFlags )
3069 {
3070     FIXME("(%p,0x%.8lx,%d,%ld): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3071     return TRUE;
3072 }