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
22 #define WIN32_NO_STATUS
33 #include "wine/server.h"
34 #include "wine/debug.h"
35 #include "user_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(winstation
);
40 /* callback for enumeration functions */
41 struct enum_proc_lparam
47 static BOOL CALLBACK
enum_names_WtoA( LPWSTR name
, LPARAM lparam
)
49 struct enum_proc_lparam
*data
= (struct enum_proc_lparam
*)lparam
;
50 char buffer
[MAX_PATH
];
52 if (!WideCharToMultiByte( CP_ACP
, 0, name
, -1, buffer
, sizeof(buffer
), NULL
, NULL
))
54 return data
->func( buffer
, data
->lparam
);
57 /* return a handle to the directory where window station objects are created */
58 static HANDLE
get_winstations_dir_handle(void)
60 static HANDLE handle
= NULL
;
63 OBJECT_ATTRIBUTES attr
;
69 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"\\Sessions\\%u\\Windows\\WindowStations", NtCurrentTeb()->Peb
->SessionId
);
70 RtlInitUnicodeString( &str
, buffer
);
71 InitializeObjectAttributes( &attr
, &str
, 0, 0, NULL
);
72 NtOpenDirectoryObject( &dir
, DIRECTORY_CREATE_OBJECT
| DIRECTORY_TRAVERSE
, &attr
);
73 if (InterlockedCompareExchangePointer( &handle
, dir
, 0 ) != 0) /* someone beat us here */
79 static WCHAR default_name
[29];
81 static BOOL WINAPI
winstation_default_name_once( INIT_ONCE
*once
, void *param
, void **context
)
83 TOKEN_STATISTICS stats
;
86 ret
= GetTokenInformation( GetCurrentProcessToken(), TokenStatistics
, &stats
, sizeof(stats
), NULL
);
88 swprintf( default_name
, ARRAY_SIZE(default_name
), L
"Service-0x%x-%x$",
89 stats
.AuthenticationId
.HighPart
, stats
.AuthenticationId
.LowPart
);
94 static const WCHAR
*get_winstation_default_name( void )
96 static INIT_ONCE once
= INIT_ONCE_STATIC_INIT
;
99 ret
= InitOnceExecuteOnce( &once
, winstation_default_name_once
, NULL
, NULL
);
100 return ret
? default_name
: NULL
;
103 /***********************************************************************
104 * CreateWindowStationA (USER32.@)
106 HWINSTA WINAPI
CreateWindowStationA( LPCSTR name
, DWORD flags
, ACCESS_MASK access
,
107 LPSECURITY_ATTRIBUTES sa
)
109 WCHAR buffer
[MAX_PATH
];
111 if (!name
) return CreateWindowStationW( NULL
, flags
, access
, sa
);
113 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
115 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
118 return CreateWindowStationW( buffer
, flags
, access
, sa
);
122 /***********************************************************************
123 * CreateWindowStationW (USER32.@)
125 HWINSTA WINAPI
CreateWindowStationW( LPCWSTR name
, DWORD flags
, ACCESS_MASK access
,
126 LPSECURITY_ATTRIBUTES sa
)
129 DWORD len
= name
? lstrlenW(name
) : 0;
133 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
138 name
= get_winstation_default_name();
139 len
= lstrlenW( name
);
141 SERVER_START_REQ( create_winstation
)
144 req
->access
= access
;
145 req
->attributes
= OBJ_CASE_INSENSITIVE
|
146 ((flags
& CWF_CREATE_ONLY
) ? 0 : OBJ_OPENIF
) |
147 ((sa
&& sa
->bInheritHandle
) ? OBJ_INHERIT
: 0);
148 req
->rootdir
= wine_server_obj_handle( get_winstations_dir_handle() );
149 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
150 wine_server_call_err( req
);
151 ret
= wine_server_ptr_handle( reply
->handle
);
158 /******************************************************************************
159 * OpenWindowStationA (USER32.@)
161 HWINSTA WINAPI
OpenWindowStationA( LPCSTR name
, BOOL inherit
, ACCESS_MASK access
)
163 WCHAR buffer
[MAX_PATH
];
165 if (!name
) return OpenWindowStationW( NULL
, inherit
, access
);
167 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
169 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
172 return OpenWindowStationW( buffer
, inherit
, access
);
176 /******************************************************************************
177 * OpenWindowStationW (USER32.@)
179 HWINSTA WINAPI
OpenWindowStationW( LPCWSTR name
, BOOL inherit
, ACCESS_MASK access
)
182 DWORD len
= name
? lstrlenW(name
) : 0;
185 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
190 name
= get_winstation_default_name();
191 len
= lstrlenW( name
);
193 SERVER_START_REQ( open_winstation
)
195 req
->access
= access
;
196 req
->attributes
= OBJ_CASE_INSENSITIVE
| (inherit
? OBJ_INHERIT
: 0);
197 req
->rootdir
= wine_server_obj_handle( get_winstations_dir_handle() );
198 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
199 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
206 /***********************************************************************
207 * CloseWindowStation (USER32.@)
209 BOOL WINAPI
CloseWindowStation( HWINSTA handle
)
212 SERVER_START_REQ( close_winstation
)
214 req
->handle
= wine_server_obj_handle( handle
);
215 ret
= !wine_server_call_err( req
);
222 /******************************************************************************
223 * GetProcessWindowStation (USER32.@)
225 HWINSTA WINAPI
GetProcessWindowStation(void)
229 SERVER_START_REQ( get_process_winstation
)
231 if (!wine_server_call_err( req
))
232 ret
= wine_server_ptr_handle( reply
->handle
);
239 /***********************************************************************
240 * SetProcessWindowStation (USER32.@)
242 BOOL WINAPI
SetProcessWindowStation( HWINSTA handle
)
246 SERVER_START_REQ( set_process_winstation
)
248 req
->handle
= wine_server_obj_handle( handle
);
249 ret
= !wine_server_call_err( req
);
256 /******************************************************************************
257 * EnumWindowStationsA (USER32.@)
259 BOOL WINAPI
EnumWindowStationsA( WINSTAENUMPROCA func
, LPARAM lparam
)
261 struct enum_proc_lparam data
;
263 data
.lparam
= lparam
;
264 return EnumWindowStationsW( enum_names_WtoA
, (LPARAM
)&data
);
268 /******************************************************************************
269 * EnumWindowStationsW (USER32.@)
271 BOOL WINAPI
EnumWindowStationsW( WINSTAENUMPROCW func
, LPARAM lparam
)
273 unsigned int index
= 0;
274 WCHAR name
[MAX_PATH
];
280 SERVER_START_REQ( enum_winstation
)
283 wine_server_set_reply( req
, name
, sizeof(name
) - sizeof(WCHAR
) );
284 status
= wine_server_call( req
);
285 name
[wine_server_reply_size(reply
)/sizeof(WCHAR
)] = 0;
289 if (status
== STATUS_NO_MORE_ENTRIES
)
293 SetLastError( RtlNtStatusToDosError( status
) );
296 ret
= func( name
, lparam
);
302 /***********************************************************************
303 * CreateDesktopA (USER32.@)
305 HDESK WINAPI
CreateDesktopA( LPCSTR name
, LPCSTR device
, LPDEVMODEA devmode
,
306 DWORD flags
, ACCESS_MASK access
, LPSECURITY_ATTRIBUTES sa
)
308 WCHAR buffer
[MAX_PATH
];
310 if (device
|| devmode
)
312 SetLastError( ERROR_INVALID_PARAMETER
);
315 if (!name
) return CreateDesktopW( NULL
, NULL
, NULL
, flags
, access
, sa
);
317 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
319 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
322 return CreateDesktopW( buffer
, NULL
, NULL
, flags
, access
, sa
);
326 /***********************************************************************
327 * CreateDesktopW (USER32.@)
329 HDESK WINAPI
CreateDesktopW( LPCWSTR name
, LPCWSTR device
, LPDEVMODEW devmode
,
330 DWORD flags
, ACCESS_MASK access
, LPSECURITY_ATTRIBUTES sa
)
333 DWORD len
= name
? lstrlenW(name
) : 0;
335 if (device
|| devmode
)
337 SetLastError( ERROR_INVALID_PARAMETER
);
342 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
345 SERVER_START_REQ( create_desktop
)
348 req
->access
= access
;
349 req
->attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
|
350 ((sa
&& sa
->bInheritHandle
) ? OBJ_INHERIT
: 0);
351 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
352 wine_server_call_err( req
);
353 ret
= wine_server_ptr_handle( reply
->handle
);
360 /******************************************************************************
361 * OpenDesktopA (USER32.@)
363 HDESK WINAPI
OpenDesktopA( LPCSTR name
, DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
365 WCHAR buffer
[MAX_PATH
];
367 if (!name
) return OpenDesktopW( NULL
, flags
, inherit
, access
);
369 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
371 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
374 return OpenDesktopW( buffer
, flags
, inherit
, access
);
378 HDESK
open_winstation_desktop( HWINSTA hwinsta
, LPCWSTR name
, DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
381 DWORD len
= name
? lstrlenW(name
) : 0;
384 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
387 SERVER_START_REQ( open_desktop
)
389 req
->winsta
= wine_server_obj_handle( hwinsta
);
391 req
->access
= access
;
392 req
->attributes
= OBJ_CASE_INSENSITIVE
| (inherit
? OBJ_INHERIT
: 0);
393 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
394 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
401 /******************************************************************************
402 * OpenDesktopW (USER32.@)
404 HDESK WINAPI
OpenDesktopW( LPCWSTR name
, DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
406 return open_winstation_desktop( NULL
, name
, flags
, inherit
, access
);
410 /***********************************************************************
411 * CloseDesktop (USER32.@)
413 BOOL WINAPI
CloseDesktop( HDESK handle
)
416 SERVER_START_REQ( close_desktop
)
418 req
->handle
= wine_server_obj_handle( handle
);
419 ret
= !wine_server_call_err( req
);
426 /******************************************************************************
427 * GetThreadDesktop (USER32.@)
429 HDESK WINAPI
GetThreadDesktop( DWORD thread
)
433 SERVER_START_REQ( get_thread_desktop
)
436 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
443 /******************************************************************************
444 * SetThreadDesktop (USER32.@)
446 BOOL WINAPI
SetThreadDesktop( HDESK handle
)
450 SERVER_START_REQ( set_thread_desktop
)
452 req
->handle
= wine_server_obj_handle( handle
);
453 ret
= !wine_server_call_err( req
);
456 if (ret
) /* reset the desktop windows */
458 struct user_thread_info
*thread_info
= get_user_thread_info();
459 struct user_key_state_info
*key_state_info
= thread_info
->key_state
;
460 thread_info
->top_window
= 0;
461 thread_info
->msg_window
= 0;
462 if (key_state_info
) key_state_info
->time
= 0;
468 /******************************************************************************
469 * EnumDesktopsA (USER32.@)
471 BOOL WINAPI
EnumDesktopsA( HWINSTA winsta
, DESKTOPENUMPROCA func
, LPARAM lparam
)
473 struct enum_proc_lparam data
;
475 data
.lparam
= lparam
;
476 return EnumDesktopsW( winsta
, enum_names_WtoA
, (LPARAM
)&data
);
480 /******************************************************************************
481 * EnumDesktopsW (USER32.@)
483 BOOL WINAPI
EnumDesktopsW( HWINSTA winsta
, DESKTOPENUMPROCW func
, LPARAM lparam
)
485 unsigned int index
= 0;
486 WCHAR name
[MAX_PATH
];
491 winsta
= GetProcessWindowStation();
495 SERVER_START_REQ( enum_desktop
)
497 req
->winstation
= wine_server_obj_handle( winsta
);
499 wine_server_set_reply( req
, name
, sizeof(name
) - sizeof(WCHAR
) );
500 status
= wine_server_call( req
);
501 name
[wine_server_reply_size(reply
)/sizeof(WCHAR
)] = 0;
505 if (status
== STATUS_NO_MORE_ENTRIES
)
509 SetLastError( RtlNtStatusToDosError( status
) );
512 ret
= func(name
, lparam
);
518 /******************************************************************************
519 * OpenInputDesktop (USER32.@)
521 HDESK WINAPI
OpenInputDesktop( DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
525 TRACE( "(%x,%i,%x)\n", flags
, inherit
, access
);
528 FIXME( "partial stub flags %08x\n", flags
);
530 SERVER_START_REQ( open_input_desktop
)
533 req
->access
= access
;
534 req
->attributes
= inherit
? OBJ_INHERIT
: 0;
535 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
543 /***********************************************************************
544 * GetUserObjectInformationA (USER32.@)
546 BOOL WINAPI
GetUserObjectInformationA( HANDLE handle
, INT index
, LPVOID info
, DWORD len
, LPDWORD needed
)
548 /* check for information types returning strings */
549 if (index
== UOI_TYPE
|| index
== UOI_NAME
)
551 WCHAR buffer
[MAX_PATH
];
554 if (!GetUserObjectInformationW( handle
, index
, buffer
, sizeof(buffer
), &lenW
)) return FALSE
;
555 lenA
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
556 if (needed
) *needed
= lenA
;
559 /* If the buffer length supplied by the caller is insufficient, Windows returns a
560 'needed' length based upon the Unicode byte length, so we should do similarly. */
561 if (needed
) *needed
= lenW
;
563 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
566 if (info
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, info
, len
, NULL
, NULL
);
569 return GetUserObjectInformationW( handle
, index
, info
, len
, needed
);
573 /***********************************************************************
574 * GetUserObjectInformationW (USER32.@)
576 BOOL WINAPI
GetUserObjectInformationW( HANDLE handle
, INT index
, LPVOID info
, DWORD len
, LPDWORD needed
)
584 USEROBJECTFLAGS
*obj_flags
= info
;
585 if (needed
) *needed
= sizeof(*obj_flags
);
586 if (len
< sizeof(*obj_flags
))
588 SetLastError( ERROR_BUFFER_OVERFLOW
);
591 SERVER_START_REQ( set_user_object_info
)
593 req
->handle
= wine_server_obj_handle( handle
);
595 ret
= !wine_server_call_err( req
);
598 /* FIXME: inherit flag */
599 obj_flags
->dwFlags
= reply
->old_obj_flags
;
607 SERVER_START_REQ( set_user_object_info
)
609 req
->handle
= wine_server_obj_handle( handle
);
611 ret
= !wine_server_call_err( req
);
614 size_t size
= reply
->is_desktop
? sizeof(L
"Desktop") : sizeof(L
"WindowStation");
615 if (needed
) *needed
= size
;
618 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
621 else memcpy( info
, reply
->is_desktop
? L
"Desktop" : L
"WindowStation", size
);
629 WCHAR buffer
[MAX_PATH
];
630 SERVER_START_REQ( set_user_object_info
)
632 req
->handle
= wine_server_obj_handle( handle
);
634 wine_server_set_reply( req
, buffer
, sizeof(buffer
) - sizeof(WCHAR
) );
635 ret
= !wine_server_call_err( req
);
638 size_t size
= wine_server_reply_size( reply
);
639 buffer
[size
/ sizeof(WCHAR
)] = 0;
640 size
+= sizeof(WCHAR
);
641 if (needed
) *needed
= size
;
644 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
647 else memcpy( info
, buffer
, size
);
655 FIXME( "not supported index %d\n", index
);
658 SetLastError( ERROR_INVALID_PARAMETER
);
664 /******************************************************************************
665 * SetUserObjectInformationA (USER32.@)
667 BOOL WINAPI
SetUserObjectInformationA( HANDLE handle
, INT index
, LPVOID info
, DWORD len
)
669 return SetUserObjectInformationW( handle
, index
, info
, len
);
673 /******************************************************************************
674 * SetUserObjectInformationW (USER32.@)
676 BOOL WINAPI
SetUserObjectInformationW( HANDLE handle
, INT index
, LPVOID info
, DWORD len
)
679 const USEROBJECTFLAGS
*obj_flags
= info
;
681 if (index
!= UOI_FLAGS
|| !info
|| len
< sizeof(*obj_flags
))
683 SetLastError( ERROR_INVALID_PARAMETER
);
686 /* FIXME: inherit flag */
687 SERVER_START_REQ( set_user_object_info
)
689 req
->handle
= wine_server_obj_handle( handle
);
690 req
->flags
= SET_USER_OBJECT_SET_FLAGS
;
691 req
->obj_flags
= obj_flags
->dwFlags
;
692 ret
= !wine_server_call_err( req
);
699 /***********************************************************************
700 * GetUserObjectSecurity (USER32.@)
702 BOOL WINAPI
GetUserObjectSecurity( HANDLE handle
, PSECURITY_INFORMATION info
,
703 PSECURITY_DESCRIPTOR sid
, DWORD len
, LPDWORD needed
)
705 FIXME( "(%p %p %p len=%d %p),stub!\n", handle
, info
, sid
, len
, needed
);
707 *needed
= sizeof(SECURITY_DESCRIPTOR
);
708 if (len
< sizeof(SECURITY_DESCRIPTOR
))
710 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
713 return InitializeSecurityDescriptor(sid
, SECURITY_DESCRIPTOR_REVISION
);
716 /***********************************************************************
717 * SetUserObjectSecurity (USER32.@)
719 BOOL WINAPI
SetUserObjectSecurity( HANDLE handle
, PSECURITY_INFORMATION info
,
720 PSECURITY_DESCRIPTOR sid
)
722 FIXME( "(%p,%p,%p),stub!\n", handle
, info
, sid
);