win32.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file win32.cpp
00013 ** \version $Id: win32.cpp 3811 2009-06-01 07:03:24Z edmanm $ 
00014 ** \brief Win32-specific functions
00015 */
00016 
00017 #include "win32.h"
00018 #include <tlhelp32.h>
00019 #include <shlobj.h>
00020 #include <QDir>
00021 #include <QLibrary>
00022 #include <QtDebug>
00023 
00024 #if defined(UNICODE)
00025 /* Force the ascii verisons of these functions, so we can run on Win98. We
00026  * don't pass any Unicode strings to these functions anyway. */
00027 #undef PROCESSENTRY32
00028 #undef LPPROCESSENTRY32
00029 #undef Process32First
00030 #undef Process32Next
00031 #endif
00032 
00033 /* Load the tool help functions dynamically, since they don't exist on
00034  * Windows NT 4.0 */
00035 typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_fn)(DWORD, DWORD);
00036 typedef BOOL (WINAPI *Process32First_fn)(HANDLE, LPPROCESSENTRY32);
00037 typedef BOOL (WINAPI *Process32Next_fn)(HANDLE, LPPROCESSENTRY32);
00038 
00039 
00040 /** Finds the location of the "special" Windows folder using the given CSIDL
00041  * value. If the folder cannot be found, the given default path is used. */
00042 QString
00043 win32_get_folder_location(int folder, QString defaultPath)
00044 {
00045   TCHAR path[MAX_PATH+1];
00046   LPITEMIDLIST idl;
00047   IMalloc *m;
00048   HRESULT result;
00049 
00050   /* Find the location of %PROGRAMFILES% */
00051   if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, folder, &idl))) {
00052     /* Get the path from the IDL */
00053     result = SHGetPathFromIDList(idl, path);
00054     SHGetMalloc(&m);
00055     if (m) {
00056       m->Release();
00057     }
00058     if (SUCCEEDED(result)) {
00059       QT_WA(return QString::fromUtf16((const ushort *)path);,
00060             return QString::fromLocal8Bit((char *)path);)
00061     }
00062   }
00063   return defaultPath;
00064 }
00065 
00066 /** Gets the location of the user's %PROGRAMFILES% folder. */
00067 QString
00068 win32_program_files_folder()
00069 {
00070   return win32_get_folder_location(
00071      CSIDL_PROGRAM_FILES, QDir::rootPath() + "\\Program Files");
00072 }
00073 
00074 /** Gets the location of the user's %APPDATA% folder. */
00075 QString
00076 win32_app_data_folder()
00077 {
00078   return win32_get_folder_location(
00079       CSIDL_APPDATA, QDir::homePath() + "\\Application Data");
00080 }
00081 
00082 /** Returns the value in keyName at keyLocation. 
00083  *  Returns an empty QString if the keyName doesn't exist */
00084 QString
00085 win32_registry_get_key_value(QString keyLocation, QString keyName)
00086 {
00087   HKEY key;
00088   char data[255] = {0};
00089   DWORD size = sizeof(data);
00090 
00091   /* Open the key for reading (opens new key if it doesn't exist) */
00092   if (RegOpenKeyExA(HKEY_CURRENT_USER,
00093                     qPrintable(keyLocation), 
00094                     0L, KEY_READ, &key) == ERROR_SUCCESS) {
00095     
00096     /* Key exists, so read the value into data */
00097     RegQueryValueExA(key, qPrintable(keyName), 
00098                     NULL, NULL, (LPBYTE)data, &size);
00099   }
00100 
00101   /* Close anything that was opened */
00102   RegCloseKey(key);
00103 
00104   return QString(data);
00105 }
00106 
00107 /** Creates and/or sets the key to the specified value */
00108 void
00109 win32_registry_set_key_value(QString keyLocation, QString keyName, QString keyValue)
00110 {
00111   HKEY key;
00112   
00113   /* Open the key for writing (opens new key if it doesn't exist */
00114   if (RegOpenKeyExA(HKEY_CURRENT_USER,
00115                    qPrintable(keyLocation),
00116                    0, KEY_WRITE, &key) != ERROR_SUCCESS) {
00117 
00118     /* Key didn't exist, so write the newly opened key */
00119     RegCreateKeyExA(HKEY_CURRENT_USER,
00120                    qPrintable(keyLocation),
00121                    0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
00122                    &key, NULL);
00123   }
00124 
00125   /* Save the value in the key */
00126   RegSetValueExA(key, qPrintable(keyName), 0, REG_SZ, 
00127                 (BYTE *)qPrintable(keyValue),
00128                 (DWORD)keyValue.length() + 1); // include null terminator
00129 
00130   /* Close the key */
00131   RegCloseKey(key);
00132 }
00133 
00134 /** Removes the key from the registry if it exists */
00135 void
00136 win32_registry_remove_key(QString keyLocation, QString keyName)
00137 {
00138   HKEY key;
00139   
00140   /* Open the key for writing (opens new key if it doesn't exist */
00141   if (RegOpenKeyExA(HKEY_CURRENT_USER,
00142                    qPrintable(keyLocation),
00143                    0, KEY_SET_VALUE, &key) == ERROR_SUCCESS) {
00144   
00145     /* Key exists so delete it */
00146     RegDeleteValueA(key, qPrintable(keyName));
00147   }
00148 
00149   /* Close anything that was opened */
00150   RegCloseKey(key);
00151 }
00152 
00153 /**
00154  * Callback for EnumThreadWindows which sends the WM_QUIT message
00155  */
00156 BOOL CALLBACK 
00157 quitWindowCallback(HWND hwnd, LPARAM targetPID)
00158 {
00159   DWORD hwndPID = 0;
00160 
00161   /* If the process ID for hwnd matches the target PID, post
00162      WM_QUIT to the window */
00163   GetWindowThreadProcessId(hwnd, &hwndPID);
00164   if (hwndPID == (DWORD)targetPID)
00165     PostMessage(hwnd, WM_QUIT, 0, (LPARAM)NULL);
00166   return TRUE;
00167 }
00168 
00169 /**
00170  * Close process with the specified PID. Sends WM_QUIT to all
00171  * top-level windows.
00172  */
00173 void
00174 win32_end_process_by_pid(DWORD pid)
00175 {
00176   /* Send WM_QUIT to all windows */
00177   EnumWindows(&quitWindowCallback, (LPARAM)pid);
00178   /* At this point we could kill the main thread, but how do we find
00179      the ID of the main thread? We can find the ID of all threads
00180      but killing them all seems to cause a problem for Firefox */
00181   //PostThreadMessage(thread.th32ThreadID, WM_CLOSE, 0, (LPARAM)NULL);
00182 }
00183 
00184 /**
00185  * Close all processes started from the specified filename. Sends
00186  * WM_QUIT to all top-level windows. Filename should be given in
00187  * lowercase, and comparison is case insensitive. Note: the MSDN
00188  * documentation for WM_QUIT states that the message should not be
00189  * sent by PostMessage(). However, sending WM_CLOSE leaves Firefox
00190  * running, whereas WM_QUIT seems to work.
00191  */
00192 void
00193 win32_end_process_by_filename(QString filename)
00194 {
00195   /* Get list of running processes */
00196   QHash<qint64, QString> procList = win32_process_list();
00197 
00198   /* On old versions of Windows win32_process_list() will return
00199      an empty list. In this case, just keep Vidalia open */
00200   if (procList.isEmpty()) {
00201     return;
00202   }
00203 
00204   /* Loop over all processes */
00205   QHashIterator<qint64, QString> i(procList);
00206   while (i.hasNext()) {
00207     i.next();
00208     if (i.value().toLower() == filename) {
00209       /* Kill this process */
00210       win32_end_process_by_pid((DWORD)i.key());
00211     }
00212   }
00213 }
00214 
00215 /** Returns a list of all currently active processes, including their pid
00216  * and exe filename. */
00217 QHash<qint64, QString>
00218 win32_process_list()
00219 {
00220   QHash<qint64, QString> procList;
00221   CreateToolhelp32Snapshot_fn pCreateToolhelp32Snapshot;
00222   Process32First_fn pProcess32First;
00223   Process32Next_fn pProcess32Next;
00224   HANDLE hSnapshot;
00225   PROCESSENTRY32 proc;
00226   QString exeFile;
00227   qint64 pid;
00228 
00229   /* Load the tool help functions */
00230   pCreateToolhelp32Snapshot =
00231     (CreateToolhelp32Snapshot_fn)QLibrary::resolve("kernel32", "CreateToolhelp32Snapshot");
00232   pProcess32First = (Process32First_fn)QLibrary::resolve("kernel32", "Process32First");
00233   pProcess32Next = (Process32Next_fn)QLibrary::resolve("kernel32", "Process32Next");
00234  
00235   if (!pCreateToolhelp32Snapshot || !pProcess32First || !pProcess32Next) {
00236     qWarning("Unable to load tool help functions. Running process information "
00237              "will be unavailable.");
00238     return QHash<qint64, QString>();
00239   }
00240 
00241   /* Create a snapshot of all active processes */
00242   hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
00243   if (hSnapshot != INVALID_HANDLE_VALUE) {
00244     proc.dwSize = sizeof(PROCESSENTRY32);
00245     
00246     /* Iterate through all the processes in the snapshot */
00247     if (pProcess32First(hSnapshot, &proc)) {
00248       do {
00249         /* Extract the PID and exe filename from the process record */
00250         pid = (qint64)proc.th32ProcessID;
00251         exeFile = QString::fromAscii((const char *)proc.szExeFile);
00252         
00253         /* Add this process to our list */
00254         procList.insert(pid, exeFile);
00255       } while (pProcess32Next(hSnapshot, &proc));
00256     }
00257     CloseHandle(hSnapshot);
00258   }
00259   return procList;
00260 }
00261 

Generated on Tue Jul 7 16:58:27 2009 for Vidalia by  doxygen 1.4.7