| /* | |
| * USER initialization code | |
| * | |
| * Copyright 2000 Alexandre Julliard | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winreg.h" | |
| #include "tlhelp32.h" | |
| #include "controls.h" | |
| #include "user_private.h" | |
| #include "win.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(graphics); | |
| WORD USER_HeapSel = 0; /* USER heap selector */ | |
| HMODULE user32_module = 0; | |
| static SYSLEVEL USER_SysLevel; | |
| static CRITICAL_SECTION_DEBUG critsect_debug = | |
| { | |
| 0, 0, &USER_SysLevel.crst, | |
| { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, | |
| 0, 0, { 0, (DWORD)(__FILE__ ": USER_SysLevel") } | |
| }; | |
| static SYSLEVEL USER_SysLevel = { { &critsect_debug, -1, 0, 0, 0, 0 }, 2 }; | |
| static HPALETTE (WINAPI *pfnGDISelectPalette)( HDC hdc, HPALETTE hpal, WORD bkgnd ); | |
| static UINT (WINAPI *pfnGDIRealizePalette)( HDC hdc ); | |
| static HPALETTE hPrimaryPalette; | |
| static DWORD exiting_thread_id; | |
| extern void WDML_NotifyThreadDetach(void); | |
| /*********************************************************************** | |
| * USER_Lock | |
| */ | |
| void USER_Lock(void) | |
| { | |
| _EnterSysLevel( &USER_SysLevel ); | |
| } | |
| /*********************************************************************** | |
| * USER_Unlock | |
| */ | |
| void USER_Unlock(void) | |
| { | |
| _LeaveSysLevel( &USER_SysLevel ); | |
| } | |
| /*********************************************************************** | |
| * USER_CheckNotLock | |
| * | |
| * Make sure that we don't hold the user lock. | |
| */ | |
| void USER_CheckNotLock(void) | |
| { | |
| _CheckNotSysLevel( &USER_SysLevel ); | |
| } | |
| /*********************************************************************** | |
| * UserSelectPalette (Not a Windows API) | |
| */ | |
| static HPALETTE WINAPI UserSelectPalette( HDC hDC, HPALETTE hPal, BOOL bForceBackground ) | |
| { | |
| WORD wBkgPalette = 1; | |
| if (!bForceBackground && (hPal != GetStockObject(DEFAULT_PALETTE))) | |
| { | |
| HWND hwnd = WindowFromDC( hDC ); | |
| if (hwnd) | |
| { | |
| HWND hForeground = GetForegroundWindow(); | |
| /* set primary palette if it's related to current active */ | |
| if (hForeground == hwnd || IsChild(hForeground,hwnd)) | |
| { | |
| wBkgPalette = 0; | |
| hPrimaryPalette = hPal; | |
| } | |
| } | |
| } | |
| return pfnGDISelectPalette( hDC, hPal, wBkgPalette); | |
| } | |
| /*********************************************************************** | |
| * UserRealizePalette (USER32.@) | |
| */ | |
| UINT WINAPI UserRealizePalette( HDC hDC ) | |
| { | |
| UINT realized = pfnGDIRealizePalette( hDC ); | |
| /* do not send anything if no colors were changed */ | |
| if (realized && GetCurrentObject( hDC, OBJ_PAL ) == hPrimaryPalette) | |
| { | |
| /* send palette change notification */ | |
| HWND hWnd = WindowFromDC( hDC ); | |
| if (hWnd) SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0, | |
| SMTO_ABORTIFHUNG, 2000, NULL ); | |
| } | |
| return realized; | |
| } | |
| /*********************************************************************** | |
| * palette_init | |
| * | |
| * Patch the function pointers in GDI for SelectPalette and RealizePalette | |
| */ | |
| static void palette_init(void) | |
| { | |
| void **ptr; | |
| HMODULE module = GetModuleHandleA( "gdi32" ); | |
| if (!module) | |
| { | |
| ERR( "cannot get GDI32 handle\n" ); | |
| return; | |
| } | |
| if ((ptr = (void**)GetProcAddress( module, "pfnSelectPalette" ))) | |
| pfnGDISelectPalette = InterlockedExchangePointer( ptr, UserSelectPalette ); | |
| else ERR( "cannot find pfnSelectPalette in GDI32\n" ); | |
| if ((ptr = (void**)GetProcAddress( module, "pfnRealizePalette" ))) | |
| pfnGDIRealizePalette = InterlockedExchangePointer( ptr, UserRealizePalette ); | |
| else ERR( "cannot find pfnRealizePalette in GDI32\n" ); | |
| } | |
| /*********************************************************************** | |
| * USER initialisation routine | |
| */ | |
| static BOOL process_attach(void) | |
| { | |
| HINSTANCE16 instance; | |
| /* Create USER heap */ | |
| if ((instance = LoadLibrary16( "USER.EXE" )) >= 32) USER_HeapSel = instance | 7; | |
| else | |
| { | |
| USER_HeapSel = GlobalAlloc16( GMEM_FIXED, 65536 ); | |
| LocalInit16( USER_HeapSel, 32, 65534 ); | |
| } | |
| /* some Win9x dlls expect keyboard to be loaded */ | |
| if (GetVersion() & 0x80000000) LoadLibrary16( "keyboard.drv" ); | |
| /* Initialize system colors and metrics */ | |
| SYSPARAMS_Init(); | |
| /* Setup palette function pointers */ | |
| palette_init(); | |
| /* Initialize built-in window classes */ | |
| CLASS_RegisterBuiltinClasses(); | |
| /* Initialize message spying */ | |
| if (!SPY_Init()) return FALSE; | |
| return TRUE; | |
| } | |
| /********************************************************************** | |
| * USER_IsExitingThread | |
| */ | |
| BOOL USER_IsExitingThread( DWORD tid ) | |
| { | |
| return (tid == exiting_thread_id); | |
| } | |
| /********************************************************************** | |
| * thread_detach | |
| */ | |
| static void thread_detach(void) | |
| { | |
| exiting_thread_id = GetCurrentThreadId(); | |
| WDML_NotifyThreadDetach(); | |
| WIN_DestroyThreadWindows( GetDesktopWindow() ); | |
| CloseHandle( get_user_thread_info()->server_queue ); | |
| exiting_thread_id = 0; | |
| } | |
| /*********************************************************************** | |
| * UserClientDllInitialize (USER32.@) | |
| * | |
| * USER dll initialisation routine (exported as UserClientDllInitialize for compatibility). | |
| */ | |
| BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) | |
| { | |
| BOOL ret = TRUE; | |
| switch(reason) | |
| { | |
| case DLL_PROCESS_ATTACH: | |
| user32_module = inst; | |
| ret = process_attach(); | |
| break; | |
| case DLL_THREAD_DETACH: | |
| thread_detach(); | |
| break; | |
| case DLL_PROCESS_DETACH: | |
| USER_unload_driver(); | |
| break; | |
| } | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * USER_GetProcessHandleList(Internal) | |
| */ | |
| static HANDLE *USER_GetProcessHandleList(void) | |
| { | |
| DWORD count, i, n; | |
| HANDLE *list; | |
| PROCESSENTRY32 pe; | |
| HANDLE hSnapshot; | |
| BOOL r; | |
| hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); | |
| if (!hSnapshot) | |
| { | |
| ERR("cannot create snapshot\n"); | |
| return FALSE; | |
| } | |
| /* count the number of processes plus one */ | |
| for (count=0; ;count++) | |
| { | |
| pe.dwSize = sizeof pe; | |
| if (count) | |
| r = Process32Next( hSnapshot, &pe ); | |
| else | |
| r = Process32First( hSnapshot, &pe ); | |
| if (!r) | |
| break; | |
| } | |
| /* allocate memory make a list of the process handles */ | |
| list = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof(HANDLE) ); | |
| n=0; | |
| for (i=0; i<count; i++) | |
| { | |
| pe.dwSize = sizeof pe; | |
| if (i) | |
| r = Process32Next( hSnapshot, &pe ); | |
| else | |
| r = Process32First( hSnapshot, &pe ); | |
| if (!r) | |
| break; | |
| /* don't kill ourselves */ | |
| if (GetCurrentProcessId() == pe.th32ProcessID ) | |
| continue; | |
| /* open the process so we don't can track it */ | |
| list[n] = OpenProcess( PROCESS_QUERY_INFORMATION| | |
| PROCESS_TERMINATE, | |
| FALSE, pe.th32ProcessID ); | |
| /* check it didn't terminate already */ | |
| if( list[n] ) | |
| n++; | |
| } | |
| list[n]=0; | |
| CloseHandle( hSnapshot ); | |
| if (!r) | |
| ERR("Error enumerating processes\n"); | |
| TRACE("return %lu processes\n", n); | |
| return list; | |
| } | |
| /*********************************************************************** | |
| * USER_KillProcesses (Internal) | |
| */ | |
| static DWORD USER_KillProcesses(void) | |
| { | |
| DWORD n, r, i; | |
| HANDLE *handles; | |
| const DWORD dwShutdownTimeout = 10000; | |
| TRACE("terminating other processes\n"); | |
| /* kill it and add it to our list of object to wait on */ | |
| handles = USER_GetProcessHandleList(); | |
| for (n=0; handles && handles[n]; n++) | |
| TerminateProcess( handles[n], 0 ); | |
| /* wait for processes to exit */ | |
| for (i=0; i<n; i+=MAXIMUM_WAIT_OBJECTS) | |
| { | |
| int n_objs = ((n-i)>MAXIMUM_WAIT_OBJECTS) ? MAXIMUM_WAIT_OBJECTS : (n-i); | |
| r = WaitForMultipleObjects( n_objs, &handles[i], TRUE, dwShutdownTimeout ); | |
| if (r==WAIT_TIMEOUT) | |
| ERR("wait failed!\n"); | |
| } | |
| /* close the handles */ | |
| for (i=0; i<n; i++) | |
| CloseHandle( handles[i] ); | |
| HeapFree( GetProcessHeap(), 0, handles ); | |
| return n; | |
| } | |
| /*********************************************************************** | |
| * USER_DoShutdown (Internal) | |
| */ | |
| static void USER_DoShutdown(void) | |
| { | |
| DWORD i, n; | |
| const DWORD nRetries = 10; | |
| for (i=0; i<nRetries; i++) | |
| { | |
| n = USER_KillProcesses(); | |
| TRACE("Killed %ld processes, attempt %ld\n", n, i); | |
| if(!n) | |
| break; | |
| } | |
| } | |
| /*********************************************************************** | |
| * ExitWindowsEx (USER32.@) | |
| */ | |
| BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reserved ) | |
| { | |
| int i; | |
| BOOL result = FALSE; | |
| HWND *list, *phwnd; | |
| /* We have to build a list of all windows first, as in EnumWindows */ | |
| TRACE("(%x,%lx)\n", flags, reserved); | |
| list = WIN_ListChildren( GetDesktopWindow() ); | |
| if (list) | |
| { | |
| /* Send a WM_QUERYENDSESSION message to every window */ | |
| for (i = 0; list[i]; i++) | |
| { | |
| /* Make sure that the window still exists */ | |
| if (!IsWindow( list[i] )) continue; | |
| if (!SendMessageW( list[i], WM_QUERYENDSESSION, 0, 0 )) break; | |
| } | |
| result = !list[i]; | |
| /* Now notify all windows that got a WM_QUERYENDSESSION of the result */ | |
| for (phwnd = list; i > 0; i--, phwnd++) | |
| { | |
| if (!IsWindow( *phwnd )) continue; | |
| SendMessageW( *phwnd, WM_ENDSESSION, result, 0 ); | |
| } | |
| HeapFree( GetProcessHeap(), 0, list ); | |
| if ( !(result || (flags & EWX_FORCE) )) | |
| return FALSE; | |
| } | |
| /* USER_DoShutdown will kill all processes except the current process */ | |
| USER_DoShutdown(); | |
| if (flags & EWX_REBOOT) | |
| { | |
| WCHAR winebootW[] = { 'w','i','n','e','b','o','o','t',0 }; | |
| PROCESS_INFORMATION pi; | |
| STARTUPINFOW si; | |
| memset( &si, 0, sizeof si ); | |
| si.cb = sizeof si; | |
| if (CreateProcessW( NULL, winebootW, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi )) | |
| { | |
| CloseHandle( pi.hProcess ); | |
| CloseHandle( pi.hThread ); | |
| } | |
| else | |
| MESSAGE("wine: Failed to start wineboot\n"); | |
| } | |
| if (result) ExitProcess(0); | |
| return TRUE; | |
| } |