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/unicode.h"
35 #include "wine/debug.h"
36 #include "user_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(winstation
);
41 /* callback for enumeration functions */
42 struct enum_proc_lparam
48 static BOOL CALLBACK
enum_names_WtoA( LPWSTR name
, LPARAM lparam
)
50 struct enum_proc_lparam
*data
= (struct enum_proc_lparam
*)lparam
;
51 char buffer
[MAX_PATH
];
53 if (!WideCharToMultiByte( CP_ACP
, 0, name
, -1, buffer
, sizeof(buffer
), NULL
, NULL
))
55 return data
->func( buffer
, data
->lparam
);
58 /* return a handle to the directory where window station objects are created */
59 static HANDLE
get_winstations_dir_handle(void)
61 static HANDLE handle
= NULL
;
62 static const WCHAR basenameW
[] = {'\\','S','e','s','s','i','o','n','s','\\','%','u',
63 '\\','W','i','n','d','o','w','s','\\',
64 'W','i','n','d','o','w','S','t','a','t','i','o','n','s',0};
67 OBJECT_ATTRIBUTES attr
;
73 sprintfW( buffer
, basenameW
, NtCurrentTeb()->Peb
->SessionId
);
74 RtlInitUnicodeString( &str
, buffer
);
75 InitializeObjectAttributes( &attr
, &str
, 0, 0, NULL
);
76 NtOpenDirectoryObject( &dir
, DIRECTORY_CREATE_OBJECT
| DIRECTORY_TRAVERSE
, &attr
);
77 if (InterlockedCompareExchangePointer( &handle
, dir
, 0 ) != 0) /* someone beat us here */
83 /***********************************************************************
84 * CreateWindowStationA (USER32.@)
86 HWINSTA WINAPI
CreateWindowStationA( LPCSTR name
, DWORD reserved
, ACCESS_MASK access
,
87 LPSECURITY_ATTRIBUTES sa
)
89 WCHAR buffer
[MAX_PATH
];
91 if (!name
) return CreateWindowStationW( NULL
, reserved
, access
, sa
);
93 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
95 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
98 return CreateWindowStationW( buffer
, reserved
, access
, sa
);
102 /***********************************************************************
103 * CreateWindowStationW (USER32.@)
105 HWINSTA WINAPI
CreateWindowStationW( LPCWSTR name
, DWORD reserved
, ACCESS_MASK access
,
106 LPSECURITY_ATTRIBUTES sa
)
109 DWORD len
= name
? strlenW(name
) : 0;
113 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
116 SERVER_START_REQ( create_winstation
)
119 req
->access
= access
;
120 req
->attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
|
121 ((sa
&& sa
->bInheritHandle
) ? OBJ_INHERIT
: 0);
122 req
->rootdir
= wine_server_obj_handle( get_winstations_dir_handle() );
123 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
124 wine_server_call_err( req
);
125 ret
= wine_server_ptr_handle( reply
->handle
);
132 /******************************************************************************
133 * OpenWindowStationA (USER32.@)
135 HWINSTA WINAPI
OpenWindowStationA( LPCSTR name
, BOOL inherit
, ACCESS_MASK access
)
137 WCHAR buffer
[MAX_PATH
];
139 if (!name
) return OpenWindowStationW( NULL
, inherit
, access
);
141 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
143 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
146 return OpenWindowStationW( buffer
, inherit
, access
);
150 /******************************************************************************
151 * OpenWindowStationW (USER32.@)
153 HWINSTA WINAPI
OpenWindowStationW( LPCWSTR name
, BOOL inherit
, ACCESS_MASK access
)
156 DWORD len
= name
? strlenW(name
) : 0;
159 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
162 SERVER_START_REQ( open_winstation
)
164 req
->access
= access
;
165 req
->attributes
= OBJ_CASE_INSENSITIVE
| (inherit
? OBJ_INHERIT
: 0);
166 req
->rootdir
= wine_server_obj_handle( get_winstations_dir_handle() );
167 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
168 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
175 /***********************************************************************
176 * CloseWindowStation (USER32.@)
178 BOOL WINAPI
CloseWindowStation( HWINSTA handle
)
181 SERVER_START_REQ( close_winstation
)
183 req
->handle
= wine_server_obj_handle( handle
);
184 ret
= !wine_server_call_err( req
);
191 /******************************************************************************
192 * GetProcessWindowStation (USER32.@)
194 HWINSTA WINAPI
GetProcessWindowStation(void)
198 SERVER_START_REQ( get_process_winstation
)
200 if (!wine_server_call_err( req
))
201 ret
= wine_server_ptr_handle( reply
->handle
);
208 /***********************************************************************
209 * SetProcessWindowStation (USER32.@)
211 BOOL WINAPI
SetProcessWindowStation( HWINSTA handle
)
215 SERVER_START_REQ( set_process_winstation
)
217 req
->handle
= wine_server_obj_handle( handle
);
218 ret
= !wine_server_call_err( req
);
225 /******************************************************************************
226 * EnumWindowStationsA (USER32.@)
228 BOOL WINAPI
EnumWindowStationsA( WINSTAENUMPROCA func
, LPARAM lparam
)
230 struct enum_proc_lparam data
;
232 data
.lparam
= lparam
;
233 return EnumWindowStationsW( enum_names_WtoA
, (LPARAM
)&data
);
237 /******************************************************************************
238 * EnumWindowStationsW (USER32.@)
240 BOOL WINAPI
EnumWindowStationsW( WINSTAENUMPROCW func
, LPARAM lparam
)
242 unsigned int index
= 0;
243 WCHAR name
[MAX_PATH
];
249 SERVER_START_REQ( enum_winstation
)
252 wine_server_set_reply( req
, name
, sizeof(name
) - sizeof(WCHAR
) );
253 status
= wine_server_call( req
);
254 name
[wine_server_reply_size(reply
)/sizeof(WCHAR
)] = 0;
258 if (status
== STATUS_NO_MORE_ENTRIES
)
262 SetLastError( RtlNtStatusToDosError( status
) );
265 ret
= func( name
, lparam
);
271 /***********************************************************************
272 * CreateDesktopA (USER32.@)
274 HDESK WINAPI
CreateDesktopA( LPCSTR name
, LPCSTR device
, LPDEVMODEA devmode
,
275 DWORD flags
, ACCESS_MASK access
, LPSECURITY_ATTRIBUTES sa
)
277 WCHAR buffer
[MAX_PATH
];
279 if (device
|| devmode
)
281 SetLastError( ERROR_INVALID_PARAMETER
);
284 if (!name
) return CreateDesktopW( NULL
, NULL
, NULL
, flags
, access
, sa
);
286 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
288 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
291 return CreateDesktopW( buffer
, NULL
, NULL
, flags
, access
, sa
);
295 /***********************************************************************
296 * CreateDesktopW (USER32.@)
298 HDESK WINAPI
CreateDesktopW( LPCWSTR name
, LPCWSTR device
, LPDEVMODEW devmode
,
299 DWORD flags
, ACCESS_MASK access
, LPSECURITY_ATTRIBUTES sa
)
302 DWORD len
= name
? strlenW(name
) : 0;
304 if (device
|| devmode
)
306 SetLastError( ERROR_INVALID_PARAMETER
);
311 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
314 SERVER_START_REQ( create_desktop
)
317 req
->access
= access
;
318 req
->attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
|
319 ((sa
&& sa
->bInheritHandle
) ? OBJ_INHERIT
: 0);
320 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
321 wine_server_call_err( req
);
322 ret
= wine_server_ptr_handle( reply
->handle
);
329 /******************************************************************************
330 * OpenDesktopA (USER32.@)
332 HDESK WINAPI
OpenDesktopA( LPCSTR name
, DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
334 WCHAR buffer
[MAX_PATH
];
336 if (!name
) return OpenDesktopW( NULL
, flags
, inherit
, access
);
338 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, buffer
, MAX_PATH
))
340 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
343 return OpenDesktopW( buffer
, flags
, inherit
, access
);
347 HDESK
open_winstation_desktop( HWINSTA hwinsta
, LPCWSTR name
, DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
350 DWORD len
= name
? strlenW(name
) : 0;
353 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
356 SERVER_START_REQ( open_desktop
)
358 req
->winsta
= wine_server_obj_handle( hwinsta
);
360 req
->access
= access
;
361 req
->attributes
= OBJ_CASE_INSENSITIVE
| (inherit
? OBJ_INHERIT
: 0);
362 wine_server_add_data( req
, name
, len
* sizeof(WCHAR
) );
363 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
370 /******************************************************************************
371 * OpenDesktopW (USER32.@)
373 HDESK WINAPI
OpenDesktopW( LPCWSTR name
, DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
375 return open_winstation_desktop( NULL
, name
, flags
, inherit
, access
);
379 /***********************************************************************
380 * CloseDesktop (USER32.@)
382 BOOL WINAPI
CloseDesktop( HDESK handle
)
385 SERVER_START_REQ( close_desktop
)
387 req
->handle
= wine_server_obj_handle( handle
);
388 ret
= !wine_server_call_err( req
);
395 /******************************************************************************
396 * GetThreadDesktop (USER32.@)
398 HDESK WINAPI
GetThreadDesktop( DWORD thread
)
402 SERVER_START_REQ( get_thread_desktop
)
405 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
412 /******************************************************************************
413 * SetThreadDesktop (USER32.@)
415 BOOL WINAPI
SetThreadDesktop( HDESK handle
)
419 SERVER_START_REQ( set_thread_desktop
)
421 req
->handle
= wine_server_obj_handle( handle
);
422 ret
= !wine_server_call_err( req
);
425 if (ret
) /* reset the desktop windows */
427 struct user_thread_info
*thread_info
= get_user_thread_info();
428 struct user_key_state_info
*key_state_info
= thread_info
->key_state
;
429 thread_info
->top_window
= 0;
430 thread_info
->msg_window
= 0;
431 if (key_state_info
) key_state_info
->time
= 0;
437 /******************************************************************************
438 * EnumDesktopsA (USER32.@)
440 BOOL WINAPI
EnumDesktopsA( HWINSTA winsta
, DESKTOPENUMPROCA func
, LPARAM lparam
)
442 struct enum_proc_lparam data
;
444 data
.lparam
= lparam
;
445 return EnumDesktopsW( winsta
, enum_names_WtoA
, (LPARAM
)&data
);
449 /******************************************************************************
450 * EnumDesktopsW (USER32.@)
452 BOOL WINAPI
EnumDesktopsW( HWINSTA winsta
, DESKTOPENUMPROCW func
, LPARAM lparam
)
454 unsigned int index
= 0;
455 WCHAR name
[MAX_PATH
];
460 winsta
= GetProcessWindowStation();
464 SERVER_START_REQ( enum_desktop
)
466 req
->winstation
= wine_server_obj_handle( winsta
);
468 wine_server_set_reply( req
, name
, sizeof(name
) - sizeof(WCHAR
) );
469 status
= wine_server_call( req
);
470 name
[wine_server_reply_size(reply
)/sizeof(WCHAR
)] = 0;
474 if (status
== STATUS_NO_MORE_ENTRIES
)
478 SetLastError( RtlNtStatusToDosError( status
) );
481 ret
= func(name
, lparam
);
487 /******************************************************************************
488 * OpenInputDesktop (USER32.@)
490 HDESK WINAPI
OpenInputDesktop( DWORD flags
, BOOL inherit
, ACCESS_MASK access
)
494 TRACE( "(%x,%i,%x)\n", flags
, inherit
, access
);
497 FIXME( "partial stub flags %08x\n", flags
);
499 SERVER_START_REQ( open_input_desktop
)
502 req
->access
= access
;
503 req
->attributes
= inherit
? OBJ_INHERIT
: 0;
504 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->handle
);
512 /***********************************************************************
513 * GetUserObjectInformationA (USER32.@)
515 BOOL WINAPI
GetUserObjectInformationA( HANDLE handle
, INT index
, LPVOID info
, DWORD len
, LPDWORD needed
)
517 /* check for information types returning strings */
518 if (index
== UOI_TYPE
|| index
== UOI_NAME
)
520 WCHAR buffer
[MAX_PATH
];
523 if (!GetUserObjectInformationW( handle
, index
, buffer
, sizeof(buffer
), &lenW
)) return FALSE
;
524 lenA
= WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, NULL
, 0, NULL
, NULL
);
525 if (needed
) *needed
= lenA
;
528 /* If the buffer length supplied by the caller is insufficient, Windows returns a
529 'needed' length based upon the Unicode byte length, so we should do similarly. */
530 if (needed
) *needed
= lenW
;
532 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
535 if (info
) WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, info
, len
, NULL
, NULL
);
538 return GetUserObjectInformationW( handle
, index
, info
, len
, needed
);
542 /***********************************************************************
543 * GetUserObjectInformationW (USER32.@)
545 BOOL WINAPI
GetUserObjectInformationW( HANDLE handle
, INT index
, LPVOID info
, DWORD len
, LPDWORD needed
)
547 static const WCHAR desktopW
[] = { 'D','e','s','k','t','o','p',0 };
548 static const WCHAR winstationW
[] = { 'W','i','n','d','o','w','S','t','a','t','i','o','n',0 };
555 USEROBJECTFLAGS
*obj_flags
= info
;
556 if (needed
) *needed
= sizeof(*obj_flags
);
557 if (len
< sizeof(*obj_flags
))
559 SetLastError( ERROR_BUFFER_OVERFLOW
);
562 SERVER_START_REQ( set_user_object_info
)
564 req
->handle
= wine_server_obj_handle( handle
);
566 ret
= !wine_server_call_err( req
);
569 /* FIXME: inherit flag */
570 obj_flags
->dwFlags
= reply
->old_obj_flags
;
578 SERVER_START_REQ( set_user_object_info
)
580 req
->handle
= wine_server_obj_handle( handle
);
582 ret
= !wine_server_call_err( req
);
585 size_t size
= reply
->is_desktop
? sizeof(desktopW
) : sizeof(winstationW
);
586 if (needed
) *needed
= size
;
589 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
592 else memcpy( info
, reply
->is_desktop
? desktopW
: winstationW
, size
);
600 WCHAR buffer
[MAX_PATH
];
601 SERVER_START_REQ( set_user_object_info
)
603 req
->handle
= wine_server_obj_handle( handle
);
605 wine_server_set_reply( req
, buffer
, sizeof(buffer
) - sizeof(WCHAR
) );
606 ret
= !wine_server_call_err( req
);
609 size_t size
= wine_server_reply_size( reply
);
610 buffer
[size
/ sizeof(WCHAR
)] = 0;
611 size
+= sizeof(WCHAR
);
612 if (needed
) *needed
= size
;
615 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
618 else memcpy( info
, buffer
, size
);
626 FIXME( "not supported index %d\n", index
);
629 SetLastError( ERROR_INVALID_PARAMETER
);
635 /******************************************************************************
636 * SetUserObjectInformationA (USER32.@)
638 BOOL WINAPI
SetUserObjectInformationA( HANDLE handle
, INT index
, LPVOID info
, DWORD len
)
640 return SetUserObjectInformationW( handle
, index
, info
, len
);
644 /******************************************************************************
645 * SetUserObjectInformationW (USER32.@)
647 BOOL WINAPI
SetUserObjectInformationW( HANDLE handle
, INT index
, LPVOID info
, DWORD len
)
650 const USEROBJECTFLAGS
*obj_flags
= info
;
652 if (index
!= UOI_FLAGS
|| !info
|| len
< sizeof(*obj_flags
))
654 SetLastError( ERROR_INVALID_PARAMETER
);
657 /* FIXME: inherit flag */
658 SERVER_START_REQ( set_user_object_info
)
660 req
->handle
= wine_server_obj_handle( handle
);
661 req
->flags
= SET_USER_OBJECT_SET_FLAGS
;
662 req
->obj_flags
= obj_flags
->dwFlags
;
663 ret
= !wine_server_call_err( req
);
670 /***********************************************************************
671 * GetUserObjectSecurity (USER32.@)
673 BOOL WINAPI
GetUserObjectSecurity( HANDLE handle
, PSECURITY_INFORMATION info
,
674 PSECURITY_DESCRIPTOR sid
, DWORD len
, LPDWORD needed
)
676 FIXME( "(%p %p %p len=%d %p),stub!\n", handle
, info
, sid
, len
, needed
);
678 *needed
= sizeof(SECURITY_DESCRIPTOR
);
679 if (len
< sizeof(SECURITY_DESCRIPTOR
))
681 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
684 return InitializeSecurityDescriptor(sid
, SECURITY_DESCRIPTOR_REVISION
);
687 /***********************************************************************
688 * SetUserObjectSecurity (USER32.@)
690 BOOL WINAPI
SetUserObjectSecurity( HANDLE handle
, PSECURITY_INFORMATION info
,
691 PSECURITY_DESCRIPTOR sid
)
693 FIXME( "(%p,%p,%p),stub!\n", handle
, info
, sid
);