mlang/tests: Skip tests for unsupported code page identifiers.
[wine] / dlls / user32 / winstation.c
1 /*
2  * Window stations and desktops
3  *
4  * Copyright 2002 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "ntstatus.h"
22 #define WIN32_NO_STATUS
23
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 "wine/server.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "user_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(winstation);
37
38
39 /* callback for enumeration functions */
40 struct enum_proc_lparam
41 {
42     NAMEENUMPROCA func;
43     LPARAM        lparam;
44 };
45
46 static BOOL CALLBACK enum_names_WtoA( LPWSTR name, LPARAM lparam )
47 {
48     struct enum_proc_lparam *data = (struct enum_proc_lparam *)lparam;
49     char buffer[MAX_PATH];
50
51     if (!WideCharToMultiByte( CP_ACP, 0, name, -1, buffer, sizeof(buffer), NULL, NULL ))
52         return FALSE;
53     return data->func( buffer, data->lparam );
54 }
55
56
57 /***********************************************************************
58  *              CreateWindowStationA  (USER32.@)
59  */
60 HWINSTA WINAPI CreateWindowStationA( LPCSTR name, DWORD reserved, ACCESS_MASK access,
61                                      LPSECURITY_ATTRIBUTES sa )
62 {
63     WCHAR buffer[MAX_PATH];
64
65     if (!name) return CreateWindowStationW( NULL, reserved, access, sa );
66
67     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
68     {
69         SetLastError( ERROR_FILENAME_EXCED_RANGE );
70         return 0;
71     }
72     return CreateWindowStationW( buffer, reserved, access, sa );
73 }
74
75
76 /***********************************************************************
77  *              CreateWindowStationW  (USER32.@)
78  */
79 HWINSTA WINAPI CreateWindowStationW( LPCWSTR name, DWORD reserved, ACCESS_MASK access,
80                                      LPSECURITY_ATTRIBUTES sa )
81 {
82     HANDLE ret;
83     DWORD len = name ? strlenW(name) : 0;
84
85     if (len >= MAX_PATH)
86     {
87         SetLastError( ERROR_FILENAME_EXCED_RANGE );
88         return 0;
89     }
90     SERVER_START_REQ( create_winstation )
91     {
92         req->flags      = 0;
93         req->access     = access;
94         req->attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
95                           ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
96         wine_server_add_data( req, name, len * sizeof(WCHAR) );
97         /* it doesn't seem to set last error */
98         wine_server_call( req );
99         ret = reply->handle;
100     }
101     SERVER_END_REQ;
102     return ret;
103 }
104
105
106 /******************************************************************************
107  *              OpenWindowStationA  (USER32.@)
108  */
109 HWINSTA WINAPI OpenWindowStationA( LPCSTR name, BOOL inherit, ACCESS_MASK access )
110 {
111     WCHAR buffer[MAX_PATH];
112
113     if (!name) return OpenWindowStationW( NULL, inherit, access );
114
115     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
116     {
117         SetLastError( ERROR_FILENAME_EXCED_RANGE );
118         return 0;
119     }
120     return OpenWindowStationW( buffer, inherit, access );
121 }
122
123
124 /******************************************************************************
125  *              OpenWindowStationW  (USER32.@)
126  */
127 HWINSTA WINAPI OpenWindowStationW( LPCWSTR name, BOOL inherit, ACCESS_MASK access )
128 {
129     HANDLE ret = 0;
130     DWORD len = name ? strlenW(name) : 0;
131     if (len >= MAX_PATH)
132     {
133         SetLastError( ERROR_FILENAME_EXCED_RANGE );
134         return 0;
135     }
136     SERVER_START_REQ( open_winstation )
137     {
138         req->access     = access;
139         req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
140         wine_server_add_data( req, name, len * sizeof(WCHAR) );
141         if (!wine_server_call_err( req )) ret = reply->handle;
142     }
143     SERVER_END_REQ;
144     return ret;
145 }
146
147
148 /***********************************************************************
149  *              CloseWindowStation  (USER32.@)
150  */
151 BOOL WINAPI CloseWindowStation( HWINSTA handle )
152 {
153     BOOL ret;
154     SERVER_START_REQ( close_winstation )
155     {
156         req->handle = handle;
157         ret = !wine_server_call_err( req );
158     }
159     SERVER_END_REQ;
160     return ret;
161 }
162
163
164 /******************************************************************************
165  *              GetProcessWindowStation  (USER32.@)
166  */
167 HWINSTA WINAPI GetProcessWindowStation(void)
168 {
169     HWINSTA ret = 0;
170
171     SERVER_START_REQ( get_process_winstation )
172     {
173         if (!wine_server_call_err( req )) ret = reply->handle;
174     }
175     SERVER_END_REQ;
176     return ret;
177 }
178
179
180 /***********************************************************************
181  *              SetProcessWindowStation  (USER32.@)
182  */
183 BOOL WINAPI SetProcessWindowStation( HWINSTA handle )
184 {
185     BOOL ret;
186
187     SERVER_START_REQ( set_process_winstation )
188     {
189         req->handle = handle;
190         ret = !wine_server_call_err( req );
191     }
192     SERVER_END_REQ;
193     return ret;
194 }
195
196
197 /******************************************************************************
198  *              EnumWindowStationsA  (USER32.@)
199  */
200 BOOL WINAPI EnumWindowStationsA( WINSTAENUMPROCA func, LPARAM lparam )
201 {
202     struct enum_proc_lparam data;
203     data.func   = func;
204     data.lparam = lparam;
205     return EnumWindowStationsW( enum_names_WtoA, (LPARAM)&data );
206 }
207
208
209 /******************************************************************************
210  *              EnumWindowStationsW  (USER32.@)
211  */
212 BOOL WINAPI EnumWindowStationsW( WINSTAENUMPROCW func, LPARAM lparam )
213 {
214     unsigned int index = 0;
215     WCHAR name[MAX_PATH];
216     BOOL ret = TRUE;
217     NTSTATUS status;
218
219     while (ret)
220     {
221         SERVER_START_REQ( enum_winstation )
222         {
223             req->index = index;
224             wine_server_set_reply( req, name, sizeof(name) - sizeof(WCHAR) );
225             status = wine_server_call( req );
226             name[wine_server_reply_size(reply)/sizeof(WCHAR)] = 0;
227             index = reply->next;
228         }
229         SERVER_END_REQ;
230         if (status == STATUS_NO_MORE_ENTRIES)
231             break;
232         if (status)
233         {
234             SetLastError( RtlNtStatusToDosError( status ) );
235             return FALSE;
236         }
237         ret = func( name, lparam );
238     }
239     return ret;
240 }
241
242
243 /***********************************************************************
244  *              CreateDesktopA   (USER32.@)
245  */
246 HDESK WINAPI CreateDesktopA( LPCSTR name, LPCSTR device, LPDEVMODEA devmode,
247                              DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa )
248 {
249     WCHAR buffer[MAX_PATH];
250
251     if (device || devmode)
252     {
253         SetLastError( ERROR_INVALID_PARAMETER );
254         return 0;
255     }
256     if (!name) return CreateDesktopW( NULL, NULL, NULL, flags, access, sa );
257
258     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
259     {
260         SetLastError( ERROR_FILENAME_EXCED_RANGE );
261         return 0;
262     }
263     return CreateDesktopW( buffer, NULL, NULL, flags, access, sa );
264 }
265
266
267 /***********************************************************************
268  *              CreateDesktopW   (USER32.@)
269  */
270 HDESK WINAPI CreateDesktopW( LPCWSTR name, LPCWSTR device, LPDEVMODEW devmode,
271                              DWORD flags, ACCESS_MASK access, LPSECURITY_ATTRIBUTES sa )
272 {
273     HANDLE ret;
274     DWORD len = name ? strlenW(name) : 0;
275
276     if (device || devmode)
277     {
278         SetLastError( ERROR_INVALID_PARAMETER );
279         return 0;
280     }
281     if (len >= MAX_PATH)
282     {
283         SetLastError( ERROR_FILENAME_EXCED_RANGE );
284         return 0;
285     }
286     SERVER_START_REQ( create_desktop )
287     {
288         req->flags      = flags;
289         req->access     = access;
290         req->attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF |
291                           ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0);
292         wine_server_add_data( req, name, len * sizeof(WCHAR) );
293         /* it doesn't seem to set last error */
294         wine_server_call( req );
295         ret = reply->handle;
296     }
297     SERVER_END_REQ;
298     return ret;
299 }
300
301
302 /******************************************************************************
303  *              OpenDesktopA   (USER32.@)
304  */
305 HDESK WINAPI OpenDesktopA( LPCSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
306 {
307     WCHAR buffer[MAX_PATH];
308
309     if (!name) return OpenDesktopW( NULL, flags, inherit, access );
310
311     if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
312     {
313         SetLastError( ERROR_FILENAME_EXCED_RANGE );
314         return 0;
315     }
316     return OpenDesktopW( buffer, flags, inherit, access );
317 }
318
319
320 HDESK open_winstation_desktop( HWINSTA hwinsta, LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
321 {
322     HANDLE ret = 0;
323     DWORD len = name ? strlenW(name) : 0;
324     if (len >= MAX_PATH)
325     {
326         SetLastError( ERROR_FILENAME_EXCED_RANGE );
327         return 0;
328     }
329     SERVER_START_REQ( open_desktop )
330     {
331         req->winsta     = hwinsta;
332         req->flags      = flags;
333         req->access     = access;
334         req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0);
335         wine_server_add_data( req, name, len * sizeof(WCHAR) );
336         if (!wine_server_call( req )) ret = reply->handle;
337     }
338     SERVER_END_REQ;
339     return ret;
340 }
341
342
343 /******************************************************************************
344  *              OpenDesktopW   (USER32.@)
345  */
346 HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access )
347 {
348     return open_winstation_desktop( NULL, name, flags, inherit, access );
349 }
350
351
352 /***********************************************************************
353  *              CloseDesktop  (USER32.@)
354  */
355 BOOL WINAPI CloseDesktop( HDESK handle )
356 {
357     BOOL ret;
358     SERVER_START_REQ( close_desktop )
359     {
360         req->handle = handle;
361         ret = !wine_server_call_err( req );
362     }
363     SERVER_END_REQ;
364     return ret;
365 }
366
367
368 /******************************************************************************
369  *              GetThreadDesktop   (USER32.@)
370  */
371 HDESK WINAPI GetThreadDesktop( DWORD thread )
372 {
373     HDESK ret = 0;
374
375     SERVER_START_REQ( get_thread_desktop )
376     {
377         req->tid = thread;
378         if (!wine_server_call_err( req )) ret = reply->handle;
379     }
380     SERVER_END_REQ;
381     return ret;
382 }
383
384
385 /******************************************************************************
386  *              SetThreadDesktop   (USER32.@)
387  */
388 BOOL WINAPI SetThreadDesktop( HDESK handle )
389 {
390     BOOL ret;
391
392     SERVER_START_REQ( set_thread_desktop )
393     {
394         req->handle = handle;
395         ret = !wine_server_call_err( req );
396     }
397     SERVER_END_REQ;
398     if (ret)  /* reset the desktop windows */
399     {
400         struct user_thread_info *thread_info = get_user_thread_info();
401         thread_info->top_window = 0;
402         thread_info->msg_window = 0;
403     }
404     return ret;
405 }
406
407
408 /******************************************************************************
409  *              EnumDesktopsA   (USER32.@)
410  */
411 BOOL WINAPI EnumDesktopsA( HWINSTA winsta, DESKTOPENUMPROCA func, LPARAM lparam )
412 {
413     struct enum_proc_lparam data;
414     data.func   = func;
415     data.lparam = lparam;
416     return EnumDesktopsW( winsta, enum_names_WtoA, (LPARAM)&data );
417 }
418
419
420 /******************************************************************************
421  *              EnumDesktopsW   (USER32.@)
422  */
423 BOOL WINAPI EnumDesktopsW( HWINSTA winsta, DESKTOPENUMPROCW func, LPARAM lparam )
424 {
425     unsigned int index = 0;
426     WCHAR name[MAX_PATH];
427     BOOL ret = TRUE;
428     NTSTATUS status;
429
430     if (!winsta)
431         winsta = GetProcessWindowStation();
432
433     while (ret)
434     {
435         SERVER_START_REQ( enum_desktop )
436         {
437             req->winstation = winsta;
438             req->index      = index;
439             wine_server_set_reply( req, name, sizeof(name) - sizeof(WCHAR) );
440             status = wine_server_call( req );
441             name[wine_server_reply_size(reply)/sizeof(WCHAR)] = 0;
442             index = reply->next;
443         }
444         SERVER_END_REQ;
445         if (status == STATUS_NO_MORE_ENTRIES)
446             break;
447         if (status)
448         {
449             SetLastError( RtlNtStatusToDosError( status ) );
450             return FALSE;
451         }
452         ret = func(name, lparam);
453     }
454     return ret;
455 }
456
457
458 /******************************************************************************
459  *              OpenInputDesktop   (USER32.@)
460  */
461 HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
462 {
463     FIXME( "(%x,%i,%x): stub\n", flags, inherit, access );
464     SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
465     return 0;
466 }
467
468
469 /***********************************************************************
470  *              GetUserObjectInformationA   (USER32.@)
471  */
472 BOOL WINAPI GetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed )
473 {
474     /* check for information types returning strings */
475     if (index == UOI_TYPE || index == UOI_NAME)
476     {
477         WCHAR buffer[MAX_PATH];
478         DWORD lenA;
479
480         if (!GetUserObjectInformationW( handle, index, buffer, sizeof(buffer), NULL )) return FALSE;
481         lenA = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
482         if (needed) *needed = lenA;
483         if (lenA > len)
484         {
485             SetLastError( ERROR_MORE_DATA );
486             return FALSE;
487         }
488         if (info) WideCharToMultiByte( CP_ACP, 0, buffer, -1, info, len, NULL, NULL );
489         return TRUE;
490     }
491     return GetUserObjectInformationW( handle, index, info, len, needed );
492 }
493
494
495 /***********************************************************************
496  *              GetUserObjectInformationW   (USER32.@)
497  */
498 BOOL WINAPI GetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len, LPDWORD needed )
499 {
500     static const WCHAR desktopW[] = { 'D','e','s','k','t','o','p',0 };
501     static const WCHAR winstationW[] = { 'W','i','n','d','o','w','S','t','a','t','i','o','n',0 };
502     BOOL ret;
503
504     switch(index)
505     {
506     case UOI_FLAGS:
507         {
508             USEROBJECTFLAGS *obj_flags = info;
509             if (needed) *needed = sizeof(*obj_flags);
510             if (len < sizeof(*obj_flags))
511             {
512                 SetLastError( ERROR_BUFFER_OVERFLOW );
513                 return FALSE;
514             }
515             SERVER_START_REQ( set_user_object_info )
516             {
517                 req->handle    = handle;
518                 req->flags     = 0;
519                 ret = !wine_server_call_err( req );
520                 if (ret)
521                 {
522                     /* FIXME: inherit flag */
523                     obj_flags->dwFlags = reply->old_obj_flags;
524                 }
525             }
526             SERVER_END_REQ;
527         }
528         return ret;
529
530     case UOI_TYPE:
531         SERVER_START_REQ( set_user_object_info )
532         {
533             req->handle = handle;
534             req->flags  = 0;
535             ret = !wine_server_call_err( req );
536             if (ret)
537             {
538                 size_t size = reply->is_desktop ? sizeof(desktopW) : sizeof(winstationW);
539                 if (needed) *needed = size;
540                 if (len < size)
541                 {
542                     SetLastError( ERROR_MORE_DATA );
543                     ret = FALSE;
544                 }
545                 else memcpy( info, reply->is_desktop ? desktopW : winstationW, size );
546             }
547         }
548         SERVER_END_REQ;
549         return ret;
550
551     case UOI_NAME:
552         {
553             WCHAR buffer[MAX_PATH];
554             SERVER_START_REQ( set_user_object_info )
555             {
556                 req->handle = handle;
557                 req->flags  = 0;
558                 wine_server_set_reply( req, buffer, sizeof(buffer) - sizeof(WCHAR) );
559                 ret = !wine_server_call_err( req );
560                 if (ret)
561                 {
562                     size_t size = wine_server_reply_size( reply );
563                     buffer[size / sizeof(WCHAR)] = 0;
564                     size += sizeof(WCHAR);
565                     if (needed) *needed = size;
566                     if (len < size)
567                     {
568                         SetLastError( ERROR_MORE_DATA );
569                         ret = FALSE;
570                     }
571                     else memcpy( info, buffer, size );
572                 }
573             }
574             SERVER_END_REQ;
575         }
576         return ret;
577
578     case UOI_USER_SID:
579         FIXME( "not supported index %d\n", index );
580         /* fall through */
581     default:
582         SetLastError( ERROR_INVALID_PARAMETER );
583         return FALSE;
584     }
585 }
586
587
588 /******************************************************************************
589  *              SetUserObjectInformationA   (USER32.@)
590  */
591 BOOL WINAPI SetUserObjectInformationA( HANDLE handle, INT index, LPVOID info, DWORD len )
592 {
593     return SetUserObjectInformationW( handle, index, info, len );
594 }
595
596
597 /******************************************************************************
598  *              SetUserObjectInformationW   (USER32.@)
599  */
600 BOOL WINAPI SetUserObjectInformationW( HANDLE handle, INT index, LPVOID info, DWORD len )
601 {
602     BOOL ret;
603     const USEROBJECTFLAGS *obj_flags = info;
604
605     if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags))
606     {
607         SetLastError( ERROR_INVALID_PARAMETER );
608         return FALSE;
609     }
610     /* FIXME: inherit flag */
611     SERVER_START_REQ( set_user_object_info )
612     {
613         req->handle    = handle;
614         req->flags     = SET_USER_OBJECT_FLAGS;
615         req->obj_flags = obj_flags->dwFlags;
616         ret = !wine_server_call_err( req );
617     }
618     SERVER_END_REQ;
619     return ret;
620 }
621
622
623 /***********************************************************************
624  *              GetUserObjectSecurity   (USER32.@)
625  */
626 BOOL WINAPI GetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info,
627                                    PSECURITY_DESCRIPTOR sid, DWORD len, LPDWORD needed )
628 {
629     FIXME( "(%p %p %p len=%d %p),stub!\n", handle, info, sid, len, needed );
630     return TRUE;
631 }
632
633 /***********************************************************************
634  *              SetUserObjectSecurity   (USER32.@)
635  */
636 BOOL WINAPI SetUserObjectSecurity( HANDLE handle, PSECURITY_INFORMATION info,
637                                    PSECURITY_DESCRIPTOR sid )
638 {
639     FIXME( "(%p,%p,%p),stub!\n", handle, info, sid );
640     return TRUE;
641 }