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