| /* |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "winerror.h" |
| #include "wingdi.h" |
| #include "winuser.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 ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreateWindowStationA (USER32.@) |
| */ |
| HWINSTA WINAPI CreateWindowStationA( LPCSTR name, DWORD reserved, ACCESS_MASK access, |
| LPSECURITY_ATTRIBUTES sa ) |
| { |
| WCHAR buffer[MAX_PATH]; |
| |
| if (!name) return CreateWindowStationW( NULL, reserved, access, sa ); |
| |
| if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH )) |
| { |
| SetLastError( ERROR_FILENAME_EXCED_RANGE ); |
| return 0; |
| } |
| return CreateWindowStationW( buffer, reserved, access, sa ); |
| } |
| |
| |
| /*********************************************************************** |
| * CreateWindowStationW (USER32.@) |
| */ |
| HWINSTA WINAPI CreateWindowStationW( LPCWSTR name, DWORD reserved, 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 | OBJ_OPENIF | |
| ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0); |
| wine_server_add_data( req, name, len * sizeof(WCHAR) ); |
| /* it doesn't seem to set last error */ |
| wine_server_call( req ); |
| ret = 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); |
| wine_server_add_data( req, name, len * sizeof(WCHAR) ); |
| if (!wine_server_call_err( req )) ret = reply->handle; |
| } |
| SERVER_END_REQ; |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * CloseWindowStation (USER32.@) |
| */ |
| BOOL WINAPI CloseWindowStation( HWINSTA handle ) |
| { |
| BOOL ret; |
| SERVER_START_REQ( close_winstation ) |
| { |
| req->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 = reply->handle; |
| } |
| SERVER_END_REQ; |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * SetProcessWindowStation (USER32.@) |
| */ |
| BOOL WINAPI SetProcessWindowStation( HWINSTA handle ) |
| { |
| BOOL ret; |
| |
| SERVER_START_REQ( set_process_winstation ) |
| { |
| req->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 ); |
| } |
| |
| |
| /****************************************************************************** |
| * EnumWindowStationsA (USER32.@) |
| */ |
| BOOL WINAPI EnumWindowStationsW( WINSTAENUMPROCW func, LPARAM lparam ) |
| { |
| FIXME( "(%p,%lx): stub\n", func, lparam ); |
| SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * 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) ); |
| /* it doesn't seem to set last error */ |
| wine_server_call( req ); |
| ret = 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 ); |
| } |
| |
| |
| /****************************************************************************** |
| * OpenDesktopW (USER32.@) |
| */ |
| HDESK WINAPI OpenDesktopW( 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->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( req )) ret = reply->handle; |
| } |
| SERVER_END_REQ; |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * CloseDesktop (USER32.@) |
| */ |
| BOOL WINAPI CloseDesktop( HDESK handle ) |
| { |
| BOOL ret; |
| SERVER_START_REQ( close_desktop ) |
| { |
| req->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 = reply->handle; |
| } |
| SERVER_END_REQ; |
| return ret; |
| } |
| |
| |
| /****************************************************************************** |
| * SetThreadDesktop (USER32.@) |
| */ |
| BOOL WINAPI SetThreadDesktop( HDESK handle ) |
| { |
| BOOL ret; |
| |
| SERVER_START_REQ( set_thread_desktop ) |
| { |
| req->handle = handle; |
| ret = !wine_server_call_err( req ); |
| } |
| SERVER_END_REQ; |
| if (ret) get_user_thread_info()->desktop = 0; /* reset the desktop window */ |
| 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 ) |
| { |
| FIXME( "(%p,%p,%lx): stub\n", winsta, func, lparam ); |
| SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); |
| return FALSE; |
| } |
| |
| |
| /****************************************************************************** |
| * OpenInputDesktop (USER32.@) |
| */ |
| HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access ) |
| { |
| FIXME( "(%lx,%i,%lx): stub\n", flags, inherit, access ); |
| SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * EnumDesktopWindows (USER32.@) |
| */ |
| BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam ) |
| { |
| FIXME( "(%p,%p,0x%lx): stub!\n", desktop, func, lparam ); |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * 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; |
| |
| if (!GetUserObjectInformationW( handle, index, buffer, sizeof(buffer), NULL )) return FALSE; |
| lenA = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL ); |
| if (needed) *needed = lenA; |
| if (lenA > len) |
| { |
| SetLastError( ERROR_MORE_DATA ); |
| 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 = 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 = 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_MORE_DATA ); |
| 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 = 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_MORE_DATA ); |
| 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 = handle; |
| req->flags = SET_USER_OBJECT_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=%ld %p),stub!\n", handle, info, sid, len, needed ); |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * SetUserObjectSecurity (USER32.@) |
| */ |
| BOOL WINAPI SetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info, |
| PSECURITY_DESCRIPTOR sid ) |
| { |
| FIXME( "(%p,%p,%p),stub!\n", handle, info, sid ); |
| return TRUE; |
| } |