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