Release 980503
[wine] / windows / user.c
1 /*
2  * Misc. USER functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  *           1996 Alex Korobka 
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include "windows.h"
11 #include "resource.h"
12 #include "heap.h"
13 #include "gdi.h"
14 #include "user.h"
15 #include "task.h"
16 #include "queue.h"
17 #include "win.h"
18 #include "clipboard.h"
19 #include "hook.h"
20 #include "debug.h"
21 #include "toolhelp.h"
22 #include "message.h"
23 #include "module.h"
24 #include "miscemu.h"
25 #include "shell.h"
26
27 extern BOOL32 MENU_PatchResidentPopup( HQUEUE16, WND* );
28 extern void QUEUE_FlushMessages(HQUEUE16);
29
30 /***********************************************************************
31  *           GetFreeSystemResources   (USER.284)
32  */
33 WORD WINAPI GetFreeSystemResources( WORD resType )
34 {
35     int userPercent, gdiPercent;
36
37     switch(resType)
38     {
39     case GFSR_USERRESOURCES:
40         userPercent = (int)LOCAL_CountFree( USER_HeapSel ) * 100 /
41                                LOCAL_HeapSize( USER_HeapSel );
42         gdiPercent  = 100;
43         break;
44
45     case GFSR_GDIRESOURCES:
46         gdiPercent  = (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
47                                LOCAL_HeapSize( GDI_HeapSel );
48         userPercent = 100;
49         break;
50
51     case GFSR_SYSTEMRESOURCES:
52         userPercent = (int)LOCAL_CountFree( USER_HeapSel ) * 100 /
53                                LOCAL_HeapSize( USER_HeapSel );
54         gdiPercent  = (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
55                                LOCAL_HeapSize( GDI_HeapSel );
56         break;
57
58     default:
59         return 0;
60     }
61     return (WORD)MIN( userPercent, gdiPercent );
62 }
63
64
65 /***********************************************************************
66  *           SystemHeapInfo   (TOOLHELP.71)
67  */
68 BOOL16 WINAPI SystemHeapInfo( SYSHEAPINFO *pHeapInfo )
69 {
70     pHeapInfo->wUserFreePercent = GetFreeSystemResources( GFSR_USERRESOURCES );
71     pHeapInfo->wGDIFreePercent  = GetFreeSystemResources( GFSR_GDIRESOURCES );
72     pHeapInfo->hUserSegment = USER_HeapSel;
73     pHeapInfo->hGDISegment  = GDI_HeapSel;
74     return TRUE;
75 }
76
77
78 /***********************************************************************
79  *           TimerCount   (TOOLHELP.80)
80  */
81 BOOL16 WINAPI TimerCount( TIMERINFO *pTimerInfo )
82 {
83     /* FIXME
84      * In standard mode, dwmsSinceStart = dwmsThisVM 
85      *
86      * I tested this, under Windows in enhanced mode, and
87      * if you never switch VM (ie start/stop DOS) these
88      * values should be the same as well. 
89      *
90      * Also, Wine should adjust for the hardware timer
91      * to reduce the amount of error to ~1ms. 
92      * I can't be bothered, can you?
93      */
94     pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
95     return TRUE;
96 }
97
98 static RESOURCEHANDLER16 __r16loader = NULL;
99
100 /**********************************************************************
101  *           USER_CallDefaultRsrcHandler
102  *
103  * Called by the LoadDIBIcon/CursorHandler().
104  */
105 HGLOBAL16 USER_CallDefaultRsrcHandler( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
106 {
107     return __r16loader( hMemObj, hModule, hRsrc );
108 }
109
110 /**********************************************************************
111  *           USER_InstallRsrcHandler
112  */
113 static void USER_InstallRsrcHandler( HINSTANCE16 hInstance )
114 {
115     FARPROC16 proc;
116
117     /* SetResourceHandler() returns previous function which is set
118      * when a module's resource table is loaded. */
119
120     proc = SetResourceHandler( hInstance, RT_ICON16,
121                                (FARPROC32)LoadDIBIconHandler );
122     if(!__r16loader ) 
123         __r16loader = (RESOURCEHANDLER16)proc;
124     proc = SetResourceHandler( hInstance, RT_CURSOR16,
125                                (FARPROC32)LoadDIBCursorHandler );
126     if(!__r16loader )
127         __r16loader = (RESOURCEHANDLER16)proc;
128 }
129
130 /**********************************************************************
131  *           InitApp   (USER.5)
132  */
133 INT16 WINAPI InitApp( HINSTANCE16 hInstance )
134 {
135     int queueSize;
136
137       /* InitTask() calls LibMain()'s of implicitly loaded DLLs 
138        * prior to InitApp() so there is no clean way to do
139        * SetTaskSignalHandler() in time. So, broken Windows bypasses 
140        * a pTask->userhandler on startup and simply calls a global 
141        * function pointer to the default USER signal handler.
142        */
143
144     USER_InstallRsrcHandler( hInstance );
145
146     /* Hack: restore the divide-by-zero handler */
147     /* FIXME: should set a USER-specific handler that displays a msg box */
148     INT_SetHandler( 0, INT_GetHandler( 0xff ) );
149
150       /* Create task message queue */
151     queueSize = GetProfileInt32A( "windows", "DefaultQueueSize", 8 );
152     if (!SetMessageQueue32( queueSize )) return 0;
153
154     return 1;
155 }
156
157 /**********************************************************************
158  *           USER_ModuleUnload
159  */
160 static void USER_ModuleUnload( HMODULE16 hModule )
161 {
162     HOOK_FreeModuleHooks( hModule );
163     CLASS_FreeModuleClasses( hModule );
164 }
165
166 /**********************************************************************
167  *           USER_AppExit
168  */
169 static void USER_AppExit( HTASK16 hTask, HINSTANCE16 hInstance, HQUEUE16 hQueue )
170 {
171     /* FIXME: empty clipboard if needed, maybe destroy menus (Windows
172      *        only complains about them but does nothing);
173      */
174
175     WND* desktop = WIN_GetDesktop();
176
177     /* Patch desktop window */
178     if( desktop->hmemTaskQ == hQueue )
179         desktop->hmemTaskQ = GetTaskQueue(TASK_GetNextTask(hTask));
180
181     /* Patch resident popup menu window */
182     MENU_PatchResidentPopup( hQueue, NULL );
183
184     TIMER_RemoveQueueTimers( hQueue );
185
186     QUEUE_FlushMessages( hQueue );
187     HOOK_FreeQueueHooks( hQueue );
188
189     QUEUE_SetExitingQueue( hQueue );
190     WIN_ResetQueueWindows( desktop, hQueue, (HQUEUE16)0);
191     CLIPBOARD_ResetLock( hQueue, 0 );
192     QUEUE_SetExitingQueue( 0 );
193
194     /* Free the message queue */
195
196     QUEUE_DeleteMsgQueue( hQueue );
197
198     /* ModuleUnload() in "Internals" */
199
200     hInstance = GetExePtr( hInstance );
201     if( GetModuleUsage( hInstance ) <= 1 ) 
202         USER_ModuleUnload( hInstance );
203 }
204
205
206 /***********************************************************************
207  *           USER_ExitWindows
208  *
209  * Clean-up everything and exit the Wine process.
210  * This is the back-end of ExitWindows(), called when all windows
211  * have agreed to be terminated.
212  */
213 void USER_ExitWindows(void)
214 {
215     /* Do the clean-up stuff */
216
217     WriteOutProfiles();
218     SHELL_SaveRegistry();
219
220     exit(0);
221 }
222
223
224 /***********************************************************************
225  *           USER_SignalProc (USER.314)
226  */
227 void WINAPI USER_SignalProc( HANDLE16 hTaskOrModule, UINT16 uCode,
228                              UINT16 uExitFn, HINSTANCE16 hInstance,
229                              HQUEUE16 hQueue )
230 {
231     switch( uCode )
232     {
233         case USIG_GPF:
234         case USIG_TERMINATION:
235              USER_AppExit( hTaskOrModule, hInstance, hQueue ); /* task */
236              break;
237
238         case USIG_DLL_LOAD:
239              USER_InstallRsrcHandler( hTaskOrModule ); /* module */
240              break;
241
242         case USIG_DLL_UNLOAD:
243              USER_ModuleUnload( hTaskOrModule ); /* module */
244              break;
245
246         default:
247              fprintf(stderr,"Unimplemented USER signal: %i\n", (int)uCode );
248     }
249 }
250
251
252 /***********************************************************************
253  *           ExitWindows16   (USER.7)
254  */
255 BOOL16 WINAPI ExitWindows16( DWORD dwReturnCode, UINT16 wReserved )
256 {
257     return ExitWindowsEx( EWX_LOGOFF, 0xffffffff );
258 }
259
260
261 /***********************************************************************
262  *           ExitWindowsExec16   (USER.246)
263  */
264 BOOL16 WINAPI ExitWindowsExec16( LPCSTR lpszExe, LPCSTR lpszParams )
265 {
266     fprintf(stderr, "ExitWindowsExec() : Should run the following in DOS-mode :\n\t\"%s %s\"\n",
267         lpszExe, lpszParams);
268     return ExitWindowsEx( EWX_LOGOFF, 0xffffffff );
269 }
270
271
272 /***********************************************************************
273  *           ExitWindowsEx   (USER32.196)
274  */
275 BOOL32 WINAPI ExitWindowsEx( UINT32 flags, DWORD reserved )
276 {
277     int i;
278     BOOL32 result;
279     WND **list, **ppWnd;
280         
281     /* We have to build a list of all windows first, as in EnumWindows */
282
283     if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL ))) return FALSE;
284
285     /* Send a WM_QUERYENDSESSION message to every window */
286
287     for (ppWnd = list, i = 0; *ppWnd; ppWnd++, i++)
288     {
289         /* Make sure that the window still exists */
290         if (!IsWindow32( (*ppWnd)->hwndSelf )) continue;
291         if (!SendMessage16( (*ppWnd)->hwndSelf, WM_QUERYENDSESSION, 0, 0 ))
292             break;
293     }
294     result = !(*ppWnd);
295
296     /* Now notify all windows that got a WM_QUERYENDSESSION of the result */
297
298     for (ppWnd = list; i > 0; i--, ppWnd++)
299     {
300         if (!IsWindow32( (*ppWnd)->hwndSelf )) continue;
301         SendMessage16( (*ppWnd)->hwndSelf, WM_ENDSESSION, result, 0 );
302     }
303     HeapFree( SystemHeap, 0, list );
304
305     if (result) USER_ExitWindows();
306     return FALSE;
307 }
308
309 /***********************************************************************
310  *           EnumDisplaySettingsA   (USER32.592)
311  */
312 BOOL32 WINAPI EnumDisplaySettings32A(LPCSTR name,DWORD n,LPDEVMODE32A devmode) {
313         fprintf(stderr,"EnumDisplaySettings32A(%s,%ld,%p)\n",name,n,devmode);
314         if (n==0) {
315                 devmode->dmBitsPerPel = DefaultDepthOfScreen(screen);
316                 devmode->dmPelsHeight = screenHeight;
317                 devmode->dmPelsWidth = screenWidth;
318                 return TRUE;
319         }
320         return FALSE;
321 }
322
323
324 /***********************************************************************
325  *           SetEventHook   (USER.321)
326  *
327  *      Used by Turbo Debugger for Windows
328  */
329 FARPROC16 SetEventHook(FARPROC16 lpfnEventHook)
330 {
331         fprintf(stderr, "SetEventHook(lpfnEventHook = %08x): stub !\n", (UINT32)lpfnEventHook);
332         return NULL;
333 }
334
335 /***********************************************************************
336  *           UserSeeUserDo   (USER.216)
337  */
338 DWORD WINAPI UserSeeUserDo(WORD wReqType, WORD wParam1, WORD wParam2, WORD wParam3)
339 {
340     switch (wReqType)
341     {
342     case USUD_LOCALALLOC:
343         return LOCAL_Alloc(USER_HeapSel, wParam1, wParam3);
344     case USUD_LOCALFREE:
345         return LOCAL_Free(USER_HeapSel, wParam1);
346     case USUD_LOCALCOMPACT:
347         return LOCAL_Compact(USER_HeapSel, wParam3, 0);
348     case USUD_LOCALHEAP:
349         return USER_HeapSel;
350     case USUD_FIRSTCLASS:
351         FIXME(local, "return a pointer to the first window class.\n"); 
352         return (DWORD)-1;
353     default:
354         WARN(local, "wReqType %04x (unknown)", wReqType);
355         return (DWORD)-1;
356     }
357 }
358