| /* | |
| * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "controls.h" | |
| #include "user_private.h" | |
| #include "win.h" | |
| #include "wine/unicode.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(graphics); | |
| #define DESKTOP_ALL_ACCESS 0x01ff | |
| HMODULE user32_module = 0; | |
| static CRITICAL_SECTION user_section; | |
| static CRITICAL_SECTION_DEBUG critsect_debug = | |
| { | |
| 0, 0, &user_section, | |
| { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, | |
| 0, 0, { (DWORD_PTR)(__FILE__ ": user_section") } | |
| }; | |
| static CRITICAL_SECTION user_section = { &critsect_debug, -1, 0, 0, 0, 0 }; | |
| 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) | |
| { | |
| EnterCriticalSection( &user_section ); | |
| } | |
| /*********************************************************************** | |
| * USER_Unlock | |
| */ | |
| void USER_Unlock(void) | |
| { | |
| LeaveCriticalSection( &user_section ); | |
| } | |
| /*********************************************************************** | |
| * USER_CheckNotLock | |
| * | |
| * Make sure that we don't hold the user lock. | |
| */ | |
| void USER_CheckNotLock(void) | |
| { | |
| if (user_section.OwningThread == ULongToHandle(GetCurrentThreadId()) && user_section.RecursionCount) | |
| { | |
| ERR( "BUG: holding USER lock\n" ); | |
| DebugBreak(); | |
| } | |
| } | |
| /*********************************************************************** | |
| * 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" ); | |
| } | |
| /*********************************************************************** | |
| * get_default_desktop | |
| * | |
| * Get the name of the desktop to use for this app if not specified explicitly. | |
| */ | |
| static const WCHAR *get_default_desktop(void) | |
| { | |
| static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0}; | |
| static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0}; | |
| static const WCHAR explorerW[] = {'\\','E','x','p','l','o','r','e','r',0}; | |
| static const WCHAR app_defaultsW[] = {'S','o','f','t','w','a','r','e','\\', | |
| 'W','i','n','e','\\', | |
| 'A','p','p','D','e','f','a','u','l','t','s',0}; | |
| static WCHAR buffer[MAX_PATH + sizeof(explorerW)/sizeof(WCHAR)]; | |
| WCHAR *p, *appname = buffer; | |
| const WCHAR *ret = defaultW; | |
| DWORD len; | |
| HKEY tmpkey, appkey; | |
| len = (GetModuleFileNameW( 0, buffer, MAX_PATH )); | |
| if (!len || len >= MAX_PATH) return ret; | |
| if ((p = strrchrW( appname, '/' ))) appname = p + 1; | |
| if ((p = strrchrW( appname, '\\' ))) appname = p + 1; | |
| p = appname + strlenW(appname); | |
| strcpyW( p, explorerW ); | |
| /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Explorer */ | |
| if (!RegOpenKeyW( HKEY_CURRENT_USER, app_defaultsW, &tmpkey )) | |
| { | |
| if (RegOpenKeyW( tmpkey, appname, &appkey )) appkey = 0; | |
| RegCloseKey( tmpkey ); | |
| if (appkey) | |
| { | |
| len = sizeof(buffer); | |
| if (!RegQueryValueExW( appkey, desktopW, 0, NULL, (LPBYTE)buffer, &len )) ret = buffer; | |
| RegCloseKey( appkey ); | |
| if (ret && strcmpiW( ret, defaultW )) return ret; | |
| ret = defaultW; | |
| } | |
| } | |
| memcpy( buffer, app_defaultsW, 13 * sizeof(WCHAR) ); /* copy only software\\wine */ | |
| strcpyW( buffer + 13, explorerW ); | |
| /* @@ Wine registry key: HKCU\Software\Wine\Explorer */ | |
| if (!RegOpenKeyW( HKEY_CURRENT_USER, buffer, &appkey )) | |
| { | |
| len = sizeof(buffer); | |
| if (!RegQueryValueExW( appkey, desktopW, 0, NULL, (LPBYTE)buffer, &len )) ret = buffer; | |
| RegCloseKey( appkey ); | |
| } | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * winstation_init | |
| * | |
| * Connect to the process window station and desktop. | |
| */ | |
| static void winstation_init(void) | |
| { | |
| static const WCHAR WinSta0[] = {'W','i','n','S','t','a','0',0}; | |
| STARTUPINFOW info; | |
| WCHAR *winstation = NULL, *desktop = NULL, *buffer = NULL; | |
| HANDLE handle; | |
| GetStartupInfoW( &info ); | |
| if (info.lpDesktop && *info.lpDesktop) | |
| { | |
| buffer = HeapAlloc( GetProcessHeap(), 0, (strlenW(info.lpDesktop) + 1) * sizeof(WCHAR) ); | |
| strcpyW( buffer, info.lpDesktop ); | |
| if ((desktop = strchrW( buffer, '\\' ))) | |
| { | |
| *desktop++ = 0; | |
| winstation = buffer; | |
| } | |
| else desktop = buffer; | |
| } | |
| /* set winstation if explicitly specified, or if we don't have one yet */ | |
| if (buffer || !GetProcessWindowStation()) | |
| { | |
| handle = CreateWindowStationW( winstation ? winstation : WinSta0, 0, WINSTA_ALL_ACCESS, NULL ); | |
| if (handle) | |
| { | |
| SetProcessWindowStation( handle ); | |
| /* only WinSta0 is visible */ | |
| if (!winstation || !strcmpiW( winstation, WinSta0 )) | |
| { | |
| USEROBJECTFLAGS flags; | |
| flags.fInherit = FALSE; | |
| flags.fReserved = FALSE; | |
| flags.dwFlags = WSF_VISIBLE; | |
| SetUserObjectInformationW( handle, UOI_FLAGS, &flags, sizeof(flags) ); | |
| } | |
| } | |
| } | |
| if (buffer || !GetThreadDesktop( GetCurrentThreadId() )) | |
| { | |
| handle = CreateDesktopW( desktop ? desktop : get_default_desktop(), | |
| NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); | |
| if (handle) SetThreadDesktop( handle ); | |
| } | |
| HeapFree( GetProcessHeap(), 0, buffer ); | |
| } | |
| /*********************************************************************** | |
| * USER initialisation routine | |
| */ | |
| static BOOL process_attach(void) | |
| { | |
| winstation_init(); | |
| /* 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) | |
| { | |
| struct user_thread_info *thread_info = get_user_thread_info(); | |
| exiting_thread_id = GetCurrentThreadId(); | |
| WDML_NotifyThreadDetach(); | |
| if (thread_info->top_window) WIN_DestroyThreadWindows( thread_info->top_window ); | |
| if (thread_info->msg_window) WIN_DestroyThreadWindows( thread_info->msg_window ); | |
| CloseHandle( thread_info->server_queue ); | |
| HeapFree( GetProcessHeap(), 0, thread_info->wmchar_data ); | |
| 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; | |
| } | |
| /*********************************************************************** | |
| * ExitWindowsEx (USER32.@) | |
| */ | |
| BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reason ) | |
| { | |
| static const WCHAR winebootW[] = { '\\','w','i','n','e','b','o','o','t','.','e','x','e',0 }; | |
| static const WCHAR killW[] = { ' ','-','-','k','i','l','l',0 }; | |
| static const WCHAR end_sessionW[] = { ' ','-','-','e','n','d','-','s','e','s','s','i','o','n',0 }; | |
| static const WCHAR forceW[] = { ' ','-','-','f','o','r','c','e',0 }; | |
| static const WCHAR shutdownW[] = { ' ','-','-','s','h','u','t','d','o','w','n',0 }; | |
| WCHAR app[MAX_PATH]; | |
| WCHAR cmdline[MAX_PATH + 64]; | |
| PROCESS_INFORMATION pi; | |
| STARTUPINFOW si; | |
| GetSystemDirectoryW( app, MAX_PATH - sizeof(winebootW)/sizeof(WCHAR) ); | |
| strcatW( app, winebootW ); | |
| strcpyW( cmdline, app ); | |
| if (flags & EWX_FORCE) lstrcatW( cmdline, killW ); | |
| else | |
| { | |
| lstrcatW( cmdline, end_sessionW ); | |
| if (flags & EWX_FORCEIFHUNG) lstrcatW( cmdline, forceW ); | |
| } | |
| if (!(flags & EWX_REBOOT)) lstrcatW( cmdline, shutdownW ); | |
| memset( &si, 0, sizeof si ); | |
| si.cb = sizeof si; | |
| if (!CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi )) | |
| { | |
| ERR( "Failed to run %s\n", debugstr_w(cmdline) ); | |
| return FALSE; | |
| } | |
| CloseHandle( pi.hProcess ); | |
| CloseHandle( pi.hThread ); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * LockWorkStation (USER32.@) | |
| */ | |
| BOOL WINAPI LockWorkStation(void) | |
| { | |
| TRACE(": stub\n"); | |
| SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); | |
| return FALSE; | |
| } | |
| /*********************************************************************** | |
| * RegisterServicesProcess (USER32.@) | |
| */ | |
| int WINAPI RegisterServicesProcess(DWORD ServicesProcessId) | |
| { | |
| FIXME("(0x%x): stub\n", ServicesProcessId); | |
| return 0; | |
| } |