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