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