Vidalia 0.3.1
win32.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If you
4** did not receive the LICENSE file with this file, you may obtain it from the
5** Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file win32.cpp
13** \brief Win32-specific functions
14*/
15
16#include "win32.h"
17
18#include <QDir>
19#include <QLibrary>
20#include <QtDebug>
21
22#include <tlhelp32.h>
23#include <shlobj.h>
24
25#if defined(UNICODE)
26/* Force the ascii verisons of these functions, so we can run on Win98. We
27 * don't pass any Unicode strings to these functions anyway. */
28#undef PROCESSENTRY32
29#undef LPPROCESSENTRY32
30#undef Process32First
31#undef Process32Next
32#endif
33
34/* Load the tool help functions dynamically, since they don't exist on
35 * Windows NT 4.0 */
36typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_fn)(DWORD, DWORD);
37typedef BOOL (WINAPI *Process32First_fn)(HANDLE, LPPROCESSENTRY32);
38typedef BOOL (WINAPI *Process32Next_fn)(HANDLE, LPPROCESSENTRY32);
39
40
41/** Finds the location of the "special" Windows folder using the given CSIDL
42 * value. If the folder cannot be found, the given default path is used. */
43QString
44win32_get_folder_location(int folder, QString defaultPath)
45{
46 TCHAR path[MAX_PATH+1];
47 LPITEMIDLIST idl;
48 IMalloc *m;
49 HRESULT result;
50
51 /* XXX: It would probably be a good idea to replace this function with simple
52 * calls to QDesktopServices::storageLocation(). Note that it returns the
53 * "Local Settings" application data directory though, so our installers
54 * would need to be updated as well.
55 */
56
57 /* Find the location of %PROGRAMFILES% */
58 if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, folder, &idl))) {
59 /* Get the path from the IDL */
60 result = SHGetPathFromIDList(idl, path);
61 SHGetMalloc(&m);
62 if (m) {
63 m->Release();
64 }
65 if (SUCCEEDED(result)) {
66#if defined(UNICODE)
67 return QString::fromUtf16(static_cast<const ushort *>(path));
68#else
69 return QString::fromLocal8Bit(static_cast<const char *>(path));
70#endif
71 }
72 }
73 return defaultPath;
74}
75
76/** Gets the location of the user's %PROGRAMFILES% folder. */
77QString
79{
81 CSIDL_PROGRAM_FILES, QDir::rootPath() + "\\Program Files");
82}
83
84/** Gets the location of the user's %APPDATA% folder. */
85QString
87{
89 CSIDL_LOCAL_APPDATA, QDir::homePath() + "\\Application Data");
90}
91
92/** Returns the value in keyName at keyLocation.
93 * Returns an empty QString if the keyName doesn't exist */
94QString
95win32_registry_get_key_value(QString keyLocation, QString keyName)
96{
97 HKEY key;
98 char data[255] = {0};
99 DWORD size = sizeof(data);
100
101 /* Open the key for reading (opens new key if it doesn't exist) */
102 if (RegOpenKeyExA(HKEY_CURRENT_USER,
103 qPrintable(keyLocation),
104 0L, KEY_READ, &key) == ERROR_SUCCESS) {
105
106 /* Key exists, so read the value into data */
107 RegQueryValueExA(key, qPrintable(keyName),
108 NULL, NULL, (LPBYTE)data, &size);
109 }
110
111 /* Close anything that was opened */
112 RegCloseKey(key);
113
114 return QString(data);
115}
116
117/** Creates and/or sets the key to the specified value */
118void
119win32_registry_set_key_value(QString keyLocation, QString keyName, QString keyValue)
120{
121 HKEY key;
122
123 /* Open the key for writing (opens new key if it doesn't exist */
124 if (RegOpenKeyExA(HKEY_CURRENT_USER,
125 qPrintable(keyLocation),
126 0, KEY_WRITE, &key) != ERROR_SUCCESS) {
127
128 /* Key didn't exist, so write the newly opened key */
129 RegCreateKeyExA(HKEY_CURRENT_USER,
130 qPrintable(keyLocation),
131 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
132 &key, NULL);
133 }
134
135 /* Save the value in the key */
136 RegSetValueExA(key, qPrintable(keyName), 0, REG_SZ,
137 (BYTE *)qPrintable(keyValue),
138 (DWORD)keyValue.length() + 1); // include null terminator
139
140 /* Close the key */
141 RegCloseKey(key);
142}
143
144/** Removes the key from the registry if it exists */
145void
146win32_registry_remove_key(QString keyLocation, QString keyName)
147{
148 HKEY key;
149
150 /* Open the key for writing (opens new key if it doesn't exist */
151 if (RegOpenKeyExA(HKEY_CURRENT_USER,
152 qPrintable(keyLocation),
153 0, KEY_SET_VALUE, &key) == ERROR_SUCCESS) {
154
155 /* Key exists so delete it */
156 RegDeleteValueA(key, qPrintable(keyName));
157 }
158
159 /* Close anything that was opened */
160 RegCloseKey(key);
161}
162
163/**
164 * Callback for EnumThreadWindows which sends the WM_QUIT message
165 */
166BOOL CALLBACK
167quitWindowCallback(HWND hwnd, LPARAM targetPID)
168{
169 DWORD hwndPID = 0;
170
171 /* If the process ID for hwnd matches the target PID, post
172 WM_QUIT to the window */
173 GetWindowThreadProcessId(hwnd, &hwndPID);
174 if (hwndPID == (DWORD)targetPID)
175 PostMessage(hwnd, WM_QUIT, 0, (LPARAM)NULL);
176 return TRUE;
177}
178
179/**
180 * Close process with the specified PID. Sends WM_QUIT to all
181 * top-level windows.
182 */
183void
185{
186 /* Send WM_QUIT to all windows */
187 EnumWindows(&quitWindowCallback, (LPARAM)pid);
188 /* At this point we could kill the main thread, but how do we find
189 the ID of the main thread? We can find the ID of all threads
190 but killing them all seems to cause a problem for Firefox */
191 //PostThreadMessage(thread.th32ThreadID, WM_CLOSE, 0, (LPARAM)NULL);
192}
193
194/**
195 * Close all processes started from the specified filename. Sends
196 * WM_QUIT to all top-level windows. Filename should be given in
197 * lowercase, and comparison is case insensitive. Note: the MSDN
198 * documentation for WM_QUIT states that the message should not be
199 * sent by PostMessage(). However, sending WM_CLOSE leaves Firefox
200 * running, whereas WM_QUIT seems to work.
201 */
202void
204{
205 /* Get list of running processes */
206 QHash<qint64, QString> procList = win32_process_list();
207
208 /* On old versions of Windows win32_process_list() will return
209 an empty list. In this case, just keep Vidalia open */
210 if (procList.isEmpty()) {
211 return;
212 }
213
214 /* Loop over all processes */
215 QHashIterator<qint64, QString> i(procList);
216 while (i.hasNext()) {
217 i.next();
218 if (i.value().toLower() == filename) {
219 /* Kill this process */
220 win32_end_process_by_pid((DWORD)i.key());
221 }
222 }
223}
224
225/** Returns a list of all currently active processes, including their pid
226 * and exe filename. */
227QHash<qint64, QString>
229{
230 QHash<qint64, QString> procList;
231 CreateToolhelp32Snapshot_fn pCreateToolhelp32Snapshot;
232 Process32First_fn pProcess32First;
233 Process32Next_fn pProcess32Next;
234 HANDLE hSnapshot;
235 PROCESSENTRY32 proc;
236 QString exeFile;
237 qint64 pid;
238
239 /* Load the tool help functions */
240 pCreateToolhelp32Snapshot =
241 (CreateToolhelp32Snapshot_fn)QLibrary::resolve("kernel32", "CreateToolhelp32Snapshot");
242 pProcess32First = (Process32First_fn)QLibrary::resolve("kernel32", "Process32First");
243 pProcess32Next = (Process32Next_fn)QLibrary::resolve("kernel32", "Process32Next");
244
245 if (!pCreateToolhelp32Snapshot || !pProcess32First || !pProcess32Next) {
246 qWarning("Unable to load tool help functions. Running process information "
247 "will be unavailable.");
248 return QHash<qint64, QString>();
249 }
250
251 /* Create a snapshot of all active processes */
252 hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
253 if (hSnapshot != INVALID_HANDLE_VALUE) {
254 proc.dwSize = sizeof(PROCESSENTRY32);
255
256 /* Iterate through all the processes in the snapshot */
257 if (pProcess32First(hSnapshot, &proc)) {
258 do {
259 /* Extract the PID and exe filename from the process record */
260 pid = (qint64)proc.th32ProcessID;
261 exeFile = QString::fromAscii((const char *)proc.szExeFile);
262
263 /* Add this process to our list */
264 procList.insert(pid, exeFile);
265 } while (pProcess32Next(hSnapshot, &proc));
266 }
267 CloseHandle(hSnapshot);
268 }
269 return procList;
270}
271
QString i(QString str)
Definition: html.cpp:32
BOOL(WINAPI * Process32Next_fn)(HANDLE, LPPROCESSENTRY32)
Definition: win32.cpp:38
void win32_registry_remove_key(QString keyLocation, QString keyName)
Definition: win32.cpp:146
void win32_end_process_by_pid(DWORD pid)
Definition: win32.cpp:184
QString win32_app_data_folder()
Definition: win32.cpp:86
void win32_end_process_by_filename(QString filename)
Definition: win32.cpp:203
void win32_registry_set_key_value(QString keyLocation, QString keyName, QString keyValue)
Definition: win32.cpp:119
QString win32_program_files_folder()
Definition: win32.cpp:78
QString win32_registry_get_key_value(QString keyLocation, QString keyName)
Definition: win32.cpp:95
QHash< qint64, QString > win32_process_list()
Definition: win32.cpp:228
BOOL(WINAPI * Process32First_fn)(HANDLE, LPPROCESSENTRY32)
Definition: win32.cpp:37
BOOL CALLBACK quitWindowCallback(HWND hwnd, LPARAM targetPID)
Definition: win32.cpp:167
QString win32_get_folder_location(int folder, QString defaultPath)
Definition: win32.cpp:44
HANDLE(WINAPI * CreateToolhelp32Snapshot_fn)(DWORD, DWORD)
Definition: win32.cpp:36