Fixed an unbalanced windows lock/unlock sequence in GetNextDlgTabItem.
[wine] / windows / user.c
1 /*
2  * Misc. USER functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  *           1996 Alex Korobka 
6  */
7
8 #include <stdlib.h>
9 #include "wine/winbase16.h"
10 #include "winuser.h"
11 #include "heap.h"
12 #include "user.h"
13 #include "gdi.h"
14 #include "task.h"
15 #include "queue.h"
16 #include "win.h"
17 #include "clipboard.h"
18 #include "menu.h"
19 #include "cursoricon.h"
20 #include "hook.h"
21 #include "toolhelp.h"
22 #include "message.h"
23 #include "module.h"
24 #include "miscemu.h"
25 #include "shell.h"
26 #include "callback.h"
27 #include "local.h"
28 #include "class.h"
29 #include "desktop.h"
30 #include "process.h"
31 #include "debug.h"
32
33 DECLARE_DEBUG_CHANNEL(hook)
34 DECLARE_DEBUG_CHANNEL(local)
35 DECLARE_DEBUG_CHANNEL(system)
36 DECLARE_DEBUG_CHANNEL(win)
37 DECLARE_DEBUG_CHANNEL(win32)
38
39 /***********************************************************************
40  *           GetFreeSystemResources   (USER.284)
41  */
42 WORD WINAPI GetFreeSystemResources16( WORD resType )
43 {
44     int userPercent, gdiPercent;
45
46     switch(resType)
47     {
48     case GFSR_USERRESOURCES:
49         userPercent = (int)LOCAL_CountFree( USER_HeapSel ) * 100 /
50                                LOCAL_HeapSize( USER_HeapSel );
51         gdiPercent  = 100;
52         break;
53
54     case GFSR_GDIRESOURCES:
55         gdiPercent  = (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
56                                LOCAL_HeapSize( GDI_HeapSel );
57         userPercent = 100;
58         break;
59
60     case GFSR_SYSTEMRESOURCES:
61         userPercent = (int)LOCAL_CountFree( USER_HeapSel ) * 100 /
62                                LOCAL_HeapSize( USER_HeapSel );
63         gdiPercent  = (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
64                                LOCAL_HeapSize( GDI_HeapSel );
65         break;
66
67     default:
68         return 0;
69     }
70     return (WORD)MIN( userPercent, gdiPercent );
71 }
72
73
74 /***********************************************************************
75  *           SystemHeapInfo   (TOOLHELP.71)
76  */
77 BOOL16 WINAPI SystemHeapInfo16( SYSHEAPINFO *pHeapInfo )
78 {
79     pHeapInfo->wUserFreePercent = GetFreeSystemResources16( GFSR_USERRESOURCES );
80     pHeapInfo->wGDIFreePercent  = GetFreeSystemResources16( GFSR_GDIRESOURCES );
81     pHeapInfo->hUserSegment = USER_HeapSel;
82     pHeapInfo->hGDISegment  = GDI_HeapSel;
83     return TRUE;
84 }
85
86
87 /***********************************************************************
88  *           TimerCount   (TOOLHELP.80)
89  */
90 BOOL16 WINAPI TimerCount16( TIMERINFO *pTimerInfo )
91 {
92     /* FIXME
93      * In standard mode, dwmsSinceStart = dwmsThisVM 
94      *
95      * I tested this, under Windows in enhanced mode, and
96      * if you never switch VM (ie start/stop DOS) these
97      * values should be the same as well. 
98      *
99      * Also, Wine should adjust for the hardware timer
100      * to reduce the amount of error to ~1ms. 
101      * I can't be bothered, can you?
102      */
103     pTimerInfo->dwmsSinceStart = pTimerInfo->dwmsThisVM = GetTickCount();
104     return TRUE;
105 }
106
107 /**********************************************************************
108  *           InitApp   (USER.5)
109  */
110 INT16 WINAPI InitApp16( HINSTANCE16 hInstance )
111 {
112     /* Hack: restore the divide-by-zero handler */
113     /* FIXME: should set a USER-specific handler that displays a msg box */
114     INT_SetPMHandler( 0, INT_GetPMHandler( 0xff ) );
115
116     /* Create task message queue */
117     if ( !GetFastQueue16() ) return 0;
118
119     return 1;
120 }
121
122 /**********************************************************************
123  *           USER_ModuleUnload
124  */
125 static void USER_ModuleUnload( HMODULE16 hModule )
126 {
127     HOOK_FreeModuleHooks( hModule );
128     CLASS_FreeModuleClasses( hModule );
129     CURSORICON_FreeModuleIcons( hModule );
130 }
131
132 /**********************************************************************
133  *           USER_QueueCleanup
134  */
135 static void USER_QueueCleanup( HQUEUE16 hQueue )
136 {
137     if ( hQueue )
138     {
139         WND* desktop = WIN_GetDesktop();
140
141         /* Patch desktop window */
142         if ( desktop->hmemTaskQ == hQueue )
143         {
144             HTASK16 nextTask = TASK_GetNextTask( GetCurrentTask() );
145             desktop->hmemTaskQ = GetTaskQueue16( nextTask );
146         }
147
148         /* Patch resident popup menu window */
149         MENU_PatchResidentPopup( hQueue, NULL );
150
151         TIMER_RemoveQueueTimers( hQueue );
152
153         HOOK_FreeQueueHooks( hQueue );
154
155         QUEUE_SetExitingQueue( hQueue );
156         WIN_ResetQueueWindows( desktop, hQueue, (HQUEUE16)0);
157         CLIPBOARD_ResetLock( hQueue, 0 );
158         QUEUE_SetExitingQueue( 0 );
159
160         /* Free the message queue */
161         QUEUE_DeleteMsgQueue( hQueue );
162
163         WIN_ReleaseDesktop();
164     }
165 }
166
167 /**********************************************************************
168  *           USER_AppExit
169  */
170 static void USER_AppExit( HINSTANCE16 hInstance )
171 {
172     /* FIXME: empty clipboard if needed, maybe destroy menus (Windows
173      *        only complains about them but does nothing);
174      */
175
176     /* ModuleUnload() in "Internals" */
177
178     hInstance = GetExePtr( hInstance );
179     if( GetModuleUsage16( hInstance ) <= 1 ) 
180         USER_ModuleUnload( hInstance );
181 }
182
183
184 /***********************************************************************
185  *           USER_ExitWindows
186  *
187  * Clean-up everything and exit the Wine process.
188  * This is the back-end of ExitWindows(), called when all windows
189  * have agreed to be terminated.
190  */
191 void USER_ExitWindows(void)
192 {
193     /* Do the clean-up stuff */
194
195     WriteOutProfiles16();
196     SHELL_SaveRegistry();
197
198     exit(0);
199 }
200
201
202 /***********************************************************************
203  *           USER_SignalProc (USER.314)
204  */
205 void WINAPI USER_SignalProc( HANDLE16 hTaskOrModule, UINT16 uCode,
206                              UINT16 uExitFn, HINSTANCE16 hInstance,
207                              HQUEUE16 hQueue )
208 {
209     FIXME( win, "Win 3.1 USER signal %04x\n", uCode );
210 }
211
212 /***********************************************************************
213  *           UserSignalProc     (USER.610) (USER32.559)
214  *
215  * For comments about the meaning of uCode and dwFlags 
216  * see PROCESS_CallUserSignalProc.
217  *
218  */
219 WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
220                             DWORD dwFlags, HMODULE16 hModule )
221 {
222     HINSTANCE16 hInst;
223
224     /* FIXME: Proper reaction to most signals still missing. */
225
226     switch ( uCode )
227     {
228     case USIG_DLL_UNLOAD_WIN16:
229     case USIG_DLL_UNLOAD_WIN32:
230         USER_ModuleUnload( hModule );
231         break;
232
233     case USIG_DLL_UNLOAD_ORPHANS:
234         break;
235
236     case USIG_FAULT_DIALOG_PUSH:
237     case USIG_FAULT_DIALOG_POP:
238         break;
239
240     case USIG_THREAD_INIT:
241         break;
242
243     case USIG_THREAD_EXIT:
244         USER_QueueCleanup( GetThreadQueue16( dwThreadOrProcessID ) );
245         SetThreadQueue16( dwThreadOrProcessID, 0 );
246         break;
247
248     case USIG_PROCESS_CREATE:
249     case USIG_PROCESS_INIT:
250     case USIG_PROCESS_LOADED:
251     case USIG_PROCESS_RUNNING:
252         break;
253
254     case USIG_PROCESS_EXIT:
255         break;
256
257     case USIG_PROCESS_DESTROY:
258         hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 );
259         USER_AppExit( hInst );
260         break;
261
262     default:
263         FIXME( win, "(%04x, %08lx, %04lx, %04x)\n",
264                     uCode, dwThreadOrProcessID, dwFlags, hModule );
265         break;
266     }
267
268     /* FIXME: Should chain to GdiSignalProc now. */
269
270     return 0;
271 }
272
273
274
275 /***********************************************************************
276  *           ExitWindows16   (USER.7)
277  */
278 BOOL16 WINAPI ExitWindows16( DWORD dwReturnCode, UINT16 wReserved )
279 {
280     return ExitWindowsEx( EWX_LOGOFF, 0xffffffff );
281 }
282
283
284 /***********************************************************************
285  *           ExitWindowsExec16   (USER.246)
286  */
287 BOOL16 WINAPI ExitWindowsExec16( LPCSTR lpszExe, LPCSTR lpszParams )
288 {
289     TRACE(system, "Should run the following in DOS-mode: \"%s %s\"\n",
290         lpszExe, lpszParams);
291     return ExitWindowsEx( EWX_LOGOFF, 0xffffffff );
292 }
293
294
295 /***********************************************************************
296  *           ExitWindowsEx   (USER32.196)
297  */
298 BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reserved )
299 {
300     int i;
301     BOOL result;
302     WND **list, **ppWnd;
303         
304     /* We have to build a list of all windows first, as in EnumWindows */
305
306     if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
307     {
308         WIN_ReleaseDesktop();
309         return FALSE;
310     }
311
312     /* Send a WM_QUERYENDSESSION message to every window */
313
314     for (ppWnd = list, i = 0; *ppWnd; ppWnd++, i++)
315     {
316         /* Make sure that the window still exists */
317         if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
318         if (!SendMessage16( (*ppWnd)->hwndSelf, WM_QUERYENDSESSION, 0, 0 ))
319             break;
320     }
321     result = !(*ppWnd);
322
323     /* Now notify all windows that got a WM_QUERYENDSESSION of the result */
324
325     for (ppWnd = list; i > 0; i--, ppWnd++)
326     {
327         if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
328         SendMessage16( (*ppWnd)->hwndSelf, WM_ENDSESSION, result, 0 );
329     }
330     WIN_ReleaseWinArray(list);
331
332     if (result) USER_ExitWindows();
333     WIN_ReleaseDesktop();
334     return FALSE;
335 }
336
337
338 /***********************************************************************
339  *           ChangeDisplaySettingA    (USER32.589)
340  */
341 LONG WINAPI ChangeDisplaySettingsA( LPDEVMODEA devmode, DWORD flags )
342 {
343   FIXME(system, ": stub\n");
344   if (devmode==NULL)
345     FIXME(system,"   devmode=NULL (return to default mode)\n");
346   else if ( (devmode->dmBitsPerPel != DESKTOP_GetScreenDepth()) 
347             || (devmode->dmPelsHeight != DESKTOP_GetScreenHeight())
348             || (devmode->dmPelsWidth != DESKTOP_GetScreenWidth()) )
349
350   {
351
352     if (devmode->dmFields & DM_BITSPERPEL)
353       FIXME(system,"   bpp=%ld\n",devmode->dmBitsPerPel);
354     if (devmode->dmFields & DM_PELSWIDTH)
355       FIXME(system,"   width=%ld\n",devmode->dmPelsWidth);
356     if (devmode->dmFields & DM_PELSHEIGHT)
357       FIXME(system,"   height=%ld\n",devmode->dmPelsHeight);
358     FIXME(system," (Putting X in this mode beforehand might help)\n"); 
359     /* we don't, but the program ... does not need to know */
360     return DISP_CHANGE_SUCCESSFUL; 
361   }
362   return DISP_CHANGE_SUCCESSFUL;
363 }
364
365 /***********************************************************************
366  *           EnumDisplaySettingsA   (USER32.592)
367  * FIXME: Currently uses static list of modes.
368  *
369  * RETURNS
370  *      TRUE if nth setting exists found (described in the LPDEVMODE32A struct)
371  *      FALSE if we do not have the nth setting
372  */
373 BOOL WINAPI EnumDisplaySettingsA(
374         LPCSTR name,            /* [in] huh? */
375         DWORD n,                /* [in] nth entry in display settings list*/
376         LPDEVMODEA devmode      /* [out] devmode for that setting */
377 ) {
378 #define NRMODES 5
379 #define NRDEPTHS 4
380         struct {
381                 int w,h;
382         } modes[NRMODES]={{512,384},{640,400},{640,480},{800,600},{1024,768}};
383         int depths[4] = {8,16,24,32};
384
385         TRACE(system,"(%s,%ld,%p)\n",name,n,devmode);
386         if (n==0) {
387                 devmode->dmBitsPerPel = DESKTOP_GetScreenDepth();
388                 devmode->dmPelsHeight = DESKTOP_GetScreenHeight();
389                 devmode->dmPelsWidth = DESKTOP_GetScreenWidth();
390                 return TRUE;
391         }
392         if ((n-1)<NRMODES*NRDEPTHS) {
393                 devmode->dmBitsPerPel   = depths[(n-1)/NRMODES];
394                 devmode->dmPelsHeight   = modes[(n-1)%NRMODES].h;
395                 devmode->dmPelsWidth    = modes[(n-1)%NRMODES].w;
396                 return TRUE;
397         }
398         return FALSE;
399 }
400
401 /***********************************************************************
402  *           EnumDisplaySettingsW   (USER32.593)
403  */
404 BOOL WINAPI EnumDisplaySettingsW(LPCWSTR name,DWORD n,LPDEVMODEW devmode) {
405         LPSTR nameA = HEAP_strdupWtoA(GetProcessHeap(),0,name);
406         DEVMODEA        devmodeA; 
407         BOOL ret = EnumDisplaySettingsA(nameA,n,&devmodeA); 
408
409         if (ret) {
410                 devmode->dmBitsPerPel   = devmodeA.dmBitsPerPel;
411                 devmode->dmPelsHeight   = devmodeA.dmPelsHeight;
412                 devmode->dmPelsWidth    = devmodeA.dmPelsWidth;
413                 /* FIXME: convert rest too, if they are ever returned */
414         }
415         HeapFree(GetProcessHeap(),0,nameA);
416         return ret;
417 }
418
419 /***********************************************************************
420  *           SetEventHook   (USER.321)
421  *
422  *      Used by Turbo Debugger for Windows
423  */
424 FARPROC16 WINAPI SetEventHook16(FARPROC16 lpfnEventHook)
425 {
426         FIXME(hook, "(lpfnEventHook=%08x): stub\n", (UINT)lpfnEventHook);
427         return NULL;
428 }
429
430 /***********************************************************************
431  *           UserSeeUserDo   (USER.216)
432  */
433 DWORD WINAPI UserSeeUserDo16(WORD wReqType, WORD wParam1, WORD wParam2, WORD wParam3)
434 {
435     switch (wReqType)
436     {
437     case USUD_LOCALALLOC:
438         return LOCAL_Alloc(USER_HeapSel, wParam1, wParam3);
439     case USUD_LOCALFREE:
440         return LOCAL_Free(USER_HeapSel, wParam1);
441     case USUD_LOCALCOMPACT:
442         return LOCAL_Compact(USER_HeapSel, wParam3, 0);
443     case USUD_LOCALHEAP:
444         return USER_HeapSel;
445     case USUD_FIRSTCLASS:
446         FIXME(local, "return a pointer to the first window class.\n"); 
447         return (DWORD)-1;
448     default:
449         WARN(local, "wReqType %04x (unknown)", wReqType);
450         return (DWORD)-1;
451     }
452 }
453
454 /***********************************************************************
455  *           RegisterLogonProcess   (USER32.434)
456  */
457 DWORD WINAPI RegisterLogonProcess(HANDLE hprocess,BOOL x) {
458         FIXME(win32,"(%d,%d),stub!\n",hprocess,x);
459         return 1;
460 }
461
462 /***********************************************************************
463  *           CreateWindowStation32W   (USER32.86)
464  */
465 HWINSTA WINAPI CreateWindowStationW(
466         LPWSTR winstation,DWORD res1,DWORD desiredaccess,
467         LPSECURITY_ATTRIBUTES lpsa
468 ) {
469         FIXME(win32,"(%s,0x%08lx,0x%08lx,%p),stub!\n",debugstr_w(winstation),
470                 res1,desiredaccess,lpsa
471         );
472         return 0xdeadcafe;
473 }
474
475 /***********************************************************************
476  *           SetProcessWindowStation   (USER32.496)
477  */
478 BOOL WINAPI SetProcessWindowStation(HWINSTA hWinSta) {
479         FIXME(win32,"(%d),stub!\n",hWinSta);
480         return TRUE;
481 }
482
483 /***********************************************************************
484  *           SetUserObjectSecurity   (USER32.514)
485  */
486 BOOL WINAPI SetUserObjectSecurity(
487         HANDLE hObj,
488         /*LPSECURITY_INFORMATION*/LPVOID pSIRequested,
489         PSECURITY_DESCRIPTOR pSID
490 ) {
491         FIXME(win32,"(0x%08x,%p,%p),stub!\n",hObj,pSIRequested,pSID);
492         return TRUE;
493 }
494
495 /***********************************************************************
496  *           CreateDesktop32W   (USER32.69)
497  */
498 HDESK WINAPI CreateDesktopW(
499         LPWSTR lpszDesktop,LPWSTR lpszDevice,LPDEVMODEW pDevmode,
500         DWORD dwFlags,DWORD dwDesiredAccess,LPSECURITY_ATTRIBUTES lpsa
501 ) {
502         FIXME(win32,"(%s,%s,%p,0x%08lx,0x%08lx,%p),stub!\n",
503                 debugstr_w(lpszDesktop),debugstr_w(lpszDevice),pDevmode,
504                 dwFlags,dwDesiredAccess,lpsa
505         );
506         return 0xcafedead;
507 }
508
509 BOOL WINAPI CloseWindowStation(HWINSTA hWinSta)
510 {
511     FIXME(win32, "(0x%08x)\n", hWinSta);
512     return TRUE;
513 }
514 BOOL WINAPI CloseDesktop(HDESK hDesk)
515 {
516     FIXME(win32, "(0x%08x)\n", hDesk);
517     return TRUE;
518 }
519
520 /***********************************************************************
521  *           SetWindowStationUser   (USER32.521)
522  */
523 DWORD WINAPI SetWindowStationUser(DWORD x1,DWORD x2) {
524         FIXME(win32,"(0x%08lx,0x%08lx),stub!\n",x1,x2);
525         return 1;
526 }
527
528 /***********************************************************************
529  *           SetLogonNotifyWindow   (USER32.486)
530  */
531 DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd) {
532         FIXME(win32,"(0x%x,%04x),stub!\n",hwinsta,hwnd);
533         return 1;
534 }
535
536 /***********************************************************************
537  *           LoadLocalFonts   (USER32.486)
538  */
539 VOID WINAPI LoadLocalFonts(VOID) {
540         /* are loaded. */
541         return;
542 }
543 /***********************************************************************
544  *           GetUserObjectInformation32A   (USER32.299)
545  */
546 BOOL WINAPI GetUserObjectInformationA( HANDLE hObj, int nIndex, LPVOID pvInfo, DWORD nLength, LPDWORD lpnLen )
547 {       FIXME(win32,"(0x%x %i %p %ld %p),stub!\n", hObj, nIndex, pvInfo, nLength, lpnLen );
548         return TRUE;
549 }
550 /***********************************************************************
551  *           GetUserObjectInformation32W   (USER32.300)
552  */
553 BOOL WINAPI GetUserObjectInformationW( HANDLE hObj, int nIndex, LPVOID pvInfo, DWORD nLength, LPDWORD lpnLen )
554 {       FIXME(win32,"(0x%x %i %p %ld %p),stub!\n", hObj, nIndex, pvInfo, nLength, lpnLen );
555         return TRUE;
556 }
557 /***********************************************************************
558  *           GetUserObjectSecurity32   (USER32.300)
559  */
560 BOOL WINAPI GetUserObjectSecurity(HANDLE hObj, SECURITY_INFORMATION * pSIRequested,
561         PSECURITY_DESCRIPTOR pSID, DWORD nLength, LPDWORD lpnLengthNeeded)
562 {       FIXME(win32,"(0x%x %p %p len=%ld %p),stub!\n",  hObj, pSIRequested, pSID, nLength, lpnLengthNeeded);
563         return TRUE;
564 }
565
566 /***********************************************************************
567  *           SetSystemCursor   (USER32.507)
568  */
569 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
570 {       FIXME(win32,"(%08x,%08lx),stub!\n",  hcur, id);
571         return TRUE;
572 }
573
574 /***********************************************************************
575  *      RegisterSystemThread    (USER32.435)
576  */
577 void WINAPI RegisterSystemThread(DWORD flags, DWORD reserved)
578 {
579         FIXME(win32, "(%08lx, %08lx)\n", flags, reserved);
580 }