[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);