| OLD | NEW |
| 1 #include <memory> | 1 #include <memory> |
| 2 #include <stdexcept> | 2 #include <stdexcept> |
| 3 #include <vector> | 3 #include <vector> |
| 4 | 4 |
| 5 #include <Windows.h> | 5 #include <Windows.h> |
| 6 #include <ShlObj.h> | 6 #include <ShlObj.h> |
| 7 | 7 |
| 8 #include "Utils.h" | 8 #include "Utils.h" |
| 9 | 9 |
| 10 namespace | 10 namespace |
| 11 { | 11 { |
| 12 // See http://blogs.msdn.com/b/oldnewthing/archive/2004/10/25/247180.aspx | |
| 13 EXTERN_C IMAGE_DOS_HEADER __ImageBase; | |
| 14 | |
| 15 std::wstring appDataPath; | 12 std::wstring appDataPath; |
| 16 | |
| 17 } | 13 } |
| 18 | 14 |
| 19 bool IsWindowsVistaOrLater() | 15 bool IsWindowsVistaOrLater() |
| 20 { | 16 { |
| 21 OSVERSIONINFOEX osvi; | 17 OSVERSIONINFOEX osvi; |
| 22 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | 18 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); |
| 23 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | 19 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); |
| 24 GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osvi)); | 20 GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osvi)); |
| 25 return osvi.dwMajorVersion >= 6; | 21 return osvi.dwMajorVersion >= 6; |
| 26 } | 22 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 48 | 44 |
| 49 DWORD utf16StringLength = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), length,
NULL, 0); | 45 DWORD utf16StringLength = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), length,
NULL, 0); |
| 50 if (utf16StringLength == 0) | 46 if (utf16StringLength == 0) |
| 51 throw std::runtime_error("ToUTF16String failed. Can't determine the length o
f the buffer needed."); | 47 throw std::runtime_error("ToUTF16String failed. Can't determine the length o
f the buffer needed."); |
| 52 | 48 |
| 53 std::wstring utf16String(utf16StringLength, L'\0'); | 49 std::wstring utf16String(utf16StringLength, L'\0'); |
| 54 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), length, &utf16String[0], utf16Str
ingLength); | 50 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), length, &utf16String[0], utf16Str
ingLength); |
| 55 return utf16String; | 51 return utf16String; |
| 56 } | 52 } |
| 57 | 53 |
| 58 std::wstring GetDllDir() | |
| 59 { | |
| 60 std::vector<WCHAR> path(MAX_PATH); | |
| 61 DWORD length = GetModuleFileNameW((HINSTANCE)&__ImageBase, &path[0], path.size
()); | |
| 62 | |
| 63 while (length == path.size()) | |
| 64 { | |
| 65 // Buffer too small, double buffer size | |
| 66 path.resize(path.size() * 2); | |
| 67 length = GetModuleFileNameW((HINSTANCE)&__ImageBase, &path[0], path.size()); | |
| 68 } | |
| 69 | |
| 70 try | |
| 71 { | |
| 72 if (length == 0) | |
| 73 throw std::runtime_error("Failed determining module path"); | |
| 74 | |
| 75 std::vector<WCHAR>::reverse_iterator it = std::find(path.rbegin(), path.rend
(), L'\\'); | |
| 76 if (it == path.rend()) | |
| 77 throw std::runtime_error("Unexpected plugin path, no backslash found"); | |
| 78 | |
| 79 return std::wstring(path.begin(), it.base()); | |
| 80 } | |
| 81 catch (const std::exception&) | |
| 82 { | |
| 83 return std::wstring(); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 std::wstring GetAppDataPath() | 54 std::wstring GetAppDataPath() |
| 88 { | 55 { |
| 89 if (appDataPath.empty()) | 56 if (appDataPath.empty()) |
| 90 { | 57 { |
| 91 if (IsWindowsVistaOrLater()) | 58 if (IsWindowsVistaOrLater()) |
| 92 { | 59 { |
| 93 WCHAR* pathBuffer; | 60 WCHAR* pathBuffer; |
| 94 if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, 0, &pathBuffe
r))) | 61 if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, 0, &pathBuffe
r))) |
| 95 throw std::runtime_error("Unable to find app data directory"); | 62 throw std::runtime_error("Unable to find app data directory"); |
| 96 appDataPath.assign(pathBuffer); | 63 appDataPath.assign(pathBuffer); |
| 97 CoTaskMemFree(pathBuffer); | 64 CoTaskMemFree(pathBuffer); |
| 98 } | 65 } |
| 99 else | 66 else |
| 100 { | 67 { |
| 101 std::auto_ptr<wchar_t> pathBuffer(new wchar_t[MAX_PATH]); | 68 std::auto_ptr<wchar_t> pathBuffer(new wchar_t[MAX_PATH]); |
| 102 if (!SHGetSpecialFolderPathW(0, pathBuffer.get(), CSIDL_LOCAL_APPDATA, tru
e)) | 69 if (!SHGetSpecialFolderPathW(0, pathBuffer.get(), CSIDL_LOCAL_APPDATA, tru
e)) |
| 103 throw std::runtime_error("Unable to find app data directory"); | 70 throw std::runtime_error("Unable to find app data directory"); |
| 104 appDataPath.assign(pathBuffer.get()); | 71 appDataPath.assign(pathBuffer.get()); |
| 105 } | 72 } |
| 106 appDataPath += L"\\Adblock Plus for IE"; | 73 appDataPath += L"\\Adblock Plus for IE"; |
| 107 | 74 |
| 108 // Ignore errors here, this isn't a critical operation | 75 // Ignore errors here, this isn't a critical operation |
| 109 ::CreateDirectoryW(appDataPath.c_str(), NULL); | 76 ::CreateDirectoryW(appDataPath.c_str(), NULL); |
| 110 } | 77 } |
| 111 return appDataPath; | 78 return appDataPath; |
| 112 } | 79 } |
| 80 |
| 81 /** |
| 82 * Configuration Key |
| 83 * |
| 84 * The configuration key is found in [hive]\Software\Adblock Pluse for IE, where
[hive] is either HKCU or HKLM. |
| 85 * An HKCU key overrides any found in HKLM, which mirrors the behavior of the CO
M subsystem when loading by CLSID. |
| 86 * Also in parallel, the HKCU key is used by the developer install; the HKLM one
used in the MSI. |
| 87 */ |
| 88 class Config_Key { |
| 89 public: |
| 90 Config_Key(); |
| 91 ~Config_Key(); |
| 92 |
| 93 std::wstring value_wstring( std::wstring name ); |
| 94 |
| 95 private: |
| 96 /** |
| 97 * Invariant: Not null. |
| 98 */ |
| 99 HKEY handle; |
| 100 |
| 101 static const std::wstring keyname; |
| 102 }; |
| 103 |
| 104 const std::wstring Config_Key::keyname = L"Software\\Adblock Plus for IE"; |
| 105 |
| 106 Config_Key::Config_Key() |
| 107 { |
| 108 HKEY h; |
| 109 LONG hr; |
| 110 hr = RegOpenKeyEx( HKEY_CURRENT_USER, keyname.c_str(), 0, KEY_QUERY_VALUE, &h
); |
| 111 if ( hr != ERROR_SUCCESS ) { |
| 112 // Assert key not found in the HKCU |
| 113 // Try again in HKLM |
| 114 hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, keyname.c_str(), 0, KEY_QUERY_VALUE,
&h ); |
| 115 if ( hr != ERROR_SUCCESS ) { |
| 116 // Assert key not found in either HKCU or HKLM |
| 117 // Now we give up. |
| 118 throw std::runtime_error( "Could not open configuration registry key" ); |
| 119 } |
| 120 } |
| 121 // Assert one of the RegOpenKeyEx calls succeeded. |
| 122 if ( h == 0 ) { |
| 123 // Success and a null handle? |
| 124 throw std::runtime_error( "Opened registry key but received null handle" ); |
| 125 } |
| 126 handle = h; |
| 127 } |
| 128 |
| 129 Config_Key::~Config_Key() |
| 130 { |
| 131 RegCloseKey( handle ); |
| 132 } |
| 133 |
| 134 /** |
| 135 * Retrieve a Unicode string value from this registry key. |
| 136 * |
| 137 * Reading string values is significantly more complicated than reading simpler,
fixed-size types. There are memory allocation issues to get |
| 138 * right, which necessitates two queries. There's also a peculiarity with extra
null termination characters. |
| 139 * |
| 140 * Note: The Windows registry only has partial type support for strings. The str
ing type "REG_SZ" does not say anything about string encoding, |
| 141 * only that it's a zero-terminated C-style string. It doesn't say anything abou
t the encoding of the string. We check that the value has the |
| 142 * the type REG_SZ, but that's not completely reliable. |
| 143 * |
| 144 * Precondition: |
| 145 * sizeof( wchar_t ) == 2 |
| 146 */ |
| 147 std::wstring |
| 148 Config_Key::value_wstring( std::wstring name ) |
| 149 { |
| 150 DWORD type; |
| 151 DWORD size = 0; |
| 152 /* |
| 153 * Step one is to determine the presence of the value, along with its type and
size. |
| 154 * Note that the size is given in bytes, not in characters. |
| 155 */ |
| 156 DWORD hr = ::RegQueryValueEx( handle, name.c_str(), 0, &type, 0, &size ); |
| 157 if ( hr != ERROR_SUCCESS ) { |
| 158 throw std::runtime_error( "Error finding registry value" ); |
| 159 } |
| 160 if ( type != REG_SZ ) { |
| 161 throw std::runtime_error( "Registry value does not have string type" ); |
| 162 } |
| 163 |
| 164 /* |
| 165 * Step two is to allocate a buffer for the string and query for its value. |
| 166 */ |
| 167 // Round the size up to the nearest multiple of two. |
| 168 size = ( size + 1 ) & ~ DWORD(1); |
| 169 size_t psize = size >> 1; |
| 170 std::unique_ptr< wchar_t[] > p( new wchar_t[ psize ] ); |
| 171 /* |
| 172 * We're relying that the internal representation of a string is a wchar_t arr
ay, which is true for Microsoft compilers. |
| 173 * This is fine, since we're already Microsoft-specific with the system call. |
| 174 * It would be better if Microsoft were to write type-safe C++ wrappers for th
ese system calls, but that seems unlikely. |
| 175 */ |
| 176 hr = RegQueryValueEx( handle, name.c_str(), 0, 0, reinterpret_cast<BYTE *>( p.
get() ), &size ); |
| 177 if ( hr != ERROR_SUCCESS ) { |
| 178 throw std::runtime_error( "Error retrieving registry value" ); |
| 179 } |
| 180 |
| 181 /* |
| 182 * Step three is to construct a return string. |
| 183 * |
| 184 * There's the possibility of an extra terminating null character in the retur
n value of the query. |
| 185 * If so, we have to decrement the length of the return value to eliminate it. |
| 186 * If it persists, it will interfere with later string operations such as conc
atenation. |
| 187 */ |
| 188 if ( p[ psize - 1 ] == L'\0' ) --psize; |
| 189 return std::wstring( p.get(), psize ); |
| 190 } |
| 191 |
| 192 bool |
| 193 Location::all_known() |
| 194 { |
| 195 // Not optimized at all. No need--it's only executed once, at DLL startup. |
| 196 try { |
| 197 /* |
| 198 * If any of these functions throw, we report an error. |
| 199 */ |
| 200 Config_Key ck; |
| 201 (void) ck.value_wstring( L"engine" ); |
| 202 (void) ck.value_wstring( L"locales_dir" ); |
| 203 (void) ck.value_wstring( L"html_dir" ); |
| 204 } catch ( ... ) { |
| 205 // Ignore any specific error. |
| 206 return false; |
| 207 } |
| 208 return true; |
| 209 } |
| 210 |
| 211 std::wstring |
| 212 Location::engine() |
| 213 { |
| 214 Config_Key ck; |
| 215 return ck.value_wstring( L"engine" ); |
| 216 } |
| 217 |
| 218 std::wstring |
| 219 Location::locales_dir() |
| 220 { |
| 221 Config_Key ck; |
| 222 return ck.value_wstring( L"locales_dir" ); |
| 223 } |
| 224 |
| 225 std::wstring |
| 226 Location::html_dir() |
| 227 { |
| 228 Config_Key ck; |
| 229 return ck.value_wstring( L"html_dir" ); |
| 230 } |
| OLD | NEW |