cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / winstation.c
blob5d1d5254ae10f9745cb8724c01839f9f6aee74ce
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 "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "ntuser.h"
31 #include "ddk/wdm.h"
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 BOOL is_virtual_desktop(void)
45 HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() );
46 USEROBJECTFLAGS flags = {0};
47 DWORD len;
49 if (!NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len )) return FALSE;
50 return !!(flags.dwFlags & DF_WINE_CREATE_DESKTOP);
53 /***********************************************************************
54 * NtUserCreateWindowStation (win32u.@)
56 HWINSTA WINAPI NtUserCreateWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access, ULONG arg3,
57 ULONG arg4, ULONG arg5, ULONG arg6, ULONG arg7 )
59 HANDLE ret;
61 if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR))
63 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE );
64 return 0;
67 SERVER_START_REQ( create_winstation )
69 req->flags = 0;
70 req->access = access;
71 req->attributes = attr->Attributes;
72 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
73 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
74 wine_server_call_err( req );
75 ret = wine_server_ptr_handle( reply->handle );
77 SERVER_END_REQ;
78 return ret;
81 /******************************************************************************
82 * NtUserOpenWindowStation (win32u.@)
84 HWINSTA WINAPI NtUserOpenWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access )
86 HANDLE ret = 0;
88 SERVER_START_REQ( open_winstation )
90 req->access = access;
91 req->attributes = attr->Attributes;
92 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
93 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
94 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
96 SERVER_END_REQ;
97 return ret;
100 /***********************************************************************
101 * NtUserCloseWindowStation (win32u.@)
103 BOOL WINAPI NtUserCloseWindowStation( HWINSTA handle )
105 BOOL ret;
106 SERVER_START_REQ( close_winstation )
108 req->handle = wine_server_obj_handle( handle );
109 ret = !wine_server_call_err( req );
111 SERVER_END_REQ;
112 return ret;
115 /***********************************************************************
116 * NtUSerGetProcessWindowStation (win32u.@)
118 HWINSTA WINAPI NtUserGetProcessWindowStation(void)
120 HWINSTA ret = 0;
122 SERVER_START_REQ( get_process_winstation )
124 if (!wine_server_call_err( req ))
125 ret = wine_server_ptr_handle( reply->handle );
127 SERVER_END_REQ;
128 return ret;
131 /***********************************************************************
132 * NtUserSetProcessWindowStation (win32u.@)
134 BOOL WINAPI NtUserSetProcessWindowStation( HWINSTA handle )
136 BOOL ret;
138 SERVER_START_REQ( set_process_winstation )
140 req->handle = wine_server_obj_handle( handle );
141 ret = !wine_server_call_err( req );
143 SERVER_END_REQ;
144 return ret;
147 /***********************************************************************
148 * NtUserCreateDesktopEx (win32u.@)
150 HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *device,
151 DEVMODEW *devmode, DWORD flags, ACCESS_MASK access,
152 ULONG heap_size )
154 WCHAR buffer[MAX_PATH];
155 HANDLE ret;
157 if ((device && device->Length) || (devmode && !(flags & DF_WINE_CREATE_DESKTOP)))
159 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
160 return 0;
162 if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR))
164 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE );
165 return 0;
167 SERVER_START_REQ( create_desktop )
169 req->flags = flags;
170 req->access = access;
171 req->attributes = attr->Attributes;
172 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
173 wine_server_call_err( req );
174 ret = wine_server_ptr_handle( reply->handle );
176 SERVER_END_REQ;
177 if (!devmode) return ret;
179 lstrcpynW( buffer, attr->ObjectName->Buffer, attr->ObjectName->Length / sizeof(WCHAR) + 1 );
180 if (!user_driver->pCreateDesktop( buffer, devmode->dmPelsWidth, devmode->dmPelsHeight ))
182 NtUserCloseDesktop( ret );
183 return 0;
186 /* force update display cache to use virtual desktop display settings */
187 if (flags & DF_WINE_CREATE_DESKTOP) update_display_cache( TRUE );
188 return ret;
191 /***********************************************************************
192 * NtUserOpenDesktop (win32u.@)
194 HDESK WINAPI NtUserOpenDesktop( OBJECT_ATTRIBUTES *attr, DWORD flags, ACCESS_MASK access )
196 HANDLE ret = 0;
197 if (attr->ObjectName->Length >= MAX_PATH * sizeof(WCHAR))
199 RtlSetLastWin32Error( ERROR_FILENAME_EXCED_RANGE );
200 return 0;
202 SERVER_START_REQ( open_desktop )
204 req->winsta = wine_server_obj_handle( attr->RootDirectory );
205 req->flags = flags;
206 req->access = access;
207 req->attributes = attr->Attributes;
208 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
209 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
211 SERVER_END_REQ;
212 return ret;
215 /***********************************************************************
216 * NtUserCloseDesktop (win32u.@)
218 BOOL WINAPI NtUserCloseDesktop( HDESK handle )
220 BOOL ret;
221 SERVER_START_REQ( close_desktop )
223 req->handle = wine_server_obj_handle( handle );
224 ret = !wine_server_call_err( req );
226 SERVER_END_REQ;
227 return ret;
230 /***********************************************************************
231 * NtUserGetThreadDesktop (win32u.@)
233 HDESK WINAPI NtUserGetThreadDesktop( DWORD thread )
235 HDESK ret = 0;
237 SERVER_START_REQ( get_thread_desktop )
239 req->tid = thread;
240 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
242 SERVER_END_REQ;
243 return ret;
246 /***********************************************************************
247 * NtUserSetThreadDesktop (win32u.@)
249 BOOL WINAPI NtUserSetThreadDesktop( HDESK handle )
251 BOOL ret, was_virtual_desktop = is_virtual_desktop();
253 SERVER_START_REQ( set_thread_desktop )
255 req->handle = wine_server_obj_handle( handle );
256 ret = !wine_server_call_err( req );
258 SERVER_END_REQ;
260 if (ret) /* reset the desktop windows */
262 struct user_thread_info *thread_info = get_user_thread_info();
263 struct user_key_state_info *key_state_info = thread_info->key_state;
264 thread_info->client_info.top_window = 0;
265 thread_info->client_info.msg_window = 0;
266 if (key_state_info) key_state_info->time = 0;
267 if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( TRUE );
269 return ret;
272 /***********************************************************************
273 * NtUserOpenInputDesktop (win32u.@)
275 HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
277 HANDLE ret = 0;
279 TRACE( "(%x,%i,%x)\n", (int)flags, inherit, (int)access );
281 if (flags)
282 FIXME( "partial stub flags %08x\n", (int)flags );
284 SERVER_START_REQ( open_input_desktop )
286 req->flags = flags;
287 req->access = access;
288 req->attributes = inherit ? OBJ_INHERIT : 0;
289 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
291 SERVER_END_REQ;
293 return ret;
296 /***********************************************************************
297 * NtUserGetObjectInformation (win32u.@)
299 BOOL WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, void *info,
300 DWORD len, DWORD *needed )
302 BOOL ret;
304 static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
305 static const WCHAR window_stationW[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n',0};
307 switch(index)
309 case UOI_FLAGS:
311 USEROBJECTFLAGS *obj_flags = info;
312 if (needed) *needed = sizeof(*obj_flags);
313 if (len < sizeof(*obj_flags))
315 RtlSetLastWin32Error( ERROR_BUFFER_OVERFLOW );
316 return FALSE;
318 SERVER_START_REQ( set_user_object_info )
320 req->handle = wine_server_obj_handle( handle );
321 req->flags = 0;
322 ret = !wine_server_call_err( req );
323 if (ret)
325 /* FIXME: inherit flag */
326 obj_flags->dwFlags = reply->old_obj_flags;
329 SERVER_END_REQ;
331 return ret;
333 case UOI_TYPE:
334 SERVER_START_REQ( set_user_object_info )
336 req->handle = wine_server_obj_handle( handle );
337 req->flags = 0;
338 ret = !wine_server_call_err( req );
339 if (ret)
341 size_t size = reply->is_desktop ? sizeof(desktopW) : sizeof(window_stationW);
342 if (needed) *needed = size;
343 if (len < size)
345 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
346 ret = FALSE;
348 else memcpy( info, reply->is_desktop ? desktopW : window_stationW, size );
351 SERVER_END_REQ;
352 return ret;
354 case UOI_NAME:
356 WCHAR buffer[MAX_PATH];
357 SERVER_START_REQ( set_user_object_info )
359 req->handle = wine_server_obj_handle( handle );
360 req->flags = 0;
361 wine_server_set_reply( req, buffer, sizeof(buffer) - sizeof(WCHAR) );
362 ret = !wine_server_call_err( req );
363 if (ret)
365 size_t size = wine_server_reply_size( reply );
366 buffer[size / sizeof(WCHAR)] = 0;
367 size += sizeof(WCHAR);
368 if (needed) *needed = size;
369 if (len < size)
371 RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
372 ret = FALSE;
374 else memcpy( info, buffer, size );
377 SERVER_END_REQ;
379 return ret;
381 case UOI_USER_SID:
382 FIXME( "not supported index %d\n", index );
383 /* fall through */
384 default:
385 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
386 return FALSE;
390 /***********************************************************************
391 * NtUserSetObjectInformation (win32u.@)
393 BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DWORD len )
395 BOOL ret;
396 const USEROBJECTFLAGS *obj_flags = info;
398 if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags))
400 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
401 return FALSE;
403 /* FIXME: inherit flag */
404 SERVER_START_REQ( set_user_object_info )
406 req->handle = wine_server_obj_handle( handle );
407 req->flags = SET_USER_OBJECT_SET_FLAGS;
408 req->obj_flags = obj_flags->dwFlags;
409 ret = !wine_server_call_err( req );
411 SERVER_END_REQ;
412 return ret;
415 #ifdef _WIN64
416 static inline TEB64 *NtCurrentTeb64(void) { return NULL; }
417 #else
418 static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; }
419 #endif
421 HWND get_desktop_window(void)
423 static const WCHAR wine_service_station_name[] =
424 {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n',0};
425 struct ntuser_thread_info *thread_info = NtUserGetThreadInfo();
426 WCHAR name[MAX_PATH];
427 BOOL is_service;
429 if (thread_info->top_window) return UlongToHandle( thread_info->top_window );
431 /* don't create an actual explorer desktop window for services */
432 if (NtUserGetObjectInformation( NtUserGetProcessWindowStation(), UOI_NAME, name, sizeof(name), NULL )
433 && !wcscmp( name, wine_service_station_name ))
434 is_service = TRUE;
435 else
436 is_service = FALSE;
438 SERVER_START_REQ( get_desktop_window )
440 req->force = is_service;
441 if (!wine_server_call( req ))
443 thread_info->top_window = reply->top_window;
444 thread_info->msg_window = reply->msg_window;
447 SERVER_END_REQ;
449 if (!thread_info->top_window)
451 static const WCHAR appnameW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s',
452 '\\','s','y','s','t','e','m','3','2','\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
453 static const WCHAR cmdlineW[] = {'"','C',':','\\','w','i','n','d','o','w','s','\\',
454 's','y','s','t','e','m','3','2','\\','e','x','p','l','o','r','e','r','.','e','x','e','"',
455 ' ','/','d','e','s','k','t','o','p',0};
456 static const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
457 's','y','s','t','e','m','3','2','\\',0};
458 RTL_USER_PROCESS_PARAMETERS params = { sizeof(params), sizeof(params) };
459 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)];
460 PS_ATTRIBUTE_LIST *ps_attr = (PS_ATTRIBUTE_LIST *)buffer;
461 PS_CREATE_INFO create_info;
462 WCHAR desktop[MAX_PATH];
463 PEB *peb = NtCurrentTeb()->Peb;
464 HANDLE process, thread;
465 unsigned int status;
467 SERVER_START_REQ( set_user_object_info )
469 req->handle = wine_server_obj_handle( NtUserGetThreadDesktop(GetCurrentThreadId()) );
470 req->flags = SET_USER_OBJECT_GET_FULL_NAME;
471 wine_server_set_reply( req, desktop, sizeof(desktop) - sizeof(WCHAR) );
472 if (!wine_server_call( req ))
474 size_t size = wine_server_reply_size( reply );
475 desktop[size / sizeof(WCHAR)] = 0;
476 TRACE( "starting explorer for desktop %s\n", debugstr_w(desktop) );
478 else
479 desktop[0] = 0;
481 SERVER_END_REQ;
483 params.Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
484 params.Environment = peb->ProcessParameters->Environment;
485 params.EnvironmentSize = peb->ProcessParameters->EnvironmentSize;
486 params.hStdError = peb->ProcessParameters->hStdError;
487 RtlInitUnicodeString( &params.CurrentDirectory.DosPath, system_dir );
488 RtlInitUnicodeString( &params.ImagePathName, appnameW + 4 );
489 RtlInitUnicodeString( &params.CommandLine, cmdlineW );
490 RtlInitUnicodeString( &params.WindowTitle, appnameW + 4 );
491 RtlInitUnicodeString( &params.Desktop, desktop );
493 ps_attr->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
494 ps_attr->Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR);
495 ps_attr->Attributes[0].ValuePtr = (WCHAR *)appnameW;
496 ps_attr->Attributes[0].ReturnLength = NULL;
498 ps_attr->Attributes[1].Attribute = PS_ATTRIBUTE_TOKEN;
499 ps_attr->Attributes[1].Size = sizeof(HANDLE);
500 ps_attr->Attributes[1].ValuePtr = GetCurrentThreadEffectiveToken();
501 ps_attr->Attributes[1].ReturnLength = NULL;
503 ps_attr->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[2] );
505 if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR])
507 NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = TRUE;
508 status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
509 NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, &params,
510 &create_info, ps_attr );
511 NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = FALSE;
513 else
514 status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
515 NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, &params,
516 &create_info, ps_attr );
517 if (!status)
519 NtResumeThread( thread, NULL );
520 TRACE_(win)( "started explorer\n" );
521 NtUserWaitForInputIdle( process, 10000, FALSE );
522 NtClose( thread );
523 NtClose( process );
525 else ERR_(win)( "failed to start explorer %x\n", status );
527 SERVER_START_REQ( get_desktop_window )
529 req->force = 1;
530 if (!wine_server_call( req ))
532 thread_info->top_window = reply->top_window;
533 thread_info->msg_window = reply->msg_window;
536 SERVER_END_REQ;
539 if (!thread_info->top_window) ERR_(win)( "failed to create desktop window\n" );
540 else user_driver->pSetDesktopWindow( UlongToHandle( thread_info->top_window ));
542 register_builtin_classes();
543 return UlongToHandle( thread_info->top_window );
546 static HANDLE get_winstations_dir_handle(void)
548 char bufferA[64];
549 WCHAR buffer[64];
550 UNICODE_STRING str;
551 OBJECT_ATTRIBUTES attr;
552 NTSTATUS status;
553 HANDLE dir;
555 sprintf( bufferA, "\\Sessions\\%u\\Windows\\WindowStations", (int)NtCurrentTeb()->Peb->SessionId );
556 str.Buffer = buffer;
557 str.Length = str.MaximumLength = asciiz_to_unicode( buffer, bufferA ) - sizeof(WCHAR);
558 InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
559 status = NtOpenDirectoryObject( &dir, DIRECTORY_CREATE_OBJECT | DIRECTORY_TRAVERSE, &attr );
560 return status ? 0 : dir;
563 /***********************************************************************
564 * get_default_desktop
566 * Get the name of the desktop to use for this app if not specified explicitly.
568 static const WCHAR *get_default_desktop( void *buf, size_t buf_size )
570 const WCHAR *p, *appname = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
571 KEY_VALUE_PARTIAL_INFORMATION *info = buf;
572 WCHAR *buffer = buf;
573 HKEY tmpkey, appkey;
574 DWORD len;
576 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
578 if ((p = wcsrchr( appname, '/' ))) appname = p + 1;
579 if ((p = wcsrchr( appname, '\\' ))) appname = p + 1;
580 len = lstrlenW(appname);
581 if (len > MAX_PATH) return defaultW;
582 memcpy( buffer, appname, len * sizeof(WCHAR) );
583 asciiz_to_unicode( buffer + len, "\\Explorer" );
585 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Explorer */
586 if ((tmpkey = reg_open_hkcu_key( "Software\\Wine\\AppDefaults" )))
588 appkey = reg_open_key( tmpkey, buffer, lstrlenW(buffer) * sizeof(WCHAR) );
589 NtClose( tmpkey );
590 if (appkey)
592 len = query_reg_ascii_value( appkey, "Desktop", info, buf_size );
593 NtClose( appkey );
594 if (len) return (const WCHAR *)info->Data;
598 /* @@ Wine registry key: HKCU\Software\Wine\Explorer */
599 if ((appkey = reg_open_hkcu_key( "Software\\Wine\\Explorer" )))
601 len = query_reg_ascii_value( appkey, "Desktop", info, buf_size );
602 NtClose( appkey );
603 if (len) return (const WCHAR *)info->Data;
606 return defaultW;
609 /***********************************************************************
610 * winstation_init
612 * Connect to the process window station and desktop.
614 void winstation_init(void)
616 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
617 WCHAR *winstation = NULL, *desktop = NULL, *buffer = NULL;
618 HANDLE handle, dir = NULL;
619 OBJECT_ATTRIBUTES attr;
620 UNICODE_STRING str;
622 static const WCHAR winsta0[] = {'W','i','n','S','t','a','0',0};
624 if (params->Desktop.Length)
626 buffer = malloc( params->Desktop.Length + sizeof(WCHAR) );
627 memcpy( buffer, params->Desktop.Buffer, params->Desktop.Length );
628 buffer[params->Desktop.Length / sizeof(WCHAR)] = 0;
629 if ((desktop = wcschr( buffer, '\\' )))
631 *desktop++ = 0;
632 winstation = buffer;
634 else desktop = buffer;
637 /* set winstation if explicitly specified, or if we don't have one yet */
638 if (buffer || !NtUserGetProcessWindowStation())
640 str.Buffer = (WCHAR *)(winstation ? winstation : winsta0);
641 str.Length = str.MaximumLength = lstrlenW( str.Buffer ) * sizeof(WCHAR);
642 dir = get_winstations_dir_handle();
643 InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
644 dir, NULL );
646 handle = NtUserCreateWindowStation( &attr, STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS, 0, 0, 0, 0, 0 );
647 if (handle)
649 NtUserSetProcessWindowStation( handle );
650 /* only WinSta0 is visible */
651 if (!winstation || !wcsicmp( winstation, winsta0 ))
653 USEROBJECTFLAGS flags;
654 flags.fInherit = FALSE;
655 flags.fReserved = FALSE;
656 flags.dwFlags = WSF_VISIBLE;
657 NtUserSetObjectInformation( handle, UOI_FLAGS, &flags, sizeof(flags) );
661 if (buffer || !NtUserGetThreadDesktop( GetCurrentThreadId() ))
663 char buffer[4096];
664 str.Buffer = (WCHAR *)(desktop ? desktop : get_default_desktop( buffer, sizeof(buffer) ));
665 str.Length = str.MaximumLength = lstrlenW( str.Buffer ) * sizeof(WCHAR);
666 if (!dir) dir = get_winstations_dir_handle();
667 InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
668 dir, NULL );
670 handle = NtUserCreateDesktopEx( &attr, NULL, NULL, 0, STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS, 0 );
671 if (handle) NtUserSetThreadDesktop( handle );
673 NtClose( dir );
674 free( buffer );