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

Generated on 31 Mar 2010 for Vidalia by  doxygen 1.6.1