ddraw/tests: Rewrite LimitTest().
[wine.git] / dlls / user32 / winstation.c
blob673917c14c9086a57c8afbab6d9222164018800e
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[] = {'\\','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};
65 WCHAR buffer[64];
66 UNICODE_STRING str;
67 OBJECT_ATTRIBUTES attr;
69 if (!handle)
71 HANDLE dir;
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 */
78 CloseHandle( dir );
80 return handle;
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 );
96 return 0;
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 )
108 HANDLE ret;
109 DWORD len = name ? strlenW(name) : 0;
111 if (len >= MAX_PATH)
113 SetLastError( ERROR_FILENAME_EXCED_RANGE );
114 return 0;
116 SERVER_START_REQ( create_winstation )
118 req->flags = 0;
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 );
127 SERVER_END_REQ;
128 return ret;
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 );
144 return 0;
146 return OpenWindowStationW( buffer, inherit, access );
150 /******************************************************************************
151 * OpenWindowStationW (USER32.@)
153 HWINSTA WINAPI OpenWindowStationW( LPCWSTR name, BOOL inherit, ACCESS_MASK access )
155 HANDLE ret = 0;
156 DWORD len = name ? strlenW(name) : 0;
157 if (len >= MAX_PATH)
159 SetLastError( ERROR_FILENAME_EXCED_RANGE );
160 return 0;
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 );
170 SERVER_END_REQ;
171 return ret;
175 /***********************************************************************
176 * CloseWindowStation (USER32.@)
178 BOOL WINAPI CloseWindowStation( HWINSTA handle )
180 BOOL ret;
181 SERVER_START_REQ( close_winstation )
183 req->handle = wine_server_obj_handle( handle );
184 ret = !wine_server_call_err( req );
186 SERVER_END_REQ;
187 return ret;
191 /******************************************************************************
192 * GetProcessWindowStation (USER32.@)
194 HWINSTA WINAPI GetProcessWindowStation(void)
196 HWINSTA ret = 0;
198 SERVER_START_REQ( get_process_winstation )
200 if (!wine_server_call_err( req ))
201 ret = wine_server_ptr_handle( reply->handle );
203 SERVER_END_REQ;
204 return ret;
208 /***********************************************************************
209 * SetProcessWindowStation (USER32.@)
211 BOOL WINAPI SetProcessWindowStation( HWINSTA handle )
213 BOOL ret;
215 SERVER_START_REQ( set_process_winstation )
217 req->handle = wine_server_obj_handle( handle );
218 ret = !wine_server_call_err( req );
220 SERVER_END_REQ;
221 return ret;
225 /******************************************************************************
226 * EnumWindowStationsA (USER32.@)
228 BOOL WINAPI EnumWindowStationsA( WINSTAENUMPROCA func, LPARAM lparam )
230 struct enum_proc_lparam data;
231 data.func = func;
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];
244 BOOL ret = TRUE;
245 NTSTATUS status;
247 while (ret)
249 SERVER_START_REQ( enum_winstation )
251 req->index = index;
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;
255 index = reply->next;
257 SERVER_END_REQ;
258 if (status == STATUS_NO_MORE_ENTRIES)
259 break;
260 if (status)
262 SetLastError( RtlNtStatusToDosError( status ) );
263 return FALSE;
265 ret = func( name, lparam );
267 return ret;
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 );
282 return 0;
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 );
289 return 0;
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 )
301 HANDLE ret;
302 DWORD len = name ? strlenW(name) : 0;
304 if (device || devmode)
306 SetLastError( ERROR_INVALID_PARAMETER );
307 return 0;
309 if (len >= MAX_PATH)
311 SetLastError( ERROR_FILENAME_EXCED_RANGE );
312 return 0;
314 SERVER_START_REQ( create_desktop )
316 req->flags = flags;
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 );
324 SERVER_END_REQ;
325 return ret;
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 );
341 return 0;
343 return OpenDesktopW( buffer, flags, inherit, access );
347 HDESK open_winstation_desktop( HWINSTA hwinsta, LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
349 HANDLE ret = 0;
350 DWORD len = name ? strlenW(name) : 0;
351 if (len >= MAX_PATH)
353 SetLastError( ERROR_FILENAME_EXCED_RANGE );
354 return 0;
356 SERVER_START_REQ( open_desktop )
358 req->winsta = wine_server_obj_handle( hwinsta );
359 req->flags = flags;
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 );
365 SERVER_END_REQ;
366 return ret;
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 )
384 BOOL ret;
385 SERVER_START_REQ( close_desktop )
387 req->handle = wine_server_obj_handle( handle );
388 ret = !wine_server_call_err( req );
390 SERVER_END_REQ;
391 return ret;
395 /******************************************************************************
396 * GetThreadDesktop (USER32.@)
398 HDESK WINAPI GetThreadDesktop( DWORD thread )
400 HDESK ret = 0;
402 SERVER_START_REQ( get_thread_desktop )
404 req->tid = thread;
405 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
407 SERVER_END_REQ;
408 return ret;
412 /******************************************************************************
413 * SetThreadDesktop (USER32.@)
415 BOOL WINAPI SetThreadDesktop( HDESK handle )
417 BOOL ret;
419 SERVER_START_REQ( set_thread_desktop )
421 req->handle = wine_server_obj_handle( handle );
422 ret = !wine_server_call_err( req );
424 SERVER_END_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;
433 return ret;
437 /******************************************************************************
438 * EnumDesktopsA (USER32.@)
440 BOOL WINAPI EnumDesktopsA( HWINSTA winsta, DESKTOPENUMPROCA func, LPARAM lparam )
442 struct enum_proc_lparam data;
443 data.func = func;
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];
456 BOOL ret = TRUE;
457 NTSTATUS status;
459 if (!winsta)
460 winsta = GetProcessWindowStation();
462 while (ret)
464 SERVER_START_REQ( enum_desktop )
466 req->winstation = wine_server_obj_handle( winsta );
467 req->index = index;
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;
471 index = reply->next;
473 SERVER_END_REQ;
474 if (status == STATUS_NO_MORE_ENTRIES)
475 break;
476 if (status)
478 SetLastError( RtlNtStatusToDosError( status ) );
479 return FALSE;
481 ret = func(name, lparam);
483 return ret;
487 /******************************************************************************
488 * OpenInputDesktop (USER32.@)
490 HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
492 HANDLE ret = 0;
494 TRACE( "(%x,%i,%x)\n", flags, inherit, access );
496 if (flags)
497 FIXME( "partial stub flags %08x\n", flags );
499 SERVER_START_REQ( open_input_desktop )
501 req->flags = flags;
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 );
506 SERVER_END_REQ;
508 return ret;
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];
521 DWORD lenA, lenW;
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;
526 if (lenA > len)
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 );
533 return FALSE;
535 if (info) WideCharToMultiByte( CP_ACP, 0, buffer, -1, info, len, NULL, NULL );
536 return TRUE;
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 };
549 BOOL ret;
551 switch(index)
553 case UOI_FLAGS:
555 USEROBJECTFLAGS *obj_flags = info;
556 if (needed) *needed = sizeof(*obj_flags);
557 if (len < sizeof(*obj_flags))
559 SetLastError( ERROR_BUFFER_OVERFLOW );
560 return FALSE;
562 SERVER_START_REQ( set_user_object_info )
564 req->handle = wine_server_obj_handle( handle );
565 req->flags = 0;
566 ret = !wine_server_call_err( req );
567 if (ret)
569 /* FIXME: inherit flag */
570 obj_flags->dwFlags = reply->old_obj_flags;
573 SERVER_END_REQ;
575 return ret;
577 case UOI_TYPE:
578 SERVER_START_REQ( set_user_object_info )
580 req->handle = wine_server_obj_handle( handle );
581 req->flags = 0;
582 ret = !wine_server_call_err( req );
583 if (ret)
585 size_t size = reply->is_desktop ? sizeof(desktopW) : sizeof(winstationW);
586 if (needed) *needed = size;
587 if (len < size)
589 SetLastError( ERROR_INSUFFICIENT_BUFFER );
590 ret = FALSE;
592 else memcpy( info, reply->is_desktop ? desktopW : winstationW, size );
595 SERVER_END_REQ;
596 return ret;
598 case UOI_NAME:
600 WCHAR buffer[MAX_PATH];
601 SERVER_START_REQ( set_user_object_info )
603 req->handle = wine_server_obj_handle( handle );
604 req->flags = 0;
605 wine_server_set_reply( req, buffer, sizeof(buffer) - sizeof(WCHAR) );
606 ret = !wine_server_call_err( req );
607 if (ret)
609 size_t size = wine_server_reply_size( reply );
610 buffer[size / sizeof(WCHAR)] = 0;
611 size += sizeof(WCHAR);
612 if (needed) *needed = size;
613 if (len < size)
615 SetLastError( ERROR_INSUFFICIENT_BUFFER );
616 ret = FALSE;
618 else memcpy( info, buffer, size );
621 SERVER_END_REQ;
623 return ret;
625 case UOI_USER_SID:
626 FIXME( "not supported index %d\n", index );
627 /* fall through */
628 default:
629 SetLastError( ERROR_INVALID_PARAMETER );
630 return FALSE;
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 )
649 BOOL ret;
650 const USEROBJECTFLAGS *obj_flags = info;
652 if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags))
654 SetLastError( ERROR_INVALID_PARAMETER );
655 return FALSE;
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 );
665 SERVER_END_REQ;
666 return ret;
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 );
677 if (needed)
678 *needed = sizeof(SECURITY_DESCRIPTOR);
679 if (len < sizeof(SECURITY_DESCRIPTOR))
681 SetLastError( ERROR_INSUFFICIENT_BUFFER );
682 return FALSE;
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 );
694 return TRUE;