2 * Window stations and desktops
4 * Copyright 2002 Alexandre Julliard
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.
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.
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
26 #define WIN32_NO_STATUS
32 #include "ntgdi_private.h"
33 #include "ntuser_private.h"
34 #include "wine/server.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(winstation
);
38 WINE_DECLARE_DEBUG_CHANNEL(win
);
41 #define DESKTOP_ALL_ACCESS 0x01ff
43 /***********************************************************************
44 * NtUserCreateWindowStation (win32u.@)
46 HWINSTA WINAPI
NtUserCreateWindowStation( OBJECT_ATTRIBUTES
*attr
, ACCESS_MASK access
, ULONG arg3
,
47 ULONG arg4
, ULONG arg5
, ULONG arg6
, ULONG arg7
)
51 if (attr
->ObjectName
->Length
>= MAX_PATH
* sizeof(WCHAR
))
53 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
57 SERVER_START_REQ( create_winstation
)
61 req
->attributes
= attr
->Attributes
;
62 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
63 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
64 wine_server_call_err( req
);
65 ret
= wine_server_ptr_handle( reply
->handle
);
71 /******************************************************************************
72 * NtUserOpenWindowStation (win32u.@)
74 HWINSTA WINAPI
NtUserOpenWindowStation( OBJECT_ATTRIBUTES
*attr
, ACCESS_MASK access
)
78 SERVER_START_REQ( open_winstation
)
81 req
->attributes
= attr
->Attributes
;
82 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
83 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
84 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
90 /***********************************************************************
91 * NtUserCloseWindowStation (win32u.@)
93 BOOL WINAPI
NtUserCloseWindowStation( HWINSTA handle
)
96 SERVER_START_REQ( close_winstation
)
98 req
->handle
= wine_server_obj_handle( handle
);
99 ret
= !wine_server_call_err( req
);
105 /***********************************************************************
106 * NtUSerGetProcessWindowStation (win32u.@)
108 HWINSTA WINAPI
NtUserGetProcessWindowStation(void)
112 SERVER_START_REQ( get_process_winstation
)
114 if (!wine_server_call_err( req
))
115 ret
= wine_server_ptr_handle( reply
->handle
);
121 /***********************************************************************
122 * NtUserSetProcessWindowStation (win32u.@)
124 BOOL WINAPI
NtUserSetProcessWindowStation( HWINSTA handle
)
128 SERVER_START_REQ( set_process_winstation
)
130 req
->handle
= wine_server_obj_handle( handle
);
131 ret
= !wine_server_call_err( req
);
137 /***********************************************************************
138 * NtUserCreateDesktopEx (win32u.@)
140 HDESK WINAPI
NtUserCreateDesktopEx( OBJECT_ATTRIBUTES
*attr
, UNICODE_STRING
*device
,
141 DEVMODEW
*devmode
, DWORD flags
, ACCESS_MASK access
,
146 if ((device
&& device
->Length
) || devmode
)
148 SetLastError( ERROR_INVALID_PARAMETER
);
151 if (attr
->ObjectName
->Length
>= MAX_PATH
* sizeof(WCHAR
))
153 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
156 SERVER_START_REQ( create_desktop
)
159 req
->access
= access
;
160 req
->attributes
= attr
->Attributes
;
161 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
162 wine_server_call_err( req
);
163 ret
= wine_server_ptr_handle( reply
->handle
);
169 /***********************************************************************
170 * NtUserOpenDesktop (win32u.@)
172 HDESK WINAPI
NtUserOpenDesktop( OBJECT_ATTRIBUTES
*attr
, DWORD flags
, ACCESS_MASK access
)
175 if (attr
->ObjectName
->Length
>= MAX_PATH
* sizeof(WCHAR
))
177 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
180 SERVER_START_REQ( open_desktop
)
182 req
->winsta
= wine_server_obj_handle( attr
->RootDirectory
);
184 req
->access
= access
;
185 req
->attributes
= attr
->Attributes
;
186 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
187 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
193 /***********************************************************************
194 * NtUserCloseDesktop (win32u.@)
196 BOOL WINAPI
NtUserCloseDesktop( HDESK handle
)
199 SERVER_START_REQ( close_desktop
)
201 req
->handle
= wine_server_obj_handle( handle
);
202 ret
= !wine_server_call_err( req
);
208 /***********************************************************************
209 * NtUserGetThreadDesktop (win32u.@)
211 HDESK WINAPI
NtUserGetThreadDesktop( DWORD thread
)
215 SERVER_START_REQ( get_thread_desktop
)
218 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
224 /***********************************************************************
225 * NtUserSetThreadDesktop (win32u.@)
227 BOOL WINAPI
NtUserSetThreadDesktop( HDESK handle
)
231 SERVER_START_REQ( set_thread_desktop
)
233 req
->handle
= wine_server_obj_handle( handle
);
234 ret
= !wine_server_call_err( req
);
238 if (ret
) /* reset the desktop windows */
240 struct user_thread_info
*thread_info
= get_user_thread_info();
241 struct user_key_state_info
*key_state_info
= thread_info
->key_state
;
242 thread_info
->client_info
.top_window
= 0;
243 thread_info
->client_info
.msg_window
= 0;
244 if (key_state_info
) key_state_info
->time
= 0;
249 /***********************************************************************
250 * NtUserOpenInputDesktop (win32u.@)
252 HDESK WINAPI
NtUserOpenInputDesktop( DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
256 TRACE( "(%x,%i,%x)\n", flags
, inherit
, access
);
259 FIXME( "partial stub flags %08x\n", flags
);
261 SERVER_START_REQ( open_input_desktop
)
264 req
->access
= access
;
265 req
->attributes
= inherit
? OBJ_INHERIT
: 0;
266 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
273 /***********************************************************************
274 * NtUserGetObjectInformation (win32u.@)
276 BOOL WINAPI
NtUserGetObjectInformation( HANDLE handle
, INT index
, void *info
,
277 DWORD len
, DWORD
*needed
)
281 static const WCHAR desktopW
[] = {'D','e','s','k','t','o','p',0};
282 static const WCHAR window_stationW
[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n',0};
288 USEROBJECTFLAGS
*obj_flags
= info
;
289 if (needed
) *needed
= sizeof(*obj_flags
);
290 if (len
< sizeof(*obj_flags
))
292 SetLastError( ERROR_BUFFER_OVERFLOW
);
295 SERVER_START_REQ( set_user_object_info
)
297 req
->handle
= wine_server_obj_handle( handle
);
299 ret
= !wine_server_call_err( req
);
302 /* FIXME: inherit flag */
303 obj_flags
->dwFlags
= reply
->old_obj_flags
;
311 SERVER_START_REQ( set_user_object_info
)
313 req
->handle
= wine_server_obj_handle( handle
);
315 ret
= !wine_server_call_err( req
);
318 size_t size
= reply
->is_desktop
? sizeof(desktopW
) : sizeof(window_stationW
);
319 if (needed
) *needed
= size
;
322 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
325 else memcpy( info
, reply
->is_desktop
? desktopW
: window_stationW
, size
);
333 WCHAR buffer
[MAX_PATH
];
334 SERVER_START_REQ( set_user_object_info
)
336 req
->handle
= wine_server_obj_handle( handle
);
338 wine_server_set_reply( req
, buffer
, sizeof(buffer
) - sizeof(WCHAR
) );
339 ret
= !wine_server_call_err( req
);
342 size_t size
= wine_server_reply_size( reply
);
343 buffer
[size
/ sizeof(WCHAR
)] = 0;
344 size
+= sizeof(WCHAR
);
345 if (needed
) *needed
= size
;
348 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
351 else memcpy( info
, buffer
, size
);
359 FIXME( "not supported index %d\n", index
);
362 SetLastError( ERROR_INVALID_PARAMETER
);
367 /***********************************************************************
368 * NtUserSetObjectInformation (win32u.@)
370 BOOL WINAPI
NtUserSetObjectInformation( HANDLE handle
, INT index
, void *info
, DWORD len
)
373 const USEROBJECTFLAGS
*obj_flags
= info
;
375 if (index
!= UOI_FLAGS
|| !info
|| len
< sizeof(*obj_flags
))
377 SetLastError( ERROR_INVALID_PARAMETER
);
380 /* FIXME: inherit flag */
381 SERVER_START_REQ( set_user_object_info
)
383 req
->handle
= wine_server_obj_handle( handle
);
384 req
->flags
= SET_USER_OBJECT_SET_FLAGS
;
385 req
->obj_flags
= obj_flags
->dwFlags
;
386 ret
= !wine_server_call_err( req
);
393 static inline TEB64
*NtCurrentTeb64(void) { return NULL
; }
395 static inline TEB64
*NtCurrentTeb64(void) { return (TEB64
*)NtCurrentTeb()->GdiBatchCount
; }
398 HWND
get_desktop_window(void)
400 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
402 if (thread_info
->top_window
) return UlongToHandle( thread_info
->top_window
);
405 SERVER_START_REQ( get_desktop_window
)
408 if (!wine_server_call( req
))
410 thread_info
->top_window
= reply
->top_window
;
411 thread_info
->msg_window
= reply
->msg_window
;
416 if (!thread_info
->top_window
)
418 static const WCHAR appnameW
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s',
419 '\\','s','y','s','t','e','m','3','2','\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
420 static const WCHAR cmdlineW
[] = {'"','C',':','\\','w','i','n','d','o','w','s','\\',
421 's','y','s','t','e','m','3','2','\\','e','x','p','l','o','r','e','r','.','e','x','e','"',
422 ' ','/','d','e','s','k','t','o','p',0};
423 static const WCHAR system_dir
[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
424 's','y','s','t','e','m','3','2','\\',0};
425 RTL_USER_PROCESS_PARAMETERS params
= { sizeof(params
), sizeof(params
) };
426 PS_ATTRIBUTE_LIST ps_attr
;
427 PS_CREATE_INFO create_info
;
428 WCHAR desktop
[MAX_PATH
];
429 PEB
*peb
= NtCurrentTeb()->Peb
;
430 HANDLE process
, thread
;
433 SERVER_START_REQ( set_user_object_info
)
435 req
->handle
= wine_server_obj_handle( NtUserGetThreadDesktop(GetCurrentThreadId()) );
436 req
->flags
= SET_USER_OBJECT_GET_FULL_NAME
;
437 wine_server_set_reply( req
, desktop
, sizeof(desktop
) - sizeof(WCHAR
) );
438 if (!wine_server_call( req
))
440 size_t size
= wine_server_reply_size( reply
);
441 desktop
[size
/ sizeof(WCHAR
)] = 0;
442 TRACE( "starting explorer for desktop %s\n", debugstr_w(desktop
) );
449 params
.Flags
= PROCESS_PARAMS_FLAG_NORMALIZED
;
450 params
.Environment
= peb
->ProcessParameters
->Environment
;
451 params
.EnvironmentSize
= peb
->ProcessParameters
->EnvironmentSize
;
452 params
.hStdError
= peb
->ProcessParameters
->hStdError
;
453 RtlInitUnicodeString( ¶ms
.CurrentDirectory
.DosPath
, system_dir
);
454 RtlInitUnicodeString( ¶ms
.ImagePathName
, appnameW
+ 4 );
455 RtlInitUnicodeString( ¶ms
.CommandLine
, cmdlineW
);
456 RtlInitUnicodeString( ¶ms
.WindowTitle
, appnameW
+ 4 );
457 RtlInitUnicodeString( ¶ms
.Desktop
, desktop
);
459 ps_attr
.TotalLength
= sizeof(ps_attr
);
460 ps_attr
.Attributes
[0].Attribute
= PS_ATTRIBUTE_IMAGE_NAME
;
461 ps_attr
.Attributes
[0].Size
= sizeof(appnameW
) - sizeof(WCHAR
);
462 ps_attr
.Attributes
[0].ValuePtr
= (WCHAR
*)appnameW
;
463 ps_attr
.Attributes
[0].ReturnLength
= NULL
;
465 if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
])
467 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = TRUE
;
468 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
469 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, ¶ms
,
470 &create_info
, &ps_attr
);
471 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = FALSE
;
474 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
475 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, ¶ms
,
476 &create_info
, &ps_attr
);
479 NtResumeThread( thread
, NULL
);
480 TRACE_(win
)( "started explorer\n" );
481 NtUserWaitForInputIdle( process
, 10000, FALSE
);
485 else ERR_(win
)( "failed to start explorer %x\n", status
);
487 SERVER_START_REQ( get_desktop_window
)
490 if (!wine_server_call( req
))
492 thread_info
->top_window
= reply
->top_window
;
493 thread_info
->msg_window
= reply
->msg_window
;
499 if (!thread_info
->top_window
||
500 !user_driver
->pCreateDesktopWindow( UlongToHandle( thread_info
->top_window
)))
501 ERR_(win
)( "failed to create desktop window\n" );
503 register_builtin_classes();
504 return UlongToHandle( thread_info
->top_window
);
507 static HANDLE
get_winstations_dir_handle(void)
512 OBJECT_ATTRIBUTES attr
;
516 sprintf( bufferA
, "\\Sessions\\%u\\Windows\\WindowStations", NtCurrentTeb()->Peb
->SessionId
);
518 str
.Length
= str
.MaximumLength
= asciiz_to_unicode( buffer
, bufferA
) - sizeof(WCHAR
);
519 InitializeObjectAttributes( &attr
, &str
, 0, 0, NULL
);
520 status
= NtOpenDirectoryObject( &dir
, DIRECTORY_CREATE_OBJECT
| DIRECTORY_TRAVERSE
, &attr
);
521 return status
? 0 : dir
;
524 /***********************************************************************
525 * get_default_desktop
527 * Get the name of the desktop to use for this app if not specified explicitly.
529 static const WCHAR
*get_default_desktop( void *buf
, size_t buf_size
)
531 const WCHAR
*p
, *appname
= NtCurrentTeb()->Peb
->ProcessParameters
->ImagePathName
.Buffer
;
532 KEY_VALUE_PARTIAL_INFORMATION
*info
= buf
;
537 static const WCHAR defaultW
[] = {'D','e','f','a','u','l','t',0};
539 if ((p
= wcsrchr( appname
, '/' ))) appname
= p
+ 1;
540 if ((p
= wcsrchr( appname
, '\\' ))) appname
= p
+ 1;
541 len
= lstrlenW(appname
);
542 if (len
> MAX_PATH
) return defaultW
;
543 memcpy( buffer
, appname
, len
* sizeof(WCHAR
) );
544 asciiz_to_unicode( buffer
+ len
, "\\Explorer" );
546 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Explorer */
547 if ((tmpkey
= reg_open_hkcu_key( "Software\\Wine\\AppDefaults" )))
549 appkey
= reg_open_key( tmpkey
, buffer
, lstrlenW(buffer
) * sizeof(WCHAR
) );
553 len
= query_reg_ascii_value( appkey
, "Desktop", info
, buf_size
);
555 if (len
) return (const WCHAR
*)info
->Data
;
559 /* @@ Wine registry key: HKCU\Software\Wine\Explorer */
560 if ((appkey
= reg_open_hkcu_key( "Software\\Wine\\Explorer" )))
562 len
= query_reg_ascii_value( appkey
, "Desktop", info
, buf_size
);
564 if (len
) return (const WCHAR
*)info
->Data
;
570 /***********************************************************************
573 * Connect to the process window station and desktop.
575 void winstation_init(void)
577 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
578 WCHAR
*winstation
= NULL
, *desktop
= NULL
, *buffer
= NULL
;
579 HANDLE handle
, dir
= NULL
;
580 OBJECT_ATTRIBUTES attr
;
583 static const WCHAR winsta0
[] = {'W','i','n','S','t','a','0',0};
585 if (params
->Desktop
.Length
)
587 buffer
= malloc( params
->Desktop
.Length
+ sizeof(WCHAR
) );
588 memcpy( buffer
, params
->Desktop
.Buffer
, params
->Desktop
.Length
);
589 buffer
[params
->Desktop
.Length
/ sizeof(WCHAR
)] = 0;
590 if ((desktop
= wcschr( buffer
, '\\' )))
595 else desktop
= buffer
;
598 /* set winstation if explicitly specified, or if we don't have one yet */
599 if (buffer
|| !NtUserGetProcessWindowStation())
601 str
.Buffer
= (WCHAR
*)(winstation
? winstation
: winsta0
);
602 str
.Length
= str
.MaximumLength
= lstrlenW( str
.Buffer
) * sizeof(WCHAR
);
603 dir
= get_winstations_dir_handle();
604 InitializeObjectAttributes( &attr
, &str
, OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
607 handle
= NtUserCreateWindowStation( &attr
, WINSTA_ALL_ACCESS
, 0, 0, 0, 0, 0 );
610 NtUserSetProcessWindowStation( handle
);
611 /* only WinSta0 is visible */
612 if (!winstation
|| !wcsicmp( winstation
, winsta0
))
614 USEROBJECTFLAGS flags
;
615 flags
.fInherit
= FALSE
;
616 flags
.fReserved
= FALSE
;
617 flags
.dwFlags
= WSF_VISIBLE
;
618 NtUserSetObjectInformation( handle
, UOI_FLAGS
, &flags
, sizeof(flags
) );
622 if (buffer
|| !NtUserGetThreadDesktop( GetCurrentThreadId() ))
625 str
.Buffer
= (WCHAR
*)(desktop
? desktop
: get_default_desktop( buffer
, sizeof(buffer
) ));
626 str
.Length
= str
.MaximumLength
= lstrlenW( str
.Buffer
) * sizeof(WCHAR
);
627 if (!dir
) dir
= get_winstations_dir_handle();
628 InitializeObjectAttributes( &attr
, &str
, OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
631 handle
= NtUserCreateDesktopEx( &attr
, NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, 0 );
632 if (handle
) NtUserSetThreadDesktop( handle
);