user: Defer all ExitWindowsEx processing to wineboot.
This commit is contained in:
parent
54da7fb8cf
commit
8653598a66
|
@ -26,7 +26,6 @@
|
|||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winreg.h"
|
||||
#include "tlhelp32.h"
|
||||
|
||||
#include "controls.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.@)
|
||||
*/
|
||||
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,
|
||||
MAKEWPARAM( flags, 0xbabe ), reason);
|
||||
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 */
|
||||
lstrcatW( cmdline, end_sessionW );
|
||||
if (flags & EWX_FORCEIFHUNG) lstrcatW( cmdline, forceW );
|
||||
}
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
ERR( "Failed to run %s\n", debugstr_w(cmdline) );
|
||||
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");
|
||||
}
|
||||
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -64,13 +64,6 @@ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPAR
|
|||
}
|
||||
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:
|
||||
return DefWindowProcW( hwnd, message, wp, lp );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue