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 |