| /* | |
| * 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 <stdarg.h> | |
| #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 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); | |
| 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; | |
| } |