2 * USER initialization code
4 * Copyright 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "user_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(graphics
);
36 #define DESKTOP_ALL_ACCESS 0x01ff
38 HMODULE user32_module
= 0;
40 static CRITICAL_SECTION user_section
;
41 static CRITICAL_SECTION_DEBUG critsect_debug
=
44 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
45 0, 0, { (DWORD_PTR
)(__FILE__
": user_section") }
47 static CRITICAL_SECTION user_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
49 static HPALETTE (WINAPI
*pfnGDISelectPalette
)( HDC hdc
, HPALETTE hpal
, WORD bkgnd
);
50 static UINT (WINAPI
*pfnGDIRealizePalette
)( HDC hdc
);
51 static HPALETTE hPrimaryPalette
;
53 static DWORD exiting_thread_id
;
55 extern void WDML_NotifyThreadDetach(void);
58 /* work around a Mingw build issue where _wassert causes a duplicate reference to MessageBoxW */
59 void __cdecl
_wassert( const WCHAR
*msg
, const WCHAR
*file
, unsigned line
) { abort(); }
62 /***********************************************************************
67 EnterCriticalSection( &user_section
);
71 /***********************************************************************
74 void USER_Unlock(void)
76 LeaveCriticalSection( &user_section
);
80 /***********************************************************************
83 * Make sure that we don't hold the user lock.
85 void USER_CheckNotLock(void)
87 if (RtlIsCriticalSectionLockedByThread(&user_section
))
89 ERR( "BUG: holding USER lock\n" );
95 /***********************************************************************
96 * UserSelectPalette (Not a Windows API)
98 static HPALETTE WINAPI
UserSelectPalette( HDC hDC
, HPALETTE hPal
, BOOL bForceBackground
)
100 WORD wBkgPalette
= 1;
102 if (!bForceBackground
&& (hPal
!= GetStockObject(DEFAULT_PALETTE
)))
104 HWND hwnd
= WindowFromDC( hDC
);
107 HWND hForeground
= GetForegroundWindow();
108 /* set primary palette if it's related to current active */
109 if (hForeground
== hwnd
|| IsChild(hForeground
,hwnd
))
112 hPrimaryPalette
= hPal
;
116 return pfnGDISelectPalette( hDC
, hPal
, wBkgPalette
);
120 /***********************************************************************
121 * UserRealizePalette (USER32.@)
123 UINT WINAPI
UserRealizePalette( HDC hDC
)
125 UINT realized
= pfnGDIRealizePalette( hDC
);
127 /* do not send anything if no colors were changed */
128 if (realized
&& GetCurrentObject( hDC
, OBJ_PAL
) == hPrimaryPalette
)
130 /* send palette change notification */
131 HWND hWnd
= WindowFromDC( hDC
);
132 if (hWnd
) SendMessageTimeoutW( HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0,
133 SMTO_ABORTIFHUNG
, 2000, NULL
);
139 /***********************************************************************
142 * Patch the function pointers in GDI for SelectPalette and RealizePalette
144 static void palette_init(void)
147 HMODULE module
= GetModuleHandleA( "gdi32" );
150 ERR( "cannot get GDI32 handle\n" );
153 if ((ptr
= (void**)GetProcAddress( module
, "pfnSelectPalette" )))
154 pfnGDISelectPalette
= InterlockedExchangePointer( ptr
, UserSelectPalette
);
155 else ERR( "cannot find pfnSelectPalette in GDI32\n" );
156 if ((ptr
= (void**)GetProcAddress( module
, "pfnRealizePalette" )))
157 pfnGDIRealizePalette
= InterlockedExchangePointer( ptr
, UserRealizePalette
);
158 else ERR( "cannot find pfnRealizePalette in GDI32\n" );
162 /***********************************************************************
163 * get_default_desktop
165 * Get the name of the desktop to use for this app if not specified explicitly.
167 static const WCHAR
*get_default_desktop(void)
169 static WCHAR buffer
[MAX_PATH
+ ARRAY_SIZE(L
"\\Explorer")];
170 WCHAR
*p
, *appname
= buffer
;
171 const WCHAR
*ret
= NULL
;
175 len
= (GetModuleFileNameW( 0, buffer
, MAX_PATH
));
176 if (!len
|| len
>= MAX_PATH
) return L
"Default";
177 if ((p
= wcsrchr( appname
, '/' ))) appname
= p
+ 1;
178 if ((p
= wcsrchr( appname
, '\\' ))) appname
= p
+ 1;
179 p
= appname
+ lstrlenW(appname
);
180 lstrcpyW( p
, L
"\\Explorer" );
182 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Explorer */
183 if (!RegOpenKeyW( HKEY_CURRENT_USER
, L
"Software\\Wine\\AppDefaults", &tmpkey
))
185 if (RegOpenKeyW( tmpkey
, appname
, &appkey
)) appkey
= 0;
186 RegCloseKey( tmpkey
);
189 len
= sizeof(buffer
);
190 if (!RegQueryValueExW( appkey
, L
"Desktop", 0, NULL
, (LPBYTE
)buffer
, &len
)) ret
= buffer
;
191 RegCloseKey( appkey
);
192 if (ret
&& *ret
) return ret
;
197 /* @@ Wine registry key: HKCU\Software\Wine\Explorer */
198 if (!RegOpenKeyW( HKEY_CURRENT_USER
, L
"Software\\Wine\\Explorer", &appkey
))
200 len
= sizeof(buffer
);
201 if (!RegQueryValueExW( appkey
, L
"Desktop", 0, NULL
, (LPBYTE
)buffer
, &len
)) ret
= buffer
;
202 RegCloseKey( appkey
);
203 if (ret
&& *ret
) return ret
;
209 /***********************************************************************
212 * Initialize the DPI awareness style.
214 static void dpiaware_init(void)
219 if (!LdrQueryImageFileExecutionOptions( &NtCurrentTeb()->Peb
->ProcessParameters
->ImagePathName
,
220 L
"dpiAwareness", REG_DWORD
, &option
, sizeof(option
), NULL
))
222 TRACE( "got option %x\n", option
);
225 SetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT
)~(ULONG_PTR
)option
);
230 if (QueryActCtxSettingsW( 0, NULL
, L
"http://schemas.microsoft.com/SMI/2016/WindowsSettings",
231 L
"dpiAwareness", buffer
, ARRAY_SIZE(buffer
), NULL
))
233 static const WCHAR
* const types
[] = { L
"unaware", L
"system", L
"permonitor", L
"permonitorv2" };
234 WCHAR
*p
, *start
, *end
;
237 TRACE( "got dpiAwareness=%s\n", debugstr_w(buffer
) );
238 for (start
= buffer
; *start
; start
= end
)
240 start
+= wcsspn( start
, L
" \t\r\n" );
241 if (!(end
= wcschr( start
, ',' ))) end
= start
+ lstrlenW(start
);
243 if ((p
= wcspbrk( start
, L
" \t\r\n" ))) *p
= 0;
244 for (i
= 0; i
< ARRAY_SIZE(types
); i
++)
246 if (wcsicmp( start
, types
[i
] )) continue;
247 SetProcessDpiAwarenessContext( (DPI_AWARENESS_CONTEXT
)~i
);
252 else if (QueryActCtxSettingsW( 0, NULL
, L
"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
253 L
"dpiAware", buffer
, ARRAY_SIZE(buffer
), NULL
))
255 TRACE( "got dpiAware=%s\n", debugstr_w(buffer
) );
256 if (!wcsicmp( buffer
, L
"true" ))
257 SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
);
258 else if (!wcsicmp( buffer
, L
"true/pm" ) || !wcsicmp( buffer
, L
"per monitor" ))
259 SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
261 SetProcessDpiAwarenessContext( DPI_AWARENESS_CONTEXT_UNAWARE
);
266 /***********************************************************************
269 * Connect to the process window station and desktop.
271 static void winstation_init(void)
274 WCHAR
*winstation
= NULL
, *desktop
= NULL
, *buffer
= NULL
;
277 GetStartupInfoW( &info
);
278 if (info
.lpDesktop
&& *info
.lpDesktop
)
280 buffer
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW(info
.lpDesktop
) + 1) * sizeof(WCHAR
) );
281 lstrcpyW( buffer
, info
.lpDesktop
);
282 if ((desktop
= wcschr( buffer
, '\\' )))
287 else desktop
= buffer
;
290 /* set winstation if explicitly specified, or if we don't have one yet */
291 if (buffer
|| !GetProcessWindowStation())
293 handle
= CreateWindowStationW( winstation
? winstation
: L
"WinSta0", 0, WINSTA_ALL_ACCESS
, NULL
);
296 SetProcessWindowStation( handle
);
297 /* only WinSta0 is visible */
298 if (!winstation
|| !wcsicmp( winstation
, L
"WinSta0" ))
300 USEROBJECTFLAGS flags
;
301 flags
.fInherit
= FALSE
;
302 flags
.fReserved
= FALSE
;
303 flags
.dwFlags
= WSF_VISIBLE
;
304 SetUserObjectInformationW( handle
, UOI_FLAGS
, &flags
, sizeof(flags
) );
308 if (buffer
|| !GetThreadDesktop( GetCurrentThreadId() ))
310 handle
= CreateDesktopW( desktop
? desktop
: get_default_desktop(),
311 NULL
, NULL
, 0, DESKTOP_ALL_ACCESS
, NULL
);
312 if (handle
) SetThreadDesktop( handle
);
314 HeapFree( GetProcessHeap(), 0, buffer
);
316 register_desktop_class();
320 /***********************************************************************
321 * USER initialisation routine
323 static BOOL
process_attach(void)
328 /* Initialize system colors and metrics */
331 /* Setup palette function pointers */
338 /**********************************************************************
339 * USER_IsExitingThread
341 BOOL
USER_IsExitingThread( DWORD tid
)
343 return (tid
== exiting_thread_id
);
347 /**********************************************************************
350 static void thread_detach(void)
352 struct user_thread_info
*thread_info
= get_user_thread_info();
354 exiting_thread_id
= GetCurrentThreadId();
356 WDML_NotifyThreadDetach();
357 USER_Driver
->pThreadDetach();
359 destroy_thread_windows();
360 CloseHandle( thread_info
->server_queue
);
361 HeapFree( GetProcessHeap(), 0, thread_info
->wmchar_data
);
362 HeapFree( GetProcessHeap(), 0, thread_info
->key_state
);
363 HeapFree( GetProcessHeap(), 0, thread_info
->rawinput
);
365 exiting_thread_id
= 0;
369 /***********************************************************************
370 * UserClientDllInitialize (USER32.@)
372 * USER dll initialisation routine (exported as UserClientDllInitialize for compatibility).
374 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, LPVOID reserved
)
376 static HMODULE imm32_module
;
381 case DLL_PROCESS_ATTACH
:
382 user32_module
= inst
;
383 ret
= process_attach();
385 imm32_module
= LoadLibraryW(L
"imm32.dll");
387 case DLL_THREAD_DETACH
:
390 case DLL_PROCESS_DETACH
:
391 USER_unload_driver();
392 FreeLibrary(imm32_module
);
393 DeleteCriticalSection(&user_section
);
400 /***********************************************************************
401 * ExitWindowsEx (USER32.@)
403 BOOL WINAPI
ExitWindowsEx( UINT flags
, DWORD reason
)
406 WCHAR cmdline
[MAX_PATH
+ 64];
407 PROCESS_INFORMATION pi
;
411 GetSystemDirectoryW( app
, MAX_PATH
- ARRAY_SIZE( L
"\\wineboot.exe" ));
412 lstrcatW( app
, L
"\\wineboot.exe" );
413 lstrcpyW( cmdline
, app
);
415 if (flags
& EWX_FORCE
) lstrcatW( cmdline
, L
" --kill" );
418 lstrcatW( cmdline
, L
" --end-session" );
419 if (flags
& EWX_FORCEIFHUNG
) lstrcatW( cmdline
, L
" --force" );
421 if (!(flags
& EWX_REBOOT
)) lstrcatW( cmdline
, L
" --shutdown" );
423 memset( &si
, 0, sizeof si
);
425 Wow64DisableWow64FsRedirection( &redir
);
426 if (!CreateProcessW( app
, cmdline
, NULL
, NULL
, FALSE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
428 Wow64RevertWow64FsRedirection( redir
);
429 ERR( "Failed to run %s\n", debugstr_w(cmdline
) );
432 Wow64RevertWow64FsRedirection( redir
);
433 CloseHandle( pi
.hProcess
);
434 CloseHandle( pi
.hThread
);
438 /***********************************************************************
439 * LockWorkStation (USER32.@)
441 BOOL WINAPI
LockWorkStation(void)
444 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
448 /***********************************************************************
449 * RegisterServicesProcess (USER32.@)
451 int WINAPI
RegisterServicesProcess(DWORD ServicesProcessId
)
453 FIXME("(0x%x): stub\n", ServicesProcessId
);
457 /***********************************************************************
458 * ShutdownBlockReasonCreate (USER32.@)
460 BOOL WINAPI
ShutdownBlockReasonCreate(HWND hwnd
, LPCWSTR reason
)
462 FIXME("(%p, %s): stub\n", hwnd
, debugstr_w(reason
));
463 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
467 /***********************************************************************
468 * ShutdownBlockReasonDestroy (USER32.@)
470 BOOL WINAPI
ShutdownBlockReasonDestroy(HWND hwnd
)
472 FIXME("(%p): stub\n", hwnd
);
473 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);