[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r3524: When Vidalia exits, kill Firefox and Pidgin (in vidalia/trunk/src: common vidalia)



Author: sjmurdoch
Date: 2009-02-16 17:17:58 -0500 (Mon, 16 Feb 2009)
New Revision: 3524

Modified:
   vidalia/trunk/src/common/win32.cpp
   vidalia/trunk/src/common/win32.h
   vidalia/trunk/src/vidalia/mainwindow.cpp
Log:
When Vidalia exits, kill Firefox and Pidgin

Modified: vidalia/trunk/src/common/win32.cpp
===================================================================
--- vidalia/trunk/src/common/win32.cpp	2009-02-16 04:01:24 UTC (rev 3523)
+++ vidalia/trunk/src/common/win32.cpp	2009-02-16 22:17:58 UTC (rev 3524)
@@ -35,6 +35,8 @@
 typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_fn)(DWORD, DWORD);
 typedef BOOL (WINAPI *Process32First_fn)(HANDLE, LPPROCESSENTRY32);
 typedef BOOL (WINAPI *Process32Next_fn)(HANDLE, LPPROCESSENTRY32);
+typedef BOOL (WINAPI *Thread32First_fn)(HANDLE, LPTHREADENTRY32);
+typedef BOOL (WINAPI *Thread32Next_fn)(HANDLE, LPTHREADENTRY32);
 
 
 /** Finds the location of the "special" Windows folder using the given CSIDL
@@ -150,6 +152,100 @@
   RegCloseKey(key);
 }
 
+/**
+ * Callback for EnumThreadWindows which sends the WM_CLOSE message
+ */
+BOOL CALLBACK closeWindowCallback(HWND hwnd, LPARAM lParam)
+{
+  PostMessage(hwnd, WM_CLOSE, 0, (LPARAM)NULL);
+}
+
+/**
+ * Close process with the specified PID. Sends WM_CLOSE to all
+ * top-level windows, then to all threads. A process snapshot, with
+ * TH32CS_SNAPTHREAD enabled, must be provided.
+ */
+void
+win32_end_process_by_pid(HANDLE hSnapshot, DWORD pid)
+{
+  Thread32First_fn pThread32First;
+  Thread32Next_fn pThread32Next;
+  THREADENTRY32 thread;
+
+  /* Load the tool help functions */
+  pThread32First = (Thread32First_fn)QLibrary::resolve("kernel32", "Thread32First");
+  pThread32Next = (Thread32Next_fn)QLibrary::resolve("kernel32", "Thread32Next");
+
+  if (!pThread32First || !pThread32Next) {
+    qWarning("Unable to load tool help functions. Running process information "
+             "will be unavailable.");
+  }
+
+  /* Iterate through all the threads in the snapshot */
+  thread.dwSize = sizeof(THREADENTRY32);
+  
+  if (pThread32First(hSnapshot, &thread)) {
+    do {
+      /* If the PID matches the target, kill this thread's windows */
+      if (thread.th32OwnerProcessID == pid) {
+        /* Kill all top level windows */
+        EnumThreadWindows(thread.th32ThreadID, &closeWindowCallback, (LPARAM)NULL);
+        /* Kill the thread */
+        PostThreadMessage(thread.th32ThreadID, WM_CLOSE, 0, (LPARAM)NULL);
+      }
+    } while (pThread32Next(hSnapshot, &thread));
+  }
+}
+
+/**
+ * Close all processes started from the specified filename. Sends
+ * WM_CLOSE to all top-level windows, then to all threads. Filename
+ * should be given in lowercase, and comparison is case insensitive.
+ */
+void
+win32_end_process_by_filename(QString filename)
+{
+  CreateToolhelp32Snapshot_fn pCreateToolhelp32Snapshot;
+  Process32First_fn pProcess32First;
+  Process32Next_fn pProcess32Next;
+  HANDLE hSnapshot;
+  PROCESSENTRY32 proc;
+  QString exeFile;
+  DWORD pid;
+
+  /* Load the tool help functions */
+  pCreateToolhelp32Snapshot =
+    (CreateToolhelp32Snapshot_fn)QLibrary::resolve("kernel32", "CreateToolhelp32Snapshot");
+  pProcess32First = (Process32First_fn)QLibrary::resolve("kernel32", "Process32First");
+  pProcess32Next = (Process32Next_fn)QLibrary::resolve("kernel32", "Process32Next");
+
+  if (!pCreateToolhelp32Snapshot || !pProcess32First || !pProcess32Next) {
+    qWarning("Unable to load tool help functions. Running process information "
+             "will be unavailable.");
+  }
+
+  /* Create a snapshot of all active processes */
+  hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
+  if (hSnapshot != INVALID_HANDLE_VALUE) {
+    proc.dwSize = sizeof(PROCESSENTRY32);
+    
+    /* Iterate through all the processes in the snapshot */
+    if (pProcess32First(hSnapshot, &proc)) {
+      do {
+        /* Extract the PID and exe filename from the process record */
+        pid = proc.th32ProcessID;
+        exeFile = QString::fromAscii((const char *)proc.szExeFile);
+
+        /* If the filename matches the target, kill this process */
+        if (exeFile.toLower() == filename) {
+          win32_end_process_by_pid(hSnapshot, pid);
+        }
+      } while (pProcess32Next(hSnapshot, &proc));
+    }
+    CloseHandle(hSnapshot);
+  }
+}
+
 /** Returns a list of all currently active processes, including their pid
  * and exe filename. */
 QHash<qint64, QString>

Modified: vidalia/trunk/src/common/win32.h
===================================================================
--- vidalia/trunk/src/common/win32.h	2009-02-16 04:01:24 UTC (rev 3523)
+++ vidalia/trunk/src/common/win32.h	2009-02-16 22:17:58 UTC (rev 3524)
@@ -41,5 +41,12 @@
  * and exe filename. */
 QHash<qint64, QString> win32_process_list();
 
+/**
+ * Close all processes started from the specified filename. Sends
+ * WM_CLOSE to all top-level windows, then to all threads. Filename
+ * should be given in lowercase, and comparison is case insensitive.
+ */
+void win32_end_process_by_filename(QString filename);
+
 #endif
 

Modified: vidalia/trunk/src/vidalia/mainwindow.cpp
===================================================================
--- vidalia/trunk/src/vidalia/mainwindow.cpp	2009-02-16 04:01:24 UTC (rev 3523)
+++ vidalia/trunk/src/vidalia/mainwindow.cpp	2009-02-16 22:17:58 UTC (rev 3524)
@@ -366,6 +366,25 @@
     _proxyProcess->kill();
   }
 
+  /* Kill the browser and IM client if using the new launcher */
+  VidaliaSettings vidalia_settings;
+
+  if (! vidalia_settings.getBrowserDirectory().isEmpty()) {
+    /* Disconnect the finished signals so that we won't try to exit Vidalia again */
+    QObject::disconnect(_browserProcess, SIGNAL(finished(int, QProcess::ExitStatus)), 0, 0);
+    QObject::disconnect(_imProcess, SIGNAL(finished(int, QProcess::ExitStatus)), 0, 0);
+
+    /* Use QProcess terminate function */
+    if (_browserProcess->state() == QProcess::Running)
+      _browserProcess->terminate();
+
+    /* Kill any processes which might have been forked off */
+    win32_end_process_by_filename(vidalia_settings.getBrowserExecutable());
+
+    if (_imProcess->state() == QProcess::Running)
+      _imProcess->terminate();    
+  }
+
   /* Disconnect all of the TorControl object's signals */
   QObject::disconnect(_torControl, 0, 0, 0);