user: Defer all ExitWindowsEx processing to wineboot.

This commit is contained in:
Alexandre Julliard 2006-08-17 20:54:21 +02:00
parent 54da7fb8cf
commit 8653598a66
2 changed files with 24 additions and 194 deletions

View File

@ -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() ))
{
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 */
}
if ((flags & EWX_FORCE) == 0)
{
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;
}
}
/* 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 };
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
{
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( NULL, winebootW, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
if (!CreateProcessW( NULL, 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 );
}
else
MESSAGE("wine: Failed to start wineboot\n");
}
return TRUE;
}

View File

@ -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 );
}