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
32 #define WIN32_NO_STATUS
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 */
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)
75 #define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE )
78 static void shared_object_acquire_seqlock( const shared_object_t
*object
, UINT64
*seq
)
80 while ((*seq
= ReadNoFence64( &object
->seq
)) & 1) YieldProcessor();
84 static BOOL
shared_object_release_seqlock( const shared_object_t
*object
, UINT64 seq
)
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
);
97 } while (!shared_object_release_seqlock( object
, lock
.seq
));
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
;
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
);
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
);
129 list_add_tail( &session_blocks
, &block
->entry
);
130 block
->offset
= off
.QuadPart
;
131 assert( block
->offset
+ block
->size
> block
->offset
);
136 if (status
) free( block
);
141 static NTSTATUS
find_shared_session_block( SIZE_T offset
, SIZE_T size
, struct session_block
**ret
)
143 struct session_block
*block
;
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
)
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
);
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
;
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
) );
187 BOOL
is_virtual_desktop(void)
189 HANDLE desktop
= NtUserGetThreadDesktop( GetCurrentThreadId() );
190 USEROBJECTFLAGS flags
= {0};
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
)
205 if (attr
->ObjectName
->Length
>= MAX_PATH
* sizeof(WCHAR
))
207 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE
);
211 SERVER_START_REQ( create_winstation
)
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
);
225 /******************************************************************************
226 * NtUserOpenWindowStation (win32u.@)
228 HWINSTA WINAPI
NtUserOpenWindowStation( OBJECT_ATTRIBUTES
*attr
, ACCESS_MASK access
)
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
);
244 /***********************************************************************
245 * NtUserCloseWindowStation (win32u.@)
247 BOOL WINAPI
NtUserCloseWindowStation( HWINSTA handle
)
250 SERVER_START_REQ( close_winstation
)
252 req
->handle
= wine_server_obj_handle( handle
);
253 ret
= !wine_server_call_err( req
);
259 /***********************************************************************
260 * NtUSerGetProcessWindowStation (win32u.@)
262 HWINSTA WINAPI
NtUserGetProcessWindowStation(void)
266 SERVER_START_REQ( get_process_winstation
)
268 if (!wine_server_call_err( req
))
269 ret
= wine_server_ptr_handle( reply
->handle
);
275 /***********************************************************************
276 * NtUserSetProcessWindowStation (win32u.@)
278 BOOL WINAPI
NtUserSetProcessWindowStation( HWINSTA handle
)
282 SERVER_START_REQ( set_process_winstation
)
284 req
->handle
= wine_server_obj_handle( handle
);
285 ret
= !wine_server_call_err( req
);
291 /***********************************************************************
292 * NtUserCreateDesktopEx (win32u.@)
294 HDESK WINAPI
NtUserCreateDesktopEx( OBJECT_ATTRIBUTES
*attr
, UNICODE_STRING
*device
,
295 DEVMODEW
*devmode
, DWORD flags
, ACCESS_MASK access
,
298 WCHAR buffer
[MAX_PATH
];
301 if ((device
&& device
->Length
) || (devmode
&& !(flags
& DF_WINE_VIRTUAL_DESKTOP
)))
303 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
306 if (attr
->ObjectName
->Length
>= MAX_PATH
* sizeof(WCHAR
))
308 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE
);
311 SERVER_START_REQ( create_desktop
)
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
);
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
);
330 /* force update display cache to use virtual desktop display settings */
331 if (flags
& DF_WINE_VIRTUAL_DESKTOP
) update_display_cache( TRUE
);
335 /***********************************************************************
336 * NtUserOpenDesktop (win32u.@)
338 HDESK WINAPI
NtUserOpenDesktop( OBJECT_ATTRIBUTES
*attr
, DWORD flags
, ACCESS_MASK access
)
341 if (attr
->ObjectName
->Length
>= MAX_PATH
* sizeof(WCHAR
))
343 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE
);
346 SERVER_START_REQ( open_desktop
)
348 req
->winsta
= wine_server_obj_handle( attr
->RootDirectory
);
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
);
359 /***********************************************************************
360 * NtUserCloseDesktop (win32u.@)
362 BOOL WINAPI
NtUserCloseDesktop( HDESK handle
)
365 SERVER_START_REQ( close_desktop
)
367 req
->handle
= wine_server_obj_handle( handle
);
368 ret
= !wine_server_call_err( req
);
374 /***********************************************************************
375 * NtUserGetThreadDesktop (win32u.@)
377 HDESK WINAPI
NtUserGetThreadDesktop( DWORD thread
)
381 SERVER_START_REQ( get_thread_desktop
)
384 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
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
;
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
);
419 /***********************************************************************
420 * NtUserOpenInputDesktop (win32u.@)
422 HDESK WINAPI
NtUserOpenInputDesktop( DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
426 TRACE( "(%x,%i,%x)\n", (int)flags
, inherit
, (int)access
);
429 FIXME( "partial stub flags %08x\n", (int)flags
);
431 SERVER_START_REQ( open_input_desktop
)
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
);
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
;
457 /***********************************************************************
458 * NtUserGetObjectInformation (win32u.@)
460 BOOL WINAPI
NtUserGetObjectInformation( HANDLE handle
, INT index
, void *info
,
461 DWORD len
, DWORD
*needed
)
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};
472 USEROBJECTFLAGS
*obj_flags
= info
;
473 if (needed
) *needed
= sizeof(*obj_flags
);
474 if (len
< sizeof(*obj_flags
))
476 RtlSetLastWin32Error( ERROR_BUFFER_OVERFLOW
);
479 SERVER_START_REQ( set_user_object_info
)
481 req
->handle
= wine_server_obj_handle( handle
);
483 ret
= !wine_server_call_err( req
);
486 /* FIXME: inherit flag */
487 obj_flags
->dwFlags
= reply
->old_obj_flags
;
495 SERVER_START_REQ( set_user_object_info
)
497 req
->handle
= wine_server_obj_handle( handle
);
499 ret
= !wine_server_call_err( req
);
502 size_t size
= reply
->is_desktop
? sizeof(desktopW
) : sizeof(window_stationW
);
503 if (needed
) *needed
= size
;
506 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
509 else memcpy( info
, reply
->is_desktop
? desktopW
: window_stationW
, size
);
517 WCHAR buffer
[MAX_PATH
];
518 SERVER_START_REQ( set_user_object_info
)
520 req
->handle
= wine_server_obj_handle( handle
);
522 wine_server_set_reply( req
, buffer
, sizeof(buffer
) - sizeof(WCHAR
) );
523 ret
= !wine_server_call_err( req
);
526 size_t size
= wine_server_reply_size( reply
);
527 buffer
[size
/ sizeof(WCHAR
)] = 0;
528 size
+= sizeof(WCHAR
);
529 if (needed
) *needed
= size
;
532 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER
);
535 else memcpy( info
, buffer
, size
);
543 FIXME( "not supported index %d\n", index
);
546 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
551 /***********************************************************************
552 * NtUserSetObjectInformation (win32u.@)
554 BOOL WINAPI
NtUserSetObjectInformation( HANDLE handle
, INT index
, void *info
, DWORD len
)
557 const USEROBJECTFLAGS
*obj_flags
= info
;
559 if (index
!= UOI_FLAGS
|| !info
|| len
< sizeof(*obj_flags
))
561 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
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
);
577 static inline TEB64
*NtCurrentTeb64(void) { return NULL
; }
579 static inline TEB64
*NtCurrentTeb64(void) { return (TEB64
*)NtCurrentTeb()->GdiBatchCount
; }
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
];
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
))
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
;
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
;
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
) );
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( ¶ms
.CurrentDirectory
.DosPath
, system_dir
);
649 RtlInitUnicodeString( ¶ms
.ImagePathName
, appnameW
+ 4 );
650 RtlInitUnicodeString( ¶ms
.CommandLine
, cmdlineW
);
651 RtlInitUnicodeString( ¶ms
.WindowTitle
, appnameW
+ 4 );
652 RtlInitUnicodeString( ¶ms
.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
, ¶ms
,
671 &create_info
, ps_attr
);
672 NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
] = FALSE
;
675 status
= NtCreateUserProcess( &process
, &thread
, PROCESS_ALL_ACCESS
, THREAD_ALL_ACCESS
,
676 NULL
, NULL
, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED
, ¶ms
,
677 &create_info
, ps_attr
);
680 NtResumeThread( thread
, NULL
);
681 TRACE_(win
)( "started explorer\n" );
682 NtUserWaitForInputIdle( process
, 10000, FALSE
);
686 else ERR_(win
)( "failed to start explorer %x\n", status
);
688 SERVER_START_REQ( get_desktop_window
)
691 if (!wine_server_call( req
))
693 thread_info
->top_window
= reply
->top_window
;
694 thread_info
->msg_window
= reply
->msg_window
;
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)
712 OBJECT_ATTRIBUTES attr
;
716 snprintf( bufferA
, sizeof(bufferA
), "\\Sessions\\%u\\Windows\\WindowStations", (int)NtCurrentTeb()->Peb
->SessionId
);
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
;
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
) );
754 len
= query_reg_ascii_value( appkey
, "Desktop", info
, buf_size
);
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
);
765 if (len
) return (const WCHAR
*)info
->Data
;
771 /***********************************************************************
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
;
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
, '\\' )))
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
,
808 handle
= NtUserCreateWindowStation( &attr
, STANDARD_RIGHTS_REQUIRED
| WINSTA_ALL_ACCESS
, 0, 0, 0, 0, 0 );
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() ))
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
,
832 handle
= NtUserCreateDesktopEx( &attr
, NULL
, NULL
, 0, STANDARD_RIGHTS_REQUIRED
| DESKTOP_ALL_ACCESS
, 0 );
833 if (handle
) NtUserSetThreadDesktop( handle
);