win32u: Open the desktop shared object in NtUserSetThreadDesktop.
[wine.git] / dlls / win32u / winstation.c
blobf1679ac79284ab60e6a67e6b9fc492fefc98b0b7
1 /*
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
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <stddef.h>
29 #include <pthread.h>
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "ntuser.h"
36 #include "ddk/wdm.h"
37 #include "ntgdi_private.h"
38 #include "ntuser_private.h"
39 #include "wine/server.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(winstation);
43 WINE_DECLARE_DEBUG_CHANNEL(win);
46 #define DESKTOP_ALL_ACCESS 0x01ff
48 struct session_thread_data
50 const shared_object_t *shared_desktop; /* thread desktop shared session cached object */
53 struct session_block
55 struct list entry; /* entry in the session block list */
56 const char *data; /* base pointer for the mmaped data */
57 SIZE_T offset; /* offset of data in the session shared mapping */
58 SIZE_T size; /* size of the mmaped data */
61 static pthread_mutex_t session_lock = PTHREAD_MUTEX_INITIALIZER;
62 static struct list session_blocks = LIST_INIT(session_blocks);
64 static struct session_thread_data *get_session_thread_data(void)
66 struct user_thread_info *thread_info = get_user_thread_info();
67 if (!thread_info->session_data) thread_info->session_data = calloc(1, sizeof(*thread_info->session_data));
68 return thread_info->session_data;
71 #if defined(__i386__) || defined(__x86_64__)
72 /* this prevents compilers from incorrectly reordering non-volatile reads (e.g., memcpy) from shared memory */
73 #define __SHARED_READ_FENCE do { __asm__ __volatile__( "" ::: "memory" ); } while (0)
74 #else
75 #define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE )
76 #endif
78 static void shared_object_acquire_seqlock( const shared_object_t *object, UINT64 *seq )
80 while ((*seq = ReadNoFence64( &object->seq )) & 1) YieldProcessor();
81 __SHARED_READ_FENCE;
84 static BOOL shared_object_release_seqlock( const shared_object_t *object, UINT64 seq )
86 __SHARED_READ_FENCE;
87 return ReadNoFence64( &object->seq ) == seq;
90 static object_id_t shared_object_get_id( const shared_object_t *object )
92 struct object_lock lock = OBJECT_LOCK_INIT;
95 shared_object_acquire_seqlock( object, &lock.seq );
96 lock.id = object->id;
97 } while (!shared_object_release_seqlock( object, lock.seq ));
98 return lock.id;
101 static NTSTATUS map_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret )
103 static const WCHAR nameW[] =
105 '\\','K','e','r','n','e','l','O','b','j','e','c','t','s','\\',
106 '_','_','w','i','n','e','_','s','e','s','s','i','o','n',0
108 UNICODE_STRING name = RTL_CONSTANT_STRING( nameW );
109 LARGE_INTEGER off = {.QuadPart = offset - (offset % system_info.AllocationGranularity)};
110 struct session_block *block;
111 OBJECT_ATTRIBUTES attr;
112 unsigned int status;
113 HANDLE handle;
115 assert( offset + size > offset );
117 if (!(block = calloc( 1, sizeof(*block) ))) return STATUS_NO_MEMORY;
119 InitializeObjectAttributes( &attr, &name, 0, NULL, NULL );
120 if ((status = NtOpenSection( &handle, SECTION_MAP_READ, &attr )))
121 WARN( "Failed to open shared session section, status %#x\n", status );
122 else
124 if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), (void **)&block->data, 0, 0,
125 &off, &block->size, ViewUnmap, 0, PAGE_READONLY )))
126 WARN( "Failed to map shared session block, status %#x\n", status );
127 else
129 list_add_tail( &session_blocks, &block->entry );
130 block->offset = off.QuadPart;
131 assert( block->offset + block->size > block->offset );
133 NtClose( handle );
136 if (status) free( block );
137 else *ret = block;
138 return status;
141 static NTSTATUS find_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret )
143 struct session_block *block;
144 UINT status;
146 assert( offset + size > offset );
148 pthread_mutex_lock( &session_lock );
150 LIST_FOR_EACH_ENTRY( block, &session_blocks, struct session_block, entry )
152 if (block->offset < offset && offset + size <= block->offset + block->size)
154 *ret = block;
155 pthread_mutex_unlock( &session_lock );
156 return STATUS_SUCCESS;
160 if ((status = map_shared_session_block( offset, size, ret )))
162 WARN( "Failed to map session block for offset %s, size %s, status %#x\n",
163 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size), status );
166 pthread_mutex_unlock( &session_lock );
168 return status;
171 static const shared_object_t *find_shared_session_object( obj_locator_t locator )
173 const shared_object_t *object;
174 struct session_block *block;
175 NTSTATUS status;
177 if (locator.id && !(status = find_shared_session_block( locator.offset, sizeof(*object), &block )))
179 object = (const shared_object_t *)(block->data + locator.offset - block->offset);
180 if (locator.id == shared_object_get_id( object )) return object;
181 WARN( "Session object id doesn't match expected id %s\n", wine_dbgstr_longlong(locator.id) );
184 return NULL;
187 BOOL is_virtual_desktop(void)
189 HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() );
190 USEROBJECTFLAGS flags = {0};
191 DWORD len;
193 if (!NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len )) return FALSE;
194 return !!(flags.dwFlags & DF_WINE_VIRTUAL_DESKTOP);
197 /***********************************************************************
198 * NtUserCreateWindowStation (win32u.@)
200 HWINSTA WINAPI NtUserCreateWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access, ULONG arg3,
201 ULONG arg4, ULONG arg5, ULONG arg6, ULONG arg7 )
203 HANDLE ret;
205 if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR))
207 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE );
208 return 0;
211 SERVER_START_REQ( create_winstation )
213 req->flags = 0;
214 req->access = access;
215 req->attributes = attr->Attributes;
216 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
217 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
218 wine_server_call_err( req );
219 ret = wine_server_ptr_handle( reply->handle );
221 SERVER_END_REQ;
222 return ret;
225 /******************************************************************************
226 * NtUserOpenWindowStation (win32u.@)
228 HWINSTA WINAPI NtUserOpenWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access )
230 HANDLE ret = 0;
232 SERVER_START_REQ( open_winstation )
234 req->access = access;
235 req->attributes = attr->Attributes;
236 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
237 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
238 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
240 SERVER_END_REQ;
241 return ret;
244 /***********************************************************************
245 * NtUserCloseWindowStation (win32u.@)
247 BOOL WINAPI NtUserCloseWindowStation( HWINSTA handle )
249 BOOL ret;
250 SERVER_START_REQ( close_winstation )
252 req->handle = wine_server_obj_handle( handle );
253 ret = !wine_server_call_err( req );
255 SERVER_END_REQ;
256 return ret;
259 /***********************************************************************
260 * NtUSerGetProcessWindowStation (win32u.@)
262 HWINSTA WINAPI NtUserGetProcessWindowStation(void)
264 HWINSTA ret = 0;
266 SERVER_START_REQ( get_process_winstation )
268 if (!wine_server_call_err( req ))
269 ret = wine_server_ptr_handle( reply->handle );
271 SERVER_END_REQ;
272 return ret;
275 /***********************************************************************
276 * NtUserSetProcessWindowStation (win32u.@)
278 BOOL WINAPI NtUserSetProcessWindowStation( HWINSTA handle )
280 BOOL ret;
282 SERVER_START_REQ( set_process_winstation )
284 req->handle = wine_server_obj_handle( handle );
285 ret = !wine_server_call_err( req );
287 SERVER_END_REQ;
288 return ret;
291 /***********************************************************************
292 * NtUserCreateDesktopEx (win32u.@)
294 HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *device,
295 DEVMODEW *devmode, DWORD flags, ACCESS_MASK access,
296 ULONG heap_size )
298 WCHAR buffer[MAX_PATH];
299 HANDLE ret;
301 if ((device && device->Length) || (devmode && !(flags & DF_WINE_VIRTUAL_DESKTOP)))
303 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
304 return 0;
306 if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR))
308 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE );
309 return 0;
311 SERVER_START_REQ( create_desktop )
313 req->flags = flags;
314 req->access = access;
315 req->attributes = attr->Attributes;
316 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
317 wine_server_call_err( req );
318 ret = wine_server_ptr_handle( reply->handle );
320 SERVER_END_REQ;
321 if (!devmode) return ret;
323 lstrcpynW( buffer, attr->ObjectName->Buffer, attr->ObjectName->Length / sizeof(WCHAR) + 1 );
324 if (!user_driver->pCreateDesktop( buffer, devmode->dmPelsWidth, devmode->dmPelsHeight ))
326 NtUserCloseDesktop( ret );
327 return 0;
330 /* force update display cache to use virtual desktop display settings */
331 if (flags & DF_WINE_VIRTUAL_DESKTOP) update_display_cache( TRUE );
332 return ret;
335 /***********************************************************************
336 * NtUserOpenDesktop (win32u.@)
338 HDESK WINAPI NtUserOpenDesktop( OBJECT_ATTRIBUTES *attr, DWORD flags, ACCESS_MASK access )
340 HANDLE ret = 0;
341 if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR))
343 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE );
344 return 0;
346 SERVER_START_REQ( open_desktop )
348 req->winsta = wine_server_obj_handle( attr->RootDirectory );
349 req->flags = flags;
350 req->access = access;
351 req->attributes = attr->Attributes;
352 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
353 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
355 SERVER_END_REQ;
356 return ret;
359 /***********************************************************************
360 * NtUserCloseDesktop (win32u.@)
362 BOOL WINAPI NtUserCloseDesktop( HDESK handle )
364 BOOL ret;
365 SERVER_START_REQ( close_desktop )
367 req->handle = wine_server_obj_handle( handle );
368 ret = !wine_server_call_err( req );
370 SERVER_END_REQ;
371 return ret;
374 /***********************************************************************
375 * NtUserGetThreadDesktop (win32u.@)
377 HDESK WINAPI NtUserGetThreadDesktop( DWORD thread )
379 HDESK ret = 0;
381 SERVER_START_REQ( get_thread_desktop )
383 req->tid = thread;
384 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
386 SERVER_END_REQ;
387 return ret;
390 /***********************************************************************
391 * NtUserSetThreadDesktop (win32u.@)
393 BOOL WINAPI NtUserSetThreadDesktop( HDESK handle )
395 BOOL ret, was_virtual_desktop = is_virtual_desktop();
396 obj_locator_t locator;
398 SERVER_START_REQ( set_thread_desktop )
400 req->handle = wine_server_obj_handle( handle );
401 ret = !wine_server_call_err( req );
402 locator = reply->locator;
404 SERVER_END_REQ;
406 if (ret) /* reset the desktop windows */
408 struct user_thread_info *thread_info = get_user_thread_info();
409 struct user_key_state_info *key_state_info = thread_info->key_state;
410 get_session_thread_data()->shared_desktop = find_shared_session_object( locator );
411 thread_info->client_info.top_window = 0;
412 thread_info->client_info.msg_window = 0;
413 if (key_state_info) key_state_info->time = 0;
414 if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( FALSE );
416 return ret;
419 /***********************************************************************
420 * NtUserOpenInputDesktop (win32u.@)
422 HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
424 HANDLE ret = 0;
426 TRACE( "(%x,%i,%x)\n", (int)flags, inherit, (int)access );
428 if (flags)
429 FIXME( "partial stub flags %08x\n", (int)flags );
431 SERVER_START_REQ( open_input_desktop )
433 req->flags = flags;
434 req->access = access;
435 req->attributes = inherit ? OBJ_INHERIT : 0;
436 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
438 SERVER_END_REQ;
440 return ret;
443 BOOL WINAPI NtUserSwitchDesktop( HDESK desktop )
445 TRACE( "desktop %p\n", desktop );
447 SERVER_START_REQ( set_input_desktop )
449 req->handle = wine_server_obj_handle( desktop );
450 if (wine_server_call_err( req )) return FALSE;
452 SERVER_END_REQ;
454 return TRUE;
457 /***********************************************************************
458 * NtUserGetObjectInformation (win32u.@)
460 BOOL WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, void *info,
461 DWORD len, DWORD *needed )
463 BOOL ret;
465 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
466 static const WCHAR window_stationW[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n',0};
468 switch(index)
470 case UOI_FLAGS:
472 USEROBJECTFLAGS *obj_flags = info;
473 if (needed) *needed = sizeof(*obj_flags);
474 if (len < sizeof(*obj_flags))
476 RtlSetLastWin32Error( ERROR_BUFFER_OVERFLOW );
477 return FALSE;
479 SERVER_START_REQ( set_user_object_info )
481 req->handle = wine_server_obj_handle( handle );
482 req->flags = 0;
483 ret = !wine_server_call_err( req );
484 if (ret)
486 /* FIXME: inherit flag */
487 obj_flags->dwFlags = reply->old_obj_flags;
490 SERVER_END_REQ;
492 return ret;
494 case UOI_TYPE:
495 SERVER_START_REQ( set_user_object_info )
497 req->handle = wine_server_obj_handle( handle );
498 req->flags = 0;
499 ret = !wine_server_call_err( req );
500 if (ret)
502 size_t size = reply->is_desktop ? sizeof(desktopW) : sizeof(window_stationW);
503 if (needed) *needed = size;
504 if (len < size)
506 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
507 ret = FALSE;
509 else memcpy( info, reply->is_desktop ? desktopW : window_stationW, size );
512 SERVER_END_REQ;
513 return ret;
515 case UOI_NAME:
517 WCHAR buffer[MAX_PATH];
518 SERVER_START_REQ( set_user_object_info )
520 req->handle = wine_server_obj_handle( handle );
521 req->flags = 0;
522 wine_server_set_reply( req, buffer, sizeof(buffer) - sizeof(WCHAR) );
523 ret = !wine_server_call_err( req );
524 if (ret)
526 size_t size = wine_server_reply_size( reply );
527 buffer[size / sizeof(WCHAR)] = 0;
528 size += sizeof(WCHAR);
529 if (needed) *needed = size;
530 if (len < size)
532 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
533 ret = FALSE;
535 else memcpy( info, buffer, size );
538 SERVER_END_REQ;
540 return ret;
542 case UOI_USER_SID:
543 FIXME( "not supported index %d\n", index );
544 /* fall through */
545 default:
546 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
547 return FALSE;
551 /***********************************************************************
552 * NtUserSetObjectInformation (win32u.@)
554 BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DWORD len )
556 BOOL ret;
557 const USEROBJECTFLAGS *obj_flags = info;
559 if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags))
561 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
562 return FALSE;
564 /* FIXME: inherit flag */
565 SERVER_START_REQ( set_user_object_info )
567 req->handle = wine_server_obj_handle( handle );
568 req->flags = SET_USER_OBJECT_SET_FLAGS;
569 req->obj_flags = obj_flags->dwFlags;
570 ret = !wine_server_call_err( req );
572 SERVER_END_REQ;
573 return ret;
576 #ifdef _WIN64
577 static inline TEB64 *NtCurrentTeb64(void) { return NULL; }
578 #else
579 static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; }
580 #endif
582 HWND get_desktop_window(void)
584 static const WCHAR wine_service_station_name[] =
585 {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n',0};
586 struct ntuser_thread_info *thread_info = NtUserGetThreadInfo();
587 WCHAR name[MAX_PATH];
588 BOOL is_service;
590 if (thread_info->top_window) return UlongToHandle( thread_info->top_window );
592 /* don't create an actual explorer desktop window for services */
593 if (NtUserGetObjectInformation( NtUserGetProcessWindowStation(), UOI_NAME, name, sizeof(name), NULL )
594 && !wcscmp( name, wine_service_station_name ))
595 is_service = TRUE;
596 else
597 is_service = FALSE;
599 SERVER_START_REQ( get_desktop_window )
601 req->force = is_service;
602 if (!wine_server_call( req ))
604 thread_info->top_window = reply->top_window;
605 thread_info->msg_window = reply->msg_window;
608 SERVER_END_REQ;
610 if (!thread_info->top_window)
612 static const WCHAR appnameW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s',
613 '\\','s','y','s','t','e','m','3','2','\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
614 static const WCHAR cmdlineW[] = {'"','C',':','\\','w','i','n','d','o','w','s','\\',
615 's','y','s','t','e','m','3','2','\\','e','x','p','l','o','r','e','r','.','e','x','e','"',
616 ' ','/','d','e','s','k','t','o','p',0};
617 static const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
618 's','y','s','t','e','m','3','2','\\',0};
619 RTL_USER_PROCESS_PARAMETERS params = { sizeof(params), sizeof(params) };
620 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)];
621 PS_ATTRIBUTE_LIST *ps_attr = (PS_ATTRIBUTE_LIST *)buffer;
622 PS_CREATE_INFO create_info;
623 WCHAR desktop[MAX_PATH];
624 PEB *peb = NtCurrentTeb()->Peb;
625 HANDLE process, thread;
626 unsigned int status;
628 SERVER_START_REQ( set_user_object_info )
630 req->handle = wine_server_obj_handle( NtUserGetThreadDesktop(GetCurrentThreadId()) );
631 req->flags = SET_USER_OBJECT_GET_FULL_NAME;
632 wine_server_set_reply( req, desktop, sizeof(desktop) - sizeof(WCHAR) );
633 if (!wine_server_call( req ))
635 size_t size = wine_server_reply_size( reply );
636 desktop[size / sizeof(WCHAR)] = 0;
637 TRACE( "starting explorer for desktop %s\n", debugstr_w(desktop) );
639 else
640 desktop[0] = 0;
642 SERVER_END_REQ;
644 params.Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
645 params.Environment = peb->ProcessParameters->Environment;
646 params.EnvironmentSize = peb->ProcessParameters->EnvironmentSize;
647 params.hStdError = peb->ProcessParameters->hStdError;
648 RtlInitUnicodeString( &params.CurrentDirectory.DosPath, system_dir );
649 RtlInitUnicodeString( &params.ImagePathName, appnameW + 4 );
650 RtlInitUnicodeString( &params.CommandLine, cmdlineW );
651 RtlInitUnicodeString( &params.WindowTitle, appnameW + 4 );
652 RtlInitUnicodeString( &params.Desktop, desktop );
654 ps_attr->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
655 ps_attr->Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR);
656 ps_attr->Attributes[0].ValuePtr = (WCHAR *)appnameW;
657 ps_attr->Attributes[0].ReturnLength = NULL;
659 ps_attr->Attributes[1].Attribute = PS_ATTRIBUTE_TOKEN;
660 ps_attr->Attributes[1].Size = sizeof(HANDLE);
661 ps_attr->Attributes[1].ValuePtr = GetCurrentThreadEffectiveToken();
662 ps_attr->Attributes[1].ReturnLength = NULL;
664 ps_attr->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[2] );
666 if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR])
668 NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = TRUE;
669 status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
670 NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, &params,
671 &create_info, ps_attr );
672 NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = FALSE;
674 else
675 status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
676 NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, &params,
677 &create_info, ps_attr );
678 if (!status)
680 NtResumeThread( thread, NULL );
681 TRACE_(win)( "started explorer\n" );
682 NtUserWaitForInputIdle( process, 10000, FALSE );
683 NtClose( thread );
684 NtClose( process );
686 else ERR_(win)( "failed to start explorer %x\n", status );
688 SERVER_START_REQ( get_desktop_window )
690 req->force = 1;
691 if (!wine_server_call( req ))
693 thread_info->top_window = reply->top_window;
694 thread_info->msg_window = reply->msg_window;
697 SERVER_END_REQ;
700 if (!thread_info->top_window) ERR_(win)( "failed to create desktop window\n" );
701 else user_driver->pSetDesktopWindow( UlongToHandle( thread_info->top_window ));
703 register_builtin_classes();
704 return UlongToHandle( thread_info->top_window );
707 static HANDLE get_winstations_dir_handle(void)
709 char bufferA[64];
710 WCHAR buffer[64];
711 UNICODE_STRING str;
712 OBJECT_ATTRIBUTES attr;
713 NTSTATUS status;
714 HANDLE dir;
716 snprintf( bufferA, sizeof(bufferA), "\\Sessions\\%u\\Windows\\WindowStations", (int)NtCurrentTeb()->Peb->SessionId );
717 str.Buffer = buffer;
718 str.MaximumLength = asciiz_to_unicode( buffer, bufferA );
719 str.Length = str.MaximumLength - sizeof(WCHAR);
720 InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
721 status = NtOpenDirectoryObject( &dir, DIRECTORY_CREATE_OBJECT | DIRECTORY_TRAVERSE, &attr );
722 return status ? 0 : dir;
725 /***********************************************************************
726 * get_default_desktop
728 * Get the name of the desktop to use for this app if not specified explicitly.
730 static const WCHAR *get_default_desktop( void *buf, size_t buf_size )
732 const WCHAR *p, *appname = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
733 KEY_VALUE_PARTIAL_INFORMATION *info = buf;
734 WCHAR *buffer = buf;
735 HKEY tmpkey, appkey;
736 DWORD len;
738 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
740 if ((p = wcsrchr( appname, '/' ))) appname = p + 1;
741 if ((p = wcsrchr( appname, '\\' ))) appname = p + 1;
742 len = lstrlenW(appname);
743 if (len > MAX_PATH) return defaultW;
744 memcpy( buffer, appname, len * sizeof(WCHAR) );
745 asciiz_to_unicode( buffer + len, "\\Explorer" );
747 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Explorer */
748 if ((tmpkey = reg_open_hkcu_key( "Software\\Wine\\AppDefaults" )))
750 appkey = reg_open_key( tmpkey, buffer, lstrlenW(buffer) * sizeof(WCHAR) );
751 NtClose( tmpkey );
752 if (appkey)
754 len = query_reg_ascii_value( appkey, "Desktop", info, buf_size );
755 NtClose( appkey );
756 if (len) return (const WCHAR *)info->Data;
760 /* @@ Wine registry key: HKCU\Software\Wine\Explorer */
761 if ((appkey = reg_open_hkcu_key( "Software\\Wine\\Explorer" )))
763 len = query_reg_ascii_value( appkey, "Desktop", info, buf_size );
764 NtClose( appkey );
765 if (len) return (const WCHAR *)info->Data;
768 return defaultW;
771 /***********************************************************************
772 * winstation_init
774 * Connect to the process window station and desktop.
776 void winstation_init(void)
778 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
779 WCHAR *winstation = NULL, *desktop = NULL, *buffer = NULL;
780 HANDLE handle, dir = NULL;
781 OBJECT_ATTRIBUTES attr;
782 UNICODE_STRING str;
784 static const WCHAR winsta0[] = {'W','i','n','S','t','a','0',0};
786 if (params->Desktop.Length)
788 buffer = malloc( params->Desktop.Length + sizeof(WCHAR) );
789 memcpy( buffer, params->Desktop.Buffer, params->Desktop.Length );
790 buffer[params->Desktop.Length / sizeof(WCHAR)] = 0;
791 if ((desktop = wcschr( buffer, '\\' )))
793 *desktop++ = 0;
794 winstation = buffer;
796 else desktop = buffer;
799 /* set winstation if explicitly specified, or if we don't have one yet */
800 if (buffer || !NtUserGetProcessWindowStation())
802 str.Buffer = (WCHAR *)(winstation ? winstation : winsta0);
803 str.Length = str.MaximumLength = lstrlenW( str.Buffer ) * sizeof(WCHAR);
804 dir = get_winstations_dir_handle();
805 InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
806 dir, NULL );
808 handle = NtUserCreateWindowStation( &attr, STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS, 0, 0, 0, 0, 0 );
809 if (handle)
811 NtUserSetProcessWindowStation( handle );
812 /* only WinSta0 is visible */
813 if (!winstation || !wcsicmp( winstation, winsta0 ))
815 USEROBJECTFLAGS flags;
816 flags.fInherit = FALSE;
817 flags.fReserved = FALSE;
818 flags.dwFlags = WSF_VISIBLE;
819 NtUserSetObjectInformation( handle, UOI_FLAGS, &flags, sizeof(flags) );
823 if (buffer || !NtUserGetThreadDesktop( GetCurrentThreadId() ))
825 char buffer[4096];
826 str.Buffer = (WCHAR *)(desktop ? desktop : get_default_desktop( buffer, sizeof(buffer) ));
827 str.Length = str.MaximumLength = lstrlenW( str.Buffer ) * sizeof(WCHAR);
828 if (!dir) dir = get_winstations_dir_handle();
829 InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
830 dir, NULL );
832 handle = NtUserCreateDesktopEx( &attr, NULL, NULL, 0, STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS, 0 );
833 if (handle) NtUserSetThreadDesktop( handle );
835 NtClose( dir );
836 free( buffer );