/* * Window stations and desktops * * Copyright 2002 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "ntstatus.h" #define WIN32_NO_STATUS #include #include "windef.h" #include "winbase.h" #include "winnls.h" #include "winerror.h" #include "wingdi.h" #include "winuser.h" #include "winternl.h" #include "ddk/wdm.h" #include "wine/server.h" #include "wine/unicode.h" #include "wine/debug.h" #include "user_private.h" WINE_DEFAULT_DEBUG_CHANNEL(winstation); /* callback for enumeration functions */ struct enum_proc_lparam { NAMEENUMPROCA func; LPARAM lparam; }; static BOOL CALLBACK enum_names_WtoA( LPWSTR name, LPARAM lparam ) { struct enum_proc_lparam *data = (struct enum_proc_lparam *)lparam; char buffer[MAX_PATH]; if (!WideCharToMultiByte( CP_ACP, 0, name, -1, buffer, sizeof(buffer), NULL, NULL )) return FALSE; return data->func( buffer, data->lparam ); } /* return a handle to the directory where window station objects are created */ static HANDLE get_winstations_dir_handle(void) { static HANDLE handle = NULL; static const WCHAR basenameW[] = {'\\','S','e','s','s','i','o','n','s','\\','%','u', '\\','W','i','n','d','o','w','s','\\', 'W','i','n','d','o','w','S','t','a','t','i','o','n','s',0}; WCHAR buffer[64]; UNICODE_STRING str; OBJECT_ATTRIBUTES attr; if (!handle) { HANDLE dir; sprintfW( buffer, basenameW, NtCurrentTeb()->Peb->SessionId ); RtlInitUnicodeString( &str, buffer ); InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); NtOpenDirectoryObject( &dir, DIRECTORY_CREATE_OBJECT | DIRECTORY_TRAVERSE, &attr ); if (InterlockedCompareExchangePointer( &handle, dir, 0 ) != 0) /* someone beat us here */ CloseHandle( dir ); } return handle; } /*********************************************************************** * CreateWindowStationA (USER32.@) */ HWINSTA WINAPI CreateWindowStationA( LPCSTR name, DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa ) { WCHAR buffer[MAX_PATH]; if (!name) return CreateWindowStationW( NULL, flags, access, sa ); if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } return CreateWindowStationW( buffer, flags, access, sa ); } /*********************************************************************** * CreateWindowStationW (USER32.@) */ HWINSTA WINAPI CreateWindowStationW( LPCWSTR name, DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa ) { HANDLE ret; DWORD len = name ? strlenW(name) : 0; if (len >= MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } SERVER_START_REQ( create_winstation ) { req->flags = 0; req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | ((flags & CWF_CREATE_ONLY) ? 0 : OBJ_OPENIF) | ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0); req->rootdir = wine_server_obj_handle( get_winstations_dir_handle() ); wine_server_add_data( req, name, len * sizeof(WCHAR) ); wine_server_call_err( req ); ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /****************************************************************************** * OpenWindowStationA (USER32.@) */ HWINSTA WINAPI OpenWindowStationA( LPCSTR name, BOOL inherit, ACCESS_MASK access ) { WCHAR buffer[MAX_PATH]; if (!name) return OpenWindowStationW( NULL, inherit, access ); if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } return OpenWindowStationW( buffer, inherit, access ); } /****************************************************************************** * OpenWindowStationW (USER32.@) */ HWINSTA WINAPI OpenWindowStationW( LPCWSTR name, BOOL inherit, ACCESS_MASK access ) { HANDLE ret = 0; DWORD len = name ? strlenW(name) : 0; if (len >= MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } SERVER_START_REQ( open_winstation ) { req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0); req->rootdir = wine_server_obj_handle( get_winstations_dir_handle() ); wine_server_add_data( req, name, len * sizeof(WCHAR) ); if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /*********************************************************************** * CloseWindowStation (USER32.@) */ BOOL WINAPI CloseWindowStation( HWINSTA handle ) { BOOL ret; SERVER_START_REQ( close_winstation ) { req->handle = wine_server_obj_handle( handle ); ret = !wine_server_call_err( req ); } SERVER_END_REQ; return ret; } /****************************************************************************** * GetProcessWindowStation (USER32.@) */ HWINSTA WINAPI GetProcessWindowStation(void) { HWINSTA ret = 0; SERVER_START_REQ( get_process_winstation ) { if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /*********************************************************************** * SetProcessWindowStation (USER32.@) */ BOOL WINAPI SetProcessWindowStation( HWINSTA handle ) { BOOL ret; SERVER_START_REQ( set_process_winstation ) { req->handle = wine_server_obj_handle( handle ); ret = !wine_server_call_err( req ); } SERVER_END_REQ; return ret; } /****************************************************************************** * EnumWindowStationsA (USER32.@) */ BOOL WINAPI EnumWindowStationsA( WINSTAENUMPROCA func, LPARAM lparam ) { struct enum_proc_lparam data; data.func = func; data.lparam = lparam; return EnumWindowStationsW( enum_names_WtoA, (LPARAM)&data ); } /****************************************************************************** * EnumWindowStationsW (USER32.@) */ BOOL WINAPI EnumWindowStationsW( WINSTAENUMPROCW func, LPARAM lparam ) { unsigned int index = 0; WCHAR name[MAX_PATH]; BOOL ret = TRUE; NTSTATUS status; while (ret) { SERVER_START_REQ( enum_winstation ) { req->index = index; wine_server_set_reply( req, name, sizeof(name) - sizeof(WCHAR) ); status = wine_server_call( req ); name[wine_server_reply_size(reply)/sizeof(WCHAR)] = 0; index = reply->next; } SERVER_END_REQ; if (status == STATUS_NO_MORE_ENTRIES) break; if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } ret = func( name, lparam ); } return ret; } /*********************************************************************** * CreateDesktopA (USER32.@) */ HDESK WINAPI CreateDesktopA( LPCSTR name, LPCSTR device, LPDEVMODEA devmode, DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa ) { WCHAR buffer[MAX_PATH]; if (device || devmode) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; } if (!name) return CreateDesktopW( NULL, NULL, NULL, flags, access, sa ); if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } return CreateDesktopW( buffer, NULL, NULL, flags, access, sa ); } /*********************************************************************** * CreateDesktopW (USER32.@) */ HDESK WINAPI CreateDesktopW( LPCWSTR name, LPCWSTR device, LPDEVMODEW devmode, DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa ) { HANDLE ret; DWORD len = name ? strlenW(name) : 0; if (device || devmode) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; } if (len >= MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } SERVER_START_REQ( create_desktop ) { req->flags = flags; req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF | ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0); wine_server_add_data( req, name, len * sizeof(WCHAR) ); wine_server_call_err( req ); ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /****************************************************************************** * OpenDesktopA (USER32.@) */ HDESK WINAPI OpenDesktopA( LPCSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) { WCHAR buffer[MAX_PATH]; if (!name) return OpenDesktopW( NULL, flags, inherit, access ); if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } return OpenDesktopW( buffer, flags, inherit, access ); } HDESK open_winstation_desktop( HWINSTA hwinsta, LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) { HANDLE ret = 0; DWORD len = name ? strlenW(name) : 0; if (len >= MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return 0; } SERVER_START_REQ( open_desktop ) { req->winsta = wine_server_obj_handle( hwinsta ); req->flags = flags; req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0); wine_server_add_data( req, name, len * sizeof(WCHAR) ); if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /****************************************************************************** * OpenDesktopW (USER32.@) */ HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) { return open_winstation_desktop( NULL, name, flags, inherit, access ); } /*********************************************************************** * CloseDesktop (USER32.@) */ BOOL WINAPI CloseDesktop( HDESK handle ) { BOOL ret; SERVER_START_REQ( close_desktop ) { req->handle = wine_server_obj_handle( handle ); ret = !wine_server_call_err( req ); } SERVER_END_REQ; return ret; } /****************************************************************************** * GetThreadDesktop (USER32.@) */ HDESK WINAPI GetThreadDesktop( DWORD thread ) { HDESK ret = 0; SERVER_START_REQ( get_thread_desktop ) { req->tid = thread; if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /****************************************************************************** * SetThreadDesktop (USER32.@) */ BOOL WINAPI SetThreadDesktop( HDESK handle ) { BOOL ret; SERVER_START_REQ( set_thread_desktop ) { req->handle = wine_server_obj_handle( handle ); ret = !wine_server_call_err( req ); } SERVER_END_REQ; if (ret) /* reset the desktop windows */ { struct user_thread_info *thread_info = get_user_thread_info(); struct user_key_state_info *key_state_info = thread_info->key_state; thread_info->top_window = 0; thread_info->msg_window = 0; if (key_state_info) key_state_info->time = 0; } return ret; } /****************************************************************************** * EnumDesktopsA (USER32.@) */ BOOL WINAPI EnumDesktopsA( HWINSTA winsta, DESKTOPENUMPROCA func, LPARAM lparam ) { struct enum_proc_lparam data; data.func = func; data.lparam = lparam; return EnumDesktopsW( winsta, enum_names_WtoA, (LPARAM)&data ); } /****************************************************************************** * EnumDesktopsW (USER32.@) */ BOOL WINAPI EnumDesktopsW( HWINSTA winsta, DESKTOPENUMPROCW func, LPARAM lparam ) { unsigned int index = 0; WCHAR name[MAX_PATH]; BOOL ret = TRUE; NTSTATUS status; if (!winsta) winsta = GetProcessWindowStation(); while (ret) { SERVER_START_REQ( enum_desktop ) { req->winstation = wine_server_obj_handle( winsta ); req->index = index; wine_server_set_reply( req, name, sizeof(name) - sizeof(WCHAR) ); status = wine_server_call( req ); name[wine_server_reply_size(reply)/sizeof(WCHAR)] = 0; index = reply->next; } SERVER_END_REQ; if (status == STATUS_NO_MORE_ENTRIES) break; if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } ret = func(name, lparam); } return ret; } /****************************************************************************** * OpenInputDesktop (USER32.@) */ HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access ) { HANDLE ret = 0; TRACE( "(%x,%i,%x)\n", flags, inherit, access ); if (flags) FIXME( "partial stub flags %08x\n", flags ); SERVER_START_REQ( open_input_desktop ) { req->flags = flags; req->access = access; req->attributes = inherit ? OBJ_INHERIT : 0; if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; return ret; } /*********************************************************************** * GetUserObjectInformationA (USER32.@) */ BOOL WINAPI GetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed ) { /* check for information types returning strings */ if (index == UOI_TYPE || index == UOI_NAME) { WCHAR buffer[MAX_PATH]; DWORD lenA, lenW; if (!GetUserObjectInformationW( handle, index, buffer, sizeof(buffer), &lenW )) return FALSE; lenA = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL ); if (needed) *needed = lenA; if (lenA > len) { /* If the buffer length supplied by the caller is insufficient, Windows returns a 'needed' length based upon the Unicode byte length, so we should do similarly. */ if (needed) *needed = lenW; SetLastError( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } if (info) WideCharToMultiByte( CP_ACP, 0, buffer, -1, info, len, NULL, NULL ); return TRUE; } return GetUserObjectInformationW( handle, index, info, len, needed ); } /*********************************************************************** * GetUserObjectInformationW (USER32.@) */ BOOL WINAPI GetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed ) { static const WCHAR desktopW[] = { 'D','e','s','k','t','o','p',0 }; static const WCHAR winstationW[] = { 'W','i','n','d','o','w','S','t','a','t','i','o','n',0 }; BOOL ret; switch(index) { case UOI_FLAGS: { USEROBJECTFLAGS *obj_flags = info; if (needed) *needed = sizeof(*obj_flags); if (len < sizeof(*obj_flags)) { SetLastError( ERROR_BUFFER_OVERFLOW ); return FALSE; } SERVER_START_REQ( set_user_object_info ) { req->handle = wine_server_obj_handle( handle ); req->flags = 0; ret = !wine_server_call_err( req ); if (ret) { /* FIXME: inherit flag */ obj_flags->dwFlags = reply->old_obj_flags; } } SERVER_END_REQ; } return ret; case UOI_TYPE: SERVER_START_REQ( set_user_object_info ) { req->handle = wine_server_obj_handle( handle ); req->flags = 0; ret = !wine_server_call_err( req ); if (ret) { size_t size = reply->is_desktop ? sizeof(desktopW) : sizeof(winstationW); if (needed) *needed = size; if (len < size) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); ret = FALSE; } else memcpy( info, reply->is_desktop ? desktopW : winstationW, size ); } } SERVER_END_REQ; return ret; case UOI_NAME: { WCHAR buffer[MAX_PATH]; SERVER_START_REQ( set_user_object_info ) { req->handle = wine_server_obj_handle( handle ); req->flags = 0; wine_server_set_reply( req, buffer, sizeof(buffer) - sizeof(WCHAR) ); ret = !wine_server_call_err( req ); if (ret) { size_t size = wine_server_reply_size( reply ); buffer[size / sizeof(WCHAR)] = 0; size += sizeof(WCHAR); if (needed) *needed = size; if (len < size) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); ret = FALSE; } else memcpy( info, buffer, size ); } } SERVER_END_REQ; } return ret; case UOI_USER_SID: FIXME( "not supported index %d\n", index ); /* fall through */ default: SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } } /****************************************************************************** * SetUserObjectInformationA (USER32.@) */ BOOL WINAPI SetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len ) { return SetUserObjectInformationW( handle, index, info, len ); } /****************************************************************************** * SetUserObjectInformationW (USER32.@) */ BOOL WINAPI SetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len ) { BOOL ret; const USEROBJECTFLAGS *obj_flags = info; if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } /* FIXME: inherit flag */ SERVER_START_REQ( set_user_object_info ) { req->handle = wine_server_obj_handle( handle ); req->flags = SET_USER_OBJECT_SET_FLAGS; req->obj_flags = obj_flags->dwFlags; ret = !wine_server_call_err( req ); } SERVER_END_REQ; return ret; } /*********************************************************************** * GetUserObjectSecurity (USER32.@) */ BOOL WINAPI GetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info, PSECURITY_DESCRIPTOR sid, DWORD len, LPDWORD needed ) { FIXME( "(%p %p %p len=%d %p),stub!\n", handle, info, sid, len, needed ); if (needed) *needed = sizeof(SECURITY_DESCRIPTOR); if (len < sizeof(SECURITY_DESCRIPTOR)) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } return InitializeSecurityDescriptor(sid, SECURITY_DESCRIPTOR_REVISION); } /*********************************************************************** * SetUserObjectSecurity (USER32.@) */ BOOL WINAPI SetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info, PSECURITY_DESCRIPTOR sid ) { FIXME( "(%p,%p,%p),stub!\n", handle, info, sid ); return TRUE; }