USER32: kill all wine processes when doing ExitWindowsEx (take 2)
Mike McCormack
mike at codeweavers.com
Thu Oct 28 04:36:14 CDT 2004
Added a fix for killing more than MAXIMUM_WAIT_OBJECTS processes.
Close the process handles properly.
Mike
ChangeLog:
* kill all wine processes when doing ExitWindowsEx
-------------- next part --------------
Index: windows/user.c
===================================================================
RCS file: /home/wine/wine/windows/user.c,v
retrieving revision 1.101
diff -u -r1.101 user.c
--- windows/user.c 5 Mar 2004 20:44:15 -0000 1.101
+++ windows/user.c 28 Oct 2004 08:39:20 -0000
@@ -30,6 +30,7 @@
#include "wine/winuser16.h"
#include "winreg.h"
#include "winternl.h"
+#include "tlhelp32.h"
#include "user.h"
#include "win.h"
#include "controls.h"
@@ -294,6 +295,140 @@
/***********************************************************************
+ * USER_GetProcessIdList(Internal)
+ */
+static DWORD *USER_GetProcessIdList(DWORD *pdwNum)
+{
+ DWORD count, *list, i;
+ PROCESSENTRY32 pe;
+ HANDLE hSnapshot;
+ BOOL r;
+
+ TRACE("%p\n", pdwNum);
+
+ hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+ if (!hSnapshot)
+ {
+ ERR("cannot create snapshot\n");
+ return FALSE;
+ }
+
+ /* count the number of processes */
+ count = 0;
+ memset( &pe, 0, sizeof pe );
+ pe.dwSize = sizeof pe;
+ r = Process32First( hSnapshot, &pe );
+ while (r)
+ {
+ count++;
+ memset( &pe, 0, sizeof pe );
+ pe.dwSize = sizeof pe;
+ r = Process32Next( hSnapshot, &pe );
+ }
+
+ /* allocate memory make a list of the process ids */
+ list = HeapAlloc(GetProcessHeap(), 0, count*sizeof(DWORD) );
+ for (i=0; i<count; i++)
+ {
+ memset( &pe, 0, sizeof pe );
+ pe.dwSize = sizeof pe;
+ if (i)
+ r = Process32Next( hSnapshot, &pe );
+ else
+ r = Process32First( hSnapshot, &pe );
+ if (!r)
+ break;
+ list[i] = pe.th32ProcessID;
+ }
+ CloseHandle( hSnapshot );
+
+ if (!r)
+ {
+ ERR("Error enumerating processes\n");
+ HeapFree( GetProcessHeap(), 0, list);
+ return NULL;
+ }
+
+ TRACE("return %lu processes\n", count);
+ *pdwNum = count;
+
+ return list;
+}
+
+/***********************************************************************
+ * USER_KillProcesses (Internal)
+ */
+static DWORD USER_KillProcesses(void)
+{
+ DWORD *ids, num, r, i, n;
+ HANDLE *handles;
+ const DWORD dwShutdownTimeout = 10000;
+
+ TRACE("terminating other processes\n");
+
+ num = 0;
+ ids = USER_GetProcessIdList( &num );
+ handles = HeapAlloc( GetProcessHeap(), 0, num*sizeof(HANDLE) );
+
+ n = 0;
+ for (i=0; i<num; i++)
+ {
+ /* don't kill outselves */
+ if (GetCurrentProcessId() == ids[i] )
+ continue;
+
+ /* open the process so we don't can track it */
+ handles[n] = OpenProcess( PROCESS_QUERY_INFORMATION|
+ PROCESS_TERMINATE,
+ FALSE, ids[i] );
+
+ /* check it didn't terminate already */
+ if( handles[n] == NULL )
+ continue;
+
+ /* kill it and add it to our list of object to wait on */
+ TRACE("killing process id %08lx\n", ids[i]);
+ TerminateProcess( handles[n], 0 );
+ n++;
+ }
+
+ /* 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 );
+ HeapFree( GetProcessHeap(), 0, ids );
+
+ 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 reserved )
@@ -325,6 +460,9 @@
}
HeapFree( GetProcessHeap(), 0, list );
+ /* USER_DoShutdown will kill all processes except the current process */
+ USER_DoShutdown();
+
if (result) ExitKernel16();
return TRUE;
}
More information about the wine-patches
mailing list