Remove LOCAL_*() calls from USER, use Local*16() instead.
[wine] / windows / user.c
1 /*
2  * Misc. USER functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  *           1996 Alex Korobka
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "wine/winbase16.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "wine/winuser16.h"
31 #include "winreg.h"
32 #include "winternl.h"
33 #include "tlhelp32.h"
34 #include "user_private.h"
35 #include "win.h"
36 #include "controls.h"
37 #include "cursoricon.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(user);
41
42 /* USER signal proc flags and codes */
43 /* See UserSignalProc for comments */
44 #define USIG_FLAGS_WIN32          0x0001
45 #define USIG_FLAGS_GUI            0x0002
46 #define USIG_FLAGS_FEEDBACK       0x0004
47 #define USIG_FLAGS_FAULT          0x0008
48
49 #define USIG_DLL_UNLOAD_WIN16     0x0001
50 #define USIG_DLL_UNLOAD_WIN32     0x0002
51 #define USIG_FAULT_DIALOG_PUSH    0x0003
52 #define USIG_FAULT_DIALOG_POP     0x0004
53 #define USIG_DLL_UNLOAD_ORPHANS   0x0005
54 #define USIG_THREAD_INIT          0x0010
55 #define USIG_THREAD_EXIT          0x0020
56 #define USIG_PROCESS_CREATE       0x0100
57 #define USIG_PROCESS_INIT         0x0200
58 #define USIG_PROCESS_EXIT         0x0300
59 #define USIG_PROCESS_DESTROY      0x0400
60 #define USIG_PROCESS_RUNNING      0x0500
61 #define USIG_PROCESS_LOADED       0x0600
62
63 /* UserSeeUserDo parameters */
64 #define USUD_LOCALALLOC        0x0001
65 #define USUD_LOCALFREE         0x0002
66 #define USUD_LOCALCOMPACT      0x0003
67 #define USUD_LOCALHEAP         0x0004
68 #define USUD_FIRSTCLASS        0x0005
69
70 /***********************************************************************
71  *              GetFreeSystemResources (USER.284)
72  */
73 WORD WINAPI GetFreeSystemResources16( WORD resType )
74 {
75     STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
76     HANDLE16 oldDS = stack16->ds;
77     HINSTANCE16 gdi_inst;
78     WORD gdi_heap;
79     int userPercent, gdiPercent;
80
81     if ((gdi_inst = LoadLibrary16( "GDI" )) < 32) return 0;
82     gdi_heap = gdi_inst | 7;
83
84     switch(resType)
85     {
86     case GFSR_USERRESOURCES:
87         stack16->ds = USER_HeapSel;
88         userPercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
89         gdiPercent  = 100;
90         stack16->ds = oldDS;
91         break;
92
93     case GFSR_GDIRESOURCES:
94         stack16->ds = gdi_inst;
95         gdiPercent  = (int)LocalCountFree16() * 100 / LocalHeapSize16();
96         userPercent = 100;
97         stack16->ds = oldDS;
98         break;
99
100     case GFSR_SYSTEMRESOURCES:
101         stack16->ds = USER_HeapSel;
102         userPercent = (int)LocalCountFree16() * 100 / LocalHeapSize16();
103         stack16->ds = gdi_inst;
104         gdiPercent  = (int)LocalCountFree16() * 100 / LocalHeapSize16();
105         stack16->ds = oldDS;
106         break;
107
108     default:
109         userPercent = gdiPercent = 0;
110         break;
111     }
112     FreeLibrary16( gdi_inst );
113     TRACE("<- userPercent %d, gdiPercent %d\n", userPercent, gdiPercent);
114     return (WORD)min( userPercent, gdiPercent );
115 }
116
117
118 /***********************************************************************
119  *              SignalProc32 (USER.391)
120  *              UserSignalProc (USER32.@)
121  *
122  * The exact meaning of the USER signals is undocumented, but this
123  * should cover the basic idea:
124  *
125  * USIG_DLL_UNLOAD_WIN16
126  *     This is sent when a 16-bit module is unloaded.
127  *
128  * USIG_DLL_UNLOAD_WIN32
129  *     This is sent when a 32-bit module is unloaded.
130  *
131  * USIG_DLL_UNLOAD_ORPHANS
132  *     This is sent after the last Win3.1 module is unloaded,
133  *     to allow removal of orphaned menus.
134  *
135  * USIG_FAULT_DIALOG_PUSH
136  * USIG_FAULT_DIALOG_POP
137  *     These are called to allow USER to prepare for displaying a
138  *     fault dialog, even though the fault might have happened while
139  *     inside a USER critical section.
140  *
141  * USIG_THREAD_INIT
142  *     This is called from the context of a new thread, as soon as it
143  *     has started to run.
144  *
145  * USIG_THREAD_EXIT
146  *     This is called, still in its context, just before a thread is
147  *     about to terminate.
148  *
149  * USIG_PROCESS_CREATE
150  *     This is called, in the parent process context, after a new process
151  *     has been created.
152  *
153  * USIG_PROCESS_INIT
154  *     This is called in the new process context, just after the main thread
155  *     has started execution (after the main thread's USIG_THREAD_INIT has
156  *     been sent).
157  *
158  * USIG_PROCESS_LOADED
159  *     This is called after the executable file has been loaded into the
160  *     new process context.
161  *
162  * USIG_PROCESS_RUNNING
163  *     This is called immediately before the main entry point is called.
164  *
165  * USIG_PROCESS_EXIT
166  *     This is called in the context of a process that is about to
167  *     terminate (but before the last thread's USIG_THREAD_EXIT has
168  *     been sent).
169  *
170  * USIG_PROCESS_DESTROY
171  *     This is called after a process has terminated.
172  *
173  *
174  * The meaning of the dwFlags bits is as follows:
175  *
176  * USIG_FLAGS_WIN32
177  *     Current process is 32-bit.
178  *
179  * USIG_FLAGS_GUI
180  *     Current process is a (Win32) GUI process.
181  *
182  * USIG_FLAGS_FEEDBACK
183  *     Current process needs 'feedback' (determined from the STARTUPINFO
184  *     flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
185  *
186  * USIG_FLAGS_FAULT
187  *     The signal is being sent due to a fault.
188  */
189 WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
190                             DWORD dwFlags, HMODULE16 hModule )
191 {
192     FIXME("(%04x, %08lx, %04lx, %04x)\n",
193           uCode, dwThreadOrProcessID, dwFlags, hModule );
194     /* FIXME: Should chain to GdiSignalProc now. */
195     return 0;
196 }
197
198 /***********************************************************************
199  *           USER_GetProcessHandleList(Internal)
200  */
201 static HANDLE *USER_GetProcessHandleList(void)
202 {
203     DWORD count, i, n;
204     HANDLE *list;
205     PROCESSENTRY32 pe;
206     HANDLE hSnapshot;
207     BOOL r;
208
209     hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
210     if (!hSnapshot)
211     {
212         ERR("cannot create snapshot\n");
213         return FALSE;
214     }
215
216     /* count the number of processes plus one */
217     for (count=0; ;count++)
218     {
219         pe.dwSize = sizeof pe;
220         if (count)
221             r = Process32Next( hSnapshot, &pe );
222         else
223             r = Process32First( hSnapshot, &pe );
224         if (!r)
225             break;
226     }
227
228     /* allocate memory make a list of the process handles */
229     list = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof(HANDLE) );
230     n=0;
231     for (i=0; i<count; i++)
232     {
233         pe.dwSize = sizeof pe;
234         if (i)
235             r = Process32Next( hSnapshot, &pe );
236         else
237             r = Process32First( hSnapshot, &pe );
238         if (!r)
239             break;
240
241         /* don't kill ourselves */
242         if (GetCurrentProcessId() == pe.th32ProcessID )
243             continue;
244
245         /* open the process so we don't can track it */
246         list[n] = OpenProcess( PROCESS_QUERY_INFORMATION|
247                                   PROCESS_TERMINATE,
248                                   FALSE, pe.th32ProcessID );
249
250         /* check it didn't terminate already */
251         if( list[n] )
252             n++;
253     }
254     list[n]=0;
255     CloseHandle( hSnapshot );
256
257     if (!r)
258         ERR("Error enumerating processes\n");
259
260     TRACE("return %lu processes\n", n);
261
262     return list;
263 }
264
265 /***********************************************************************
266  *              USER_KillProcesses (Internal)
267  */
268 static DWORD USER_KillProcesses(void)
269 {
270     DWORD n, r, i;
271     HANDLE *handles;
272     const DWORD dwShutdownTimeout = 10000;
273
274     TRACE("terminating other processes\n");
275
276     /* kill it and add it to our list of object to wait on */
277     handles = USER_GetProcessHandleList();
278     for (n=0; handles && handles[n]; n++)
279         TerminateProcess( handles[n], 0 );
280
281     /* wait for processes to exit */
282     for (i=0; i<n; i+=MAXIMUM_WAIT_OBJECTS)
283     {
284         int n_objs = ((n-i)>MAXIMUM_WAIT_OBJECTS) ? MAXIMUM_WAIT_OBJECTS : (n-i);
285         r = WaitForMultipleObjects( n_objs, &handles[i], TRUE, dwShutdownTimeout );
286         if (r==WAIT_TIMEOUT)
287             ERR("wait failed!\n");
288     }
289     
290     /* close the handles */
291     for (i=0; i<n; i++)
292         CloseHandle( handles[i] );
293
294     HeapFree( GetProcessHeap(), 0, handles );
295
296     return n;
297 }
298  
299 /***********************************************************************
300  *              USER_DoShutdown (Internal)
301  */
302 static void USER_DoShutdown(void)
303 {
304     DWORD i, n;
305     const DWORD nRetries = 10;
306
307     for (i=0; i<nRetries; i++)
308     {
309         n = USER_KillProcesses();
310         TRACE("Killed %ld processes, attempt %ld\n", n, i);
311         if(!n)
312             break;
313     }
314 }
315  
316 /***********************************************************************
317  *              USER_StartRebootProcess (Internal)
318  */
319 static BOOL USER_StartRebootProcess(void)
320 {
321     WCHAR winebootW[] = { 'w','i','n','e','b','o','o','t',0 };
322     PROCESS_INFORMATION pi;
323     STARTUPINFOW si;
324     BOOL r;
325
326     memset( &si, 0, sizeof si );
327     si.cb = sizeof si;
328
329     r = CreateProcessW( NULL, winebootW, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
330     if (r)
331     {
332         CloseHandle( pi.hProcess );
333         CloseHandle( pi.hThread );
334     }
335     else
336         MESSAGE("wine: Failed to start wineboot\n");
337
338     return r;
339 }
340
341 /***********************************************************************
342  *              ExitWindowsEx (USER32.@)
343  */
344 BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reserved )
345 {
346     int i;
347     BOOL result = FALSE;
348     HWND *list, *phwnd;
349
350     /* We have to build a list of all windows first, as in EnumWindows */
351     TRACE("(%x,%lx)\n", flags, reserved);
352
353     list = WIN_ListChildren( GetDesktopWindow() );
354     if (list)
355     {
356         /* Send a WM_QUERYENDSESSION message to every window */
357
358         for (i = 0; list[i]; i++)
359         {
360             /* Make sure that the window still exists */
361             if (!IsWindow( list[i] )) continue;
362             if (!SendMessageW( list[i], WM_QUERYENDSESSION, 0, 0 )) break;
363         }
364         result = !list[i];
365
366         /* Now notify all windows that got a WM_QUERYENDSESSION of the result */
367
368         for (phwnd = list; i > 0; i--, phwnd++)
369         {
370             if (!IsWindow( *phwnd )) continue;
371             SendMessageW( *phwnd, WM_ENDSESSION, result, 0 );
372         }
373         HeapFree( GetProcessHeap(), 0, list );
374
375         if ( !(result || (flags & EWX_FORCE) ))
376             return FALSE;
377     }
378
379     /* USER_DoShutdown will kill all processes except the current process */
380     USER_DoShutdown();
381
382     if (flags & EWX_REBOOT)
383         USER_StartRebootProcess();
384
385     if (result) ExitProcess(0);
386     return TRUE;
387 }
388
389 /***********************************************************************
390  *              ChangeDisplaySettingsA (USER32.@)
391  */
392 LONG WINAPI ChangeDisplaySettingsA( LPDEVMODEA devmode, DWORD flags )
393 {
394   return ChangeDisplaySettingsExA(NULL,devmode,NULL,flags,NULL);
395 }
396
397 /***********************************************************************
398  *              ChangeDisplaySettingsW (USER32.@)
399  */
400 LONG WINAPI ChangeDisplaySettingsW( LPDEVMODEW devmode, DWORD flags )
401 {
402   return ChangeDisplaySettingsExW(NULL,devmode,NULL,flags,NULL);
403 }
404
405 /***********************************************************************
406  *              ChangeDisplaySettingsExA (USER32.@)
407  */
408 LONG WINAPI ChangeDisplaySettingsExA(
409         LPCSTR devname, LPDEVMODEA devmode, HWND hwnd, DWORD flags,
410         LPVOID lparam
411 ) {
412     DEVMODEW devmodeW;
413     LONG ret;
414     UNICODE_STRING nameW;
415
416     if (devname) RtlCreateUnicodeStringFromAsciiz(&nameW, devname);
417     else nameW.Buffer = NULL;
418
419     if (devmode)
420     {
421         devmodeW.dmBitsPerPel       = devmode->dmBitsPerPel;
422         devmodeW.dmPelsHeight       = devmode->dmPelsHeight;
423         devmodeW.dmPelsWidth        = devmode->dmPelsWidth;
424         devmodeW.dmDisplayFlags     = devmode->dmDisplayFlags;
425         devmodeW.dmDisplayFrequency = devmode->dmDisplayFrequency;
426         devmodeW.dmFields           = devmode->dmFields;
427         ret = ChangeDisplaySettingsExW(nameW.Buffer, &devmodeW, hwnd, flags, lparam);
428     }
429     else
430     {
431         ret = ChangeDisplaySettingsExW(nameW.Buffer, NULL, hwnd, flags, lparam);
432     }
433
434     if (devname) RtlFreeUnicodeString(&nameW);
435     return ret;
436 }
437
438 /***********************************************************************
439  *              ChangeDisplaySettingsExW (USER32.@)
440  */
441 LONG WINAPI ChangeDisplaySettingsExW( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd,
442                                       DWORD flags, LPVOID lparam )
443 {
444     /* Pass the request on to the driver */
445     if (!USER_Driver.pChangeDisplaySettingsExW) return DISP_CHANGE_FAILED;
446     return USER_Driver.pChangeDisplaySettingsExW( devname, devmode, hwnd, flags, lparam );
447 }
448
449 /***********************************************************************
450  *              EnumDisplaySettingsW (USER32.@)
451  *
452  * RETURNS
453  *      TRUE if nth setting exists found (described in the LPDEVMODEW struct)
454  *      FALSE if we do not have the nth setting
455  */
456 BOOL WINAPI EnumDisplaySettingsW(
457         LPCWSTR name,           /* [in] huh? */
458         DWORD n,                /* [in] nth entry in display settings list*/
459         LPDEVMODEW devmode      /* [out] devmode for that setting */
460 ) {
461     return EnumDisplaySettingsExW(name, n, devmode, 0);
462 }
463
464 /***********************************************************************
465  *              EnumDisplaySettingsA (USER32.@)
466  */
467 BOOL WINAPI EnumDisplaySettingsA(LPCSTR name,DWORD n,LPDEVMODEA devmode)
468 {
469     return EnumDisplaySettingsExA(name, n, devmode, 0);
470 }
471
472 /***********************************************************************
473  *              EnumDisplaySettingsExA (USER32.@)
474  */
475 BOOL WINAPI EnumDisplaySettingsExA(LPCSTR lpszDeviceName, DWORD iModeNum,
476                                    LPDEVMODEA lpDevMode, DWORD dwFlags)
477 {
478     DEVMODEW devmodeW;
479     BOOL ret;
480     UNICODE_STRING nameW;
481
482     if (lpszDeviceName) RtlCreateUnicodeStringFromAsciiz(&nameW, lpszDeviceName);
483     else nameW.Buffer = NULL;
484
485     ret = EnumDisplaySettingsExW(nameW.Buffer,iModeNum,&devmodeW,dwFlags);
486     if (ret)
487     {
488         lpDevMode->dmBitsPerPel       = devmodeW.dmBitsPerPel;
489         lpDevMode->dmPelsHeight       = devmodeW.dmPelsHeight;
490         lpDevMode->dmPelsWidth        = devmodeW.dmPelsWidth;
491         lpDevMode->dmDisplayFlags     = devmodeW.dmDisplayFlags;
492         lpDevMode->dmDisplayFrequency = devmodeW.dmDisplayFrequency;
493         lpDevMode->dmFields           = devmodeW.dmFields;
494     }
495     if (lpszDeviceName) RtlFreeUnicodeString(&nameW);
496     return ret;
497 }
498
499 /***********************************************************************
500  *              EnumDisplaySettingsExW (USER32.@)
501  */
502 BOOL WINAPI EnumDisplaySettingsExW(LPCWSTR lpszDeviceName, DWORD iModeNum,
503                                    LPDEVMODEW lpDevMode, DWORD dwFlags)
504 {
505     /* Pass the request on to the driver */
506     if (!USER_Driver.pEnumDisplaySettingsExW) return FALSE;
507     return USER_Driver.pEnumDisplaySettingsExW(lpszDeviceName, iModeNum, lpDevMode, dwFlags);
508 }
509
510 /***********************************************************************
511  *              EnumDisplayDevicesA (USER32.@)
512  */
513 BOOL WINAPI EnumDisplayDevicesA(
514         LPVOID unused,DWORD i,LPDISPLAY_DEVICEA lpDisplayDevice,DWORD dwFlags
515 ) {
516         if (i)
517                 return FALSE;
518         FIXME("(%p,%ld,%p,0x%08lx), stub!\n",unused,i,lpDisplayDevice,dwFlags);
519         strcpy(lpDisplayDevice->DeviceName,"X11");
520         strcpy(lpDisplayDevice->DeviceString,"X 11 Windowing System");
521         lpDisplayDevice->StateFlags =
522                         DISPLAY_DEVICE_ATTACHED_TO_DESKTOP      |
523                         DISPLAY_DEVICE_PRIMARY_DEVICE           |
524                         DISPLAY_DEVICE_VGA_COMPATIBLE;
525         return TRUE;
526 }
527
528 /***********************************************************************
529  *              EnumDisplayDevicesW (USER32.@)
530  */
531 BOOL WINAPI EnumDisplayDevicesW(
532         LPVOID unused,DWORD i,LPDISPLAY_DEVICEW lpDisplayDevice,DWORD dwFlags
533 ) {
534         if (i)
535                 return FALSE;
536         FIXME("(%p,%ld,%p,0x%08lx), stub!\n",unused,i,lpDisplayDevice,dwFlags);
537         MultiByteToWideChar( CP_ACP, 0, "X11", -1, lpDisplayDevice->DeviceName,
538                              sizeof(lpDisplayDevice->DeviceName)/sizeof(WCHAR) );
539         MultiByteToWideChar( CP_ACP, 0, "X11 Windowing System", -1, lpDisplayDevice->DeviceString,
540                              sizeof(lpDisplayDevice->DeviceString)/sizeof(WCHAR) );
541         lpDisplayDevice->StateFlags =
542                         DISPLAY_DEVICE_ATTACHED_TO_DESKTOP      |
543                         DISPLAY_DEVICE_PRIMARY_DEVICE           |
544                         DISPLAY_DEVICE_VGA_COMPATIBLE;
545         return TRUE;
546 }
547
548 /***********************************************************************
549  *              UserSeeUserDo (USER.216)
550  */
551 DWORD WINAPI UserSeeUserDo16(WORD wReqType, WORD wParam1, WORD wParam2, WORD wParam3)
552 {
553     STACK16FRAME* stack16 = MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved);
554     HANDLE16 oldDS = stack16->ds;
555     DWORD ret = (DWORD)-1;
556
557     stack16->ds = USER_HeapSel;
558     switch (wReqType)
559     {
560     case USUD_LOCALALLOC:
561         ret = LocalAlloc16(wParam1, wParam3);
562         break;
563     case USUD_LOCALFREE:
564         ret = LocalFree16(wParam1);
565         break;
566     case USUD_LOCALCOMPACT:
567         ret = LocalCompact16(wParam3);
568         break;
569     case USUD_LOCALHEAP:
570         ret = USER_HeapSel;
571         break;
572     case USUD_FIRSTCLASS:
573         FIXME("return a pointer to the first window class.\n");
574         break;
575     default:
576         WARN("wReqType %04x (unknown)\n", wReqType);
577     }
578     stack16->ds = oldDS;
579     return ret;
580 }
581
582 /***********************************************************************
583  *              SetSystemCursor (USER32.@)
584  */
585 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
586 {       FIXME("(%p,%08lx),stub!\n",  hcur, id);
587         return TRUE;
588 }