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