shlwapi: Fix a string leak (Valgrind).
[wine.git] / dlls / user32 / winstation.c
blob61add7692ccaec394cf9936770ebef1540f3fb6e
1 /*
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
21 #include "ntstatus.h"
22 #define WIN32_NO_STATUS
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winerror.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winternl.h"
32 #include "ddk/wdm.h"
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
44 NAMEENUMPROCA func;
45 LPARAM 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 ))
54 return FALSE;
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[] = {'\\','W','i','n','d','o','w','s','\\',
63 'W','i','n','d','o','w','S','t','a','t','i','o','n','s',0};
64 UNICODE_STRING str;
65 OBJECT_ATTRIBUTES attr;
67 if (!handle)
69 HANDLE dir;
71 RtlInitUnicodeString( &str, basenameW );
72 InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
73 NtOpenDirectoryObject( &dir, DIRECTORY_CREATE_OBJECT | DIRECTORY_TRAVERSE, &attr );
74 if (InterlockedCompareExchangePointer( &handle, dir, 0 ) != 0) /* someone beat us here */
75 CloseHandle( dir );
77 return handle;
80 /***********************************************************************
81 * CreateWindowStationA (USER32.@)
83 HWINSTA WINAPI CreateWindowStationA( LPCSTR name, DWORD reserved, ACCESS_MASK access,
84 LPSECURITY_ATTRIBUTES sa )
86 WCHAR buffer[MAX_PATH];
88 if (!name) return CreateWindowStationW( NULL, reserved, access, sa );
90 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
92 SetLastError( ERROR_FILENAME_EXCED_RANGE );
93 return 0;
95 return CreateWindowStationW( buffer, reserved, access, sa );
99 /***********************************************************************
100 * CreateWindowStationW (USER32.@)
102 HWINSTA WINAPI CreateWindowStationW( LPCWSTR name, DWORD reserved, ACCESS_MASK access,
103 LPSECURITY_ATTRIBUTES sa )
105 HANDLE ret;
106 DWORD len = name ? strlenW(name) : 0;
108 if (len >= MAX_PATH)
110 SetLastError( ERROR_FILENAME_EXCED_RANGE );
111 return 0;
113 SERVER_START_REQ( create_winstation )
115 req->flags = 0;
116 req->access = access;
117 req->attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
118 ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
119 req->rootdir = wine_server_obj_handle( get_winstations_dir_handle() );
120 wine_server_add_data( req, name, len * sizeof(WCHAR) );
121 wine_server_call_err( req );
122 ret = wine_server_ptr_handle( reply->handle );
124 SERVER_END_REQ;
125 return ret;
129 /******************************************************************************
130 * OpenWindowStationA (USER32.@)
132 HWINSTA WINAPI OpenWindowStationA( LPCSTR name, BOOL inherit, ACCESS_MASK access )
134 WCHAR buffer[MAX_PATH];
136 if (!name) return OpenWindowStationW( NULL, inherit, access );
138 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
140 SetLastError( ERROR_FILENAME_EXCED_RANGE );
141 return 0;
143 return OpenWindowStationW( buffer, inherit, access );
147 /******************************************************************************
148 * OpenWindowStationW (USER32.@)
150 HWINSTA WINAPI OpenWindowStationW( LPCWSTR name, BOOL inherit, ACCESS_MASK access )
152 HANDLE ret = 0;
153 DWORD len = name ? strlenW(name) : 0;
154 if (len >= MAX_PATH)
156 SetLastError( ERROR_FILENAME_EXCED_RANGE );
157 return 0;
159 SERVER_START_REQ( open_winstation )
161 req->access = access;
162 req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
163 req->rootdir = wine_server_obj_handle( get_winstations_dir_handle() );
164 wine_server_add_data( req, name, len * sizeof(WCHAR) );
165 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
167 SERVER_END_REQ;
168 return ret;
172 /***********************************************************************
173 * CloseWindowStation (USER32.@)
175 BOOL WINAPI CloseWindowStation( HWINSTA handle )
177 BOOL ret;
178 SERVER_START_REQ( close_winstation )
180 req->handle = wine_server_obj_handle( handle );
181 ret = !wine_server_call_err( req );
183 SERVER_END_REQ;
184 return ret;
188 /******************************************************************************
189 * GetProcessWindowStation (USER32.@)
191 HWINSTA WINAPI GetProcessWindowStation(void)
193 HWINSTA ret = 0;
195 SERVER_START_REQ( get_process_winstation )
197 if (!wine_server_call_err( req ))
198 ret = wine_server_ptr_handle( reply->handle );
200 SERVER_END_REQ;
201 return ret;
205 /***********************************************************************
206 * SetProcessWindowStation (USER32.@)
208 BOOL WINAPI SetProcessWindowStation( HWINSTA handle )
210 BOOL ret;
212 SERVER_START_REQ( set_process_winstation )
214 req->handle = wine_server_obj_handle( handle );
215 ret = !wine_server_call_err( req );
217 SERVER_END_REQ;
218 return ret;
222 /******************************************************************************
223 * EnumWindowStationsA (USER32.@)
225 BOOL WINAPI EnumWindowStationsA( WINSTAENUMPROCA func, LPARAM lparam )
227 struct enum_proc_lparam data;
228 data.func = func;
229 data.lparam = lparam;
230 return EnumWindowStationsW( enum_names_WtoA, (LPARAM)&data );
234 /******************************************************************************
235 * EnumWindowStationsW (USER32.@)
237 BOOL WINAPI EnumWindowStationsW( WINSTAENUMPROCW func, LPARAM lparam )
239 unsigned int index = 0;
240 WCHAR name[MAX_PATH];
241 BOOL ret = TRUE;
242 NTSTATUS status;
244 while (ret)
246 SERVER_START_REQ( enum_winstation )
248 req->index = index;
249 wine_server_set_reply( req, name, sizeof(name) - sizeof(WCHAR) );
250 status = wine_server_call( req );
251 name[wine_server_reply_size(reply)/sizeof(WCHAR)] = 0;
252 index = reply->next;
254 SERVER_END_REQ;
255 if (status == STATUS_NO_MORE_ENTRIES)
256 break;
257 if (status)
259 SetLastError( RtlNtStatusToDosError( status ) );
260 return FALSE;
262 ret = func( name, lparam );
264 return ret;
268 /***********************************************************************
269 * CreateDesktopA (USER32.@)
271 HDESK WINAPI CreateDesktopA( LPCSTR name, LPCSTR device, LPDEVMODEA devmode,
272 DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa )
274 WCHAR buffer[MAX_PATH];
276 if (device || devmode)
278 SetLastError( ERROR_INVALID_PARAMETER );
279 return 0;
281 if (!name) return CreateDesktopW( NULL, NULL, NULL, flags, access, sa );
283 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
285 SetLastError( ERROR_FILENAME_EXCED_RANGE );
286 return 0;
288 return CreateDesktopW( buffer, NULL, NULL, flags, access, sa );
292 /***********************************************************************
293 * CreateDesktopW (USER32.@)
295 HDESK WINAPI CreateDesktopW( LPCWSTR name, LPCWSTR device, LPDEVMODEW devmode,
296 DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa )
298 HANDLE ret;
299 DWORD len = name ? strlenW(name) : 0;
301 if (device || devmode)
303 SetLastError( ERROR_INVALID_PARAMETER );
304 return 0;
306 if (len >= MAX_PATH)
308 SetLastError( ERROR_FILENAME_EXCED_RANGE );
309 return 0;
311 SERVER_START_REQ( create_desktop )
313 req->flags = flags;
314 req->access = access;
315 req->attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
316 ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
317 wine_server_add_data( req, name, len * sizeof(WCHAR) );
318 wine_server_call_err( req );
319 ret = wine_server_ptr_handle( reply->handle );
321 SERVER_END_REQ;
322 return ret;
326 /******************************************************************************
327 * OpenDesktopA (USER32.@)
329 HDESK WINAPI OpenDesktopA( LPCSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
331 WCHAR buffer[MAX_PATH];
333 if (!name) return OpenDesktopW( NULL, flags, inherit, access );
335 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
337 SetLastError( ERROR_FILENAME_EXCED_RANGE );
338 return 0;
340 return OpenDesktopW( buffer, flags, inherit, access );
344 HDESK open_winstation_desktop( HWINSTA hwinsta, LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
346 HANDLE ret = 0;
347 DWORD len = name ? strlenW(name) : 0;
348 if (len >= MAX_PATH)
350 SetLastError( ERROR_FILENAME_EXCED_RANGE );
351 return 0;
353 SERVER_START_REQ( open_desktop )
355 req->winsta = wine_server_obj_handle( hwinsta );
356 req->flags = flags;
357 req->access = access;
358 req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
359 wine_server_add_data( req, name, len * sizeof(WCHAR) );
360 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
362 SERVER_END_REQ;
363 return ret;
367 /******************************************************************************
368 * OpenDesktopW (USER32.@)
370 HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
372 return open_winstation_desktop( NULL, name, flags, inherit, access );
376 /***********************************************************************
377 * CloseDesktop (USER32.@)
379 BOOL WINAPI CloseDesktop( HDESK handle )
381 BOOL ret;
382 SERVER_START_REQ( close_desktop )
384 req->handle = wine_server_obj_handle( handle );
385 ret = !wine_server_call_err( req );
387 SERVER_END_REQ;
388 return ret;
392 /******************************************************************************
393 * GetThreadDesktop (USER32.@)
395 HDESK WINAPI GetThreadDesktop( DWORD thread )
397 HDESK ret = 0;
399 SERVER_START_REQ( get_thread_desktop )
401 req->tid = thread;
402 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
404 SERVER_END_REQ;
405 return ret;
409 /******************************************************************************
410 * SetThreadDesktop (USER32.@)
412 BOOL WINAPI SetThreadDesktop( HDESK handle )
414 BOOL ret;
416 SERVER_START_REQ( set_thread_desktop )
418 req->handle = wine_server_obj_handle( handle );
419 ret = !wine_server_call_err( req );
421 SERVER_END_REQ;
422 if (ret) /* reset the desktop windows */
424 struct user_thread_info *thread_info = get_user_thread_info();
425 struct user_key_state_info *key_state_info = thread_info->key_state;
426 thread_info->top_window = 0;
427 thread_info->msg_window = 0;
428 if (key_state_info) key_state_info->time = 0;
430 return ret;
434 /******************************************************************************
435 * EnumDesktopsA (USER32.@)
437 BOOL WINAPI EnumDesktopsA( HWINSTA winsta, DESKTOPENUMPROCA func, LPARAM lparam )
439 struct enum_proc_lparam data;
440 data.func = func;
441 data.lparam = lparam;
442 return EnumDesktopsW( winsta, enum_names_WtoA, (LPARAM)&data );
446 /******************************************************************************
447 * EnumDesktopsW (USER32.@)
449 BOOL WINAPI EnumDesktopsW( HWINSTA winsta, DESKTOPENUMPROCW func, LPARAM lparam )
451 unsigned int index = 0;
452 WCHAR name[MAX_PATH];
453 BOOL ret = TRUE;
454 NTSTATUS status;
456 if (!winsta)
457 winsta = GetProcessWindowStation();
459 while (ret)
461 SERVER_START_REQ( enum_desktop )
463 req->winstation = wine_server_obj_handle( winsta );
464 req->index = index;
465 wine_server_set_reply( req, name, sizeof(name) - sizeof(WCHAR) );
466 status = wine_server_call( req );
467 name[wine_server_reply_size(reply)/sizeof(WCHAR)] = 0;
468 index = reply->next;
470 SERVER_END_REQ;
471 if (status == STATUS_NO_MORE_ENTRIES)
472 break;
473 if (status)
475 SetLastError( RtlNtStatusToDosError( status ) );
476 return FALSE;
478 ret = func(name, lparam);
480 return ret;
484 /******************************************************************************
485 * OpenInputDesktop (USER32.@)
487 HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
489 HANDLE ret = 0;
491 TRACE( "(%x,%i,%x)\n", flags, inherit, access );
493 if (flags)
494 FIXME( "partial stub flags %08x\n", flags );
496 SERVER_START_REQ( open_input_desktop )
498 req->flags = flags;
499 req->access = access;
500 req->attributes = inherit ? OBJ_INHERIT : 0;
501 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
503 SERVER_END_REQ;
505 return ret;
509 /***********************************************************************
510 * GetUserObjectInformationA (USER32.@)
512 BOOL WINAPI GetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed )
514 /* check for information types returning strings */
515 if (index == UOI_TYPE || index == UOI_NAME)
517 WCHAR buffer[MAX_PATH];
518 DWORD lenA, lenW;
520 if (!GetUserObjectInformationW( handle, index, buffer, sizeof(buffer), &lenW )) return FALSE;
521 lenA = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
522 if (needed) *needed = lenA;
523 if (lenA > len)
525 /* If the buffer length supplied by the caller is insufficient, Windows returns a
526 'needed' length based upon the Unicode byte length, so we should do similarly. */
527 if (needed) *needed = lenW;
529 SetLastError( ERROR_INSUFFICIENT_BUFFER );
530 return FALSE;
532 if (info) WideCharToMultiByte( CP_ACP, 0, buffer, -1, info, len, NULL, NULL );
533 return TRUE;
535 return GetUserObjectInformationW( handle, index, info, len, needed );
539 /***********************************************************************
540 * GetUserObjectInformationW (USER32.@)
542 BOOL WINAPI GetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed )
544 static const WCHAR desktopW[] = { 'D','e','s','k','t','o','p',0 };
545 static const WCHAR winstationW[] = { 'W','i','n','d','o','w','S','t','a','t','i','o','n',0 };
546 BOOL ret;
548 switch(index)
550 case UOI_FLAGS:
552 USEROBJECTFLAGS *obj_flags = info;
553 if (needed) *needed = sizeof(*obj_flags);
554 if (len < sizeof(*obj_flags))
556 SetLastError( ERROR_BUFFER_OVERFLOW );
557 return FALSE;
559 SERVER_START_REQ( set_user_object_info )
561 req->handle = wine_server_obj_handle( handle );
562 req->flags = 0;
563 ret = !wine_server_call_err( req );
564 if (ret)
566 /* FIXME: inherit flag */
567 obj_flags->dwFlags = reply->old_obj_flags;
570 SERVER_END_REQ;
572 return ret;
574 case UOI_TYPE:
575 SERVER_START_REQ( set_user_object_info )
577 req->handle = wine_server_obj_handle( handle );
578 req->flags = 0;
579 ret = !wine_server_call_err( req );
580 if (ret)
582 size_t size = reply->is_desktop ? sizeof(desktopW) : sizeof(winstationW);
583 if (needed) *needed = size;
584 if (len < size)
586 SetLastError( ERROR_INSUFFICIENT_BUFFER );
587 ret = FALSE;
589 else memcpy( info, reply->is_desktop ? desktopW : winstationW, size );
592 SERVER_END_REQ;
593 return ret;
595 case UOI_NAME:
597 WCHAR buffer[MAX_PATH];
598 SERVER_START_REQ( set_user_object_info )
600 req->handle = wine_server_obj_handle( handle );
601 req->flags = 0;
602 wine_server_set_reply( req, buffer, sizeof(buffer) - sizeof(WCHAR) );
603 ret = !wine_server_call_err( req );
604 if (ret)
606 size_t size = wine_server_reply_size( reply );
607 buffer[size / sizeof(WCHAR)] = 0;
608 size += sizeof(WCHAR);
609 if (needed) *needed = size;
610 if (len < size)
612 SetLastError( ERROR_INSUFFICIENT_BUFFER );
613 ret = FALSE;
615 else memcpy( info, buffer, size );
618 SERVER_END_REQ;
620 return ret;
622 case UOI_USER_SID:
623 FIXME( "not supported index %d\n", index );
624 /* fall through */
625 default:
626 SetLastError( ERROR_INVALID_PARAMETER );
627 return FALSE;
632 /******************************************************************************
633 * SetUserObjectInformationA (USER32.@)
635 BOOL WINAPI SetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len )
637 return SetUserObjectInformationW( handle, index, info, len );
641 /******************************************************************************
642 * SetUserObjectInformationW (USER32.@)
644 BOOL WINAPI SetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len )
646 BOOL ret;
647 const USEROBJECTFLAGS *obj_flags = info;
649 if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags))
651 SetLastError( ERROR_INVALID_PARAMETER );
652 return FALSE;
654 /* FIXME: inherit flag */
655 SERVER_START_REQ( set_user_object_info )
657 req->handle = wine_server_obj_handle( handle );
658 req->flags = SET_USER_OBJECT_SET_FLAGS;
659 req->obj_flags = obj_flags->dwFlags;
660 ret = !wine_server_call_err( req );
662 SERVER_END_REQ;
663 return ret;
667 /***********************************************************************
668 * GetUserObjectSecurity (USER32.@)
670 BOOL WINAPI GetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info,
671 PSECURITY_DESCRIPTOR sid, DWORD len, LPDWORD needed )
673 FIXME( "(%p %p %p len=%d %p),stub!\n", handle, info, sid, len, needed );
674 if (needed)
675 *needed = sizeof(SECURITY_DESCRIPTOR);
676 if (len < sizeof(SECURITY_DESCRIPTOR))
678 SetLastError( ERROR_INSUFFICIENT_BUFFER );
679 return FALSE;
681 return InitializeSecurityDescriptor(sid, SECURITY_DESCRIPTOR_REVISION);
684 /***********************************************************************
685 * SetUserObjectSecurity (USER32.@)
687 BOOL WINAPI SetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info,
688 PSECURITY_DESCRIPTOR sid )
690 FIXME( "(%p,%p,%p),stub!\n", handle, info, sid );
691 return TRUE;