user: Defer all ExitWindowsEx processing to wineboot.
This commit is contained in:
parent
54da7fb8cf
commit
8653598a66
|
@ -26,7 +26,6 @@
|
||||||
#include "wingdi.h"
|
#include "wingdi.h"
|
||||||
#include "winuser.h"
|
#include "winuser.h"
|
||||||
#include "winreg.h"
|
#include "winreg.h"
|
||||||
#include "tlhelp32.h"
|
|
||||||
|
|
||||||
#include "controls.h"
|
#include "controls.h"
|
||||||
#include "user_private.h"
|
#include "user_private.h"
|
||||||
|
@ -283,202 +282,40 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* 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.@)
|
* ExitWindowsEx (USER32.@)
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reason )
|
BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reason )
|
||||||
{
|
{
|
||||||
TRACE("(%x,%lx)\n", flags, reason);
|
static const WCHAR winebootW[] = { '\\','w','i','n','e','b','o','o','t',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 };
|
||||||
|
|
||||||
if (!WIN_IsCurrentThread( GetDesktopWindow() ))
|
WCHAR cmdline[MAX_PATH + 64];
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
STARTUPINFOW si;
|
||||||
|
|
||||||
|
GetSystemDirectoryW( cmdline, MAX_PATH );
|
||||||
|
lstrcatW( cmdline, winebootW );
|
||||||
|
|
||||||
|
if (flags & EWX_FORCE) lstrcatW( cmdline, killW );
|
||||||
|
else
|
||||||
{
|
{
|
||||||
BOOL ret = PostMessageW( GetDesktopWindow(), WM_USER + 666,
|
lstrcatW( cmdline, end_sessionW );
|
||||||
MAKEWPARAM( flags, 0xbabe ), reason);
|
if (flags & EWX_FORCEIFHUNG) lstrcatW( cmdline, forceW );
|
||||||
if (ret)
|
|
||||||
return TRUE;
|
|
||||||
/* this can happen if explorer hasn't been started or created the
|
|
||||||
* desktop window yet */
|
|
||||||
WARN("PostMessage failed with error %ld\n", GetLastError());
|
|
||||||
/* fall through to doing it in the same process */
|
|
||||||
}
|
}
|
||||||
|
if (!(flags & EWX_REBOOT)) lstrcatW( cmdline, shutdownW );
|
||||||
|
|
||||||
if ((flags & EWX_FORCE) == 0)
|
memset( &si, 0, sizeof si );
|
||||||
|
si.cb = sizeof si;
|
||||||
|
if (!CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ))
|
||||||
{
|
{
|
||||||
HWND *list;
|
ERR( "Failed to run %s\n", debugstr_w(cmdline) );
|
||||||
|
return FALSE;
|
||||||
/* We have to build a list of all windows first, as in EnumWindows */
|
|
||||||
list = WIN_ListChildren( GetDesktopWindow() );
|
|
||||||
if (list)
|
|
||||||
{
|
|
||||||
HWND *phwnd;
|
|
||||||
UINT send_flags;
|
|
||||||
DWORD_PTR result=1;
|
|
||||||
|
|
||||||
/* Send a WM_QUERYENDSESSION / WM_ENDSESSION message pair to
|
|
||||||
* each window. Note: it might be better to send all the
|
|
||||||
* WM_QUERYENDSESSION messages, aggregate the results and then
|
|
||||||
* send all the WM_ENDSESSION messages with the results but
|
|
||||||
* that's not what Windows does.
|
|
||||||
*/
|
|
||||||
send_flags=(flags & EWX_FORCEIFHUNG) ? SMTO_ABORTIFHUNG : SMTO_NORMAL;
|
|
||||||
for (phwnd = list; *phwnd; phwnd++)
|
|
||||||
{
|
|
||||||
/* Make sure that the window still exists */
|
|
||||||
if (!IsWindow( *phwnd )) continue;
|
|
||||||
if (SendMessageTimeoutW( *phwnd, WM_QUERYENDSESSION, 0, 0, send_flags, 0, &result))
|
|
||||||
{
|
|
||||||
DWORD_PTR dummy;
|
|
||||||
SendMessageTimeoutW( *phwnd, WM_ENDSESSION, result, 0, send_flags, 0, &dummy );
|
|
||||||
if (!result) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, list );
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
CloseHandle( pi.hProcess );
|
||||||
/* USER_DoShutdown will kill all processes except the current process */
|
CloseHandle( pi.hThread );
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,13 +64,6 @@ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPAR
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* simple check to prevent applications accidentally triggering the
|
|
||||||
* ExitWindowsEx code if they send random messages to the desktop window */
|
|
||||||
case WM_USER + 666:
|
|
||||||
if (HIWORD(wp) == 0xbabe)
|
|
||||||
return ExitWindowsEx( LOWORD(wp), lp );
|
|
||||||
return DefWindowProcW( hwnd, message, wp, lp );
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DefWindowProcW( hwnd, message, wp, lp );
|
return DefWindowProcW( hwnd, message, wp, lp );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue