/*********************************************************************** * ExitWindowsEx (USER32.@) */ BOOL WINAPI ExitWindowsEx( UINT flags, DWORD reserved ) { int i; BOOL result; HWND *list, *phwnd; /* We have to build a list of all windows first, as in EnumWindows */ if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE; /* Send a WM_QUERYENDSESSION message to every window */ for (i = 0; list[i]; i++) { /* Make sure that the window still exists */ if (!IsWindow( list[i] )) continue; if (!SendMessageW( list[i], WM_QUERYENDSESSION, 0, 0 )) break; } result = !list[i]; /* Now notify all windows that got a WM_QUERYENDSESSION of the result */ for (phwnd = list; i > 0; i--, phwnd++) { if (!IsWindow( *phwnd )) continue; SendMessageW( *phwnd, WM_ENDSESSION, result, 0 ); } HeapFree( GetProcessHeap(), 0, list ); if (result) ExitKernel16(); return FALSE; }
/*********************************************************************** * TASK_ExitTask */ void TASK_ExitTask(void) { WIN16_SUBSYSTEM_TIB *tib; TDB *pTask; DWORD lockCount; /* Enter the Win16Lock to protect global data structures */ _EnterWin16Lock(); pTask = TASK_GetCurrent(); if ( !pTask ) { _LeaveWin16Lock(); return; } TRACE("Killing task %04x\n", pTask->hSelf ); /* Perform USER cleanup */ TASK_CallTaskSignalProc( USIG16_TERMINATION, pTask->hSelf ); /* Remove the task from the list to be sure we never switch back to it */ TASK_UnlinkTask( pTask->hSelf ); if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task)) { TRACE("this is the last task, exiting\n" ); ExitKernel16(); } pTask->nEvents = 0; if ( hLockedTask == pTask->hSelf ) hLockedTask = 0; TASK_DeleteTask( pTask->hSelf ); if ((tib = NtCurrentTeb()->Tib.SubSystemTib)) { free_win16_tib( tib ); NtCurrentTeb()->Tib.SubSystemTib = NULL; } /* ... and completely release the Win16Lock, just in case. */ ReleaseThunkLock( &lockCount ); }