Index: src/shared/Utils.cpp |
=================================================================== |
--- a/src/shared/Utils.cpp |
+++ b/src/shared/Utils.cpp |
@@ -9,11 +9,7 @@ |
namespace |
{ |
- // See http://blogs.msdn.com/b/oldnewthing/archive/2004/10/25/247180.aspx |
- EXTERN_C IMAGE_DOS_HEADER __ImageBase; |
- |
std::wstring appDataPath; |
- |
} |
bool IsWindowsVistaOrLater() |
@@ -55,35 +51,6 @@ |
return utf16String; |
} |
-std::wstring GetDllDir() |
-{ |
- std::vector<WCHAR> path(MAX_PATH); |
- DWORD length = GetModuleFileNameW((HINSTANCE)&__ImageBase, &path[0], path.size()); |
- |
- while (length == path.size()) |
- { |
- // Buffer too small, double buffer size |
- path.resize(path.size() * 2); |
- length = GetModuleFileNameW((HINSTANCE)&__ImageBase, &path[0], path.size()); |
- } |
- |
- try |
- { |
- if (length == 0) |
- throw std::runtime_error("Failed determining module path"); |
- |
- std::vector<WCHAR>::reverse_iterator it = std::find(path.rbegin(), path.rend(), L'\\'); |
- if (it == path.rend()) |
- throw std::runtime_error("Unexpected plugin path, no backslash found"); |
- |
- return std::wstring(path.begin(), it.base()); |
- } |
- catch (const std::exception&) |
- { |
- return std::wstring(); |
- } |
-} |
- |
std::wstring GetAppDataPath() |
{ |
if (appDataPath.empty()) |
@@ -110,3 +77,154 @@ |
} |
return appDataPath; |
} |
+ |
+/** |
+ * Configuration Key |
+ * |
+ * The configuration key is found in [hive]\Software\Adblock Pluse for IE, where [hive] is either HKCU or HKLM. |
+ * An HKCU key overrides any found in HKLM, which mirrors the behavior of the COM subsystem when loading by CLSID. |
+ * Also in parallel, the HKCU key is used by the developer install; the HKLM one used in the MSI. |
+ */ |
+class Config_Key { |
+public: |
+ Config_Key(); |
+ ~Config_Key(); |
+ |
+ std::wstring value_wstring( std::wstring name ); |
+ |
+private: |
+ /** |
+ * Invariant: Not null. |
+ */ |
+ HKEY handle; |
+ |
+ static const std::wstring keyname; |
+}; |
+ |
+const std::wstring Config_Key::keyname = L"Software\\Adblock Plus for IE"; |
+ |
+Config_Key::Config_Key() |
+{ |
+ HKEY h; |
+ LONG hr; |
+ hr = RegOpenKeyEx( HKEY_CURRENT_USER, keyname.c_str(), 0, KEY_QUERY_VALUE, &h ); |
+ if ( hr != ERROR_SUCCESS ) { |
+ // Assert key not found in the HKCU |
+ // Try again in HKLM |
+ hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, keyname.c_str(), 0, KEY_QUERY_VALUE, &h ); |
+ if ( hr != ERROR_SUCCESS ) { |
+ // Assert key not found in either HKCU or HKLM |
+ // Now we give up. |
+ throw std::runtime_error( "Could not open configuration registry key" ); |
+ } |
+ } |
+ // Assert one of the RegOpenKeyEx calls succeeded. |
+ if ( h == 0 ) { |
+ // Success and a null handle? |
+ throw std::runtime_error( "Opened registry key but received null handle" ); |
+ } |
+ handle = h; |
+} |
+ |
+Config_Key::~Config_Key() |
+{ |
+ RegCloseKey( handle ); |
+} |
+ |
+/** |
+ * Retrieve a Unicode string value from this registry key. |
+ * |
+ * Reading string values is significantly more complicated than reading simpler, fixed-size types. There are memory allocation issues to get |
+ * right, which necessitates two queries. There's also a peculiarity with extra null termination characters. |
+ * |
+ * Note: The Windows registry only has partial type support for strings. The string type "REG_SZ" does not say anything about string encoding, |
+ * only that it's a zero-terminated C-style string. It doesn't say anything about the encoding of the string. We check that the value has the |
+ * the type REG_SZ, but that's not completely reliable. |
+ * |
+ * Precondition: |
+ * sizeof( wchar_t ) == 2 |
+ */ |
+std::wstring |
+Config_Key::value_wstring( std::wstring name ) |
+{ |
+ DWORD type; |
+ DWORD size = 0; |
+ /* |
+ * Step one is to determine the presence of the value, along with its type and size. |
+ * Note that the size is given in bytes, not in characters. |
+ */ |
+ DWORD hr = ::RegQueryValueEx( handle, name.c_str(), 0, &type, 0, &size ); |
+ if ( hr != ERROR_SUCCESS ) { |
+ throw std::runtime_error( "Error finding registry value" ); |
+ } |
+ if ( type != REG_SZ ) { |
+ throw std::runtime_error( "Registry value does not have string type" ); |
+ } |
+ |
+ /* |
+ * Step two is to allocate a buffer for the string and query for its value. |
+ */ |
+ // Round the size up to the nearest multiple of two. |
+ size = ( size + 1 ) & ~ DWORD(1); |
+ size_t psize = size >> 1; |
+ std::unique_ptr< wchar_t[] > p( new wchar_t[ psize ] ); |
+ /* |
+ * We're relying that the internal representation of a string is a wchar_t array, which is true for Microsoft compilers. |
+ * This is fine, since we're already Microsoft-specific with the system call. |
+ * It would be better if Microsoft were to write type-safe C++ wrappers for these system calls, but that seems unlikely. |
+ */ |
+ hr = RegQueryValueEx( handle, name.c_str(), 0, 0, reinterpret_cast<BYTE *>( p.get() ), &size ); |
+ if ( hr != ERROR_SUCCESS ) { |
+ throw std::runtime_error( "Error retrieving registry value" ); |
+ } |
+ |
+ /* |
+ * Step three is to construct a return string. |
+ * |
+ * There's the possibility of an extra terminating null character in the return value of the query. |
+ * If so, we have to decrement the length of the return value to eliminate it. |
+ * If it persists, it will interfere with later string operations such as concatenation. |
+ */ |
+ if ( p[ psize - 1 ] == L'\0' ) --psize; |
+ return std::wstring( p.get(), psize ); |
+} |
+ |
+bool |
+Location::all_known() |
+{ |
+ // Not optimized at all. No need--it's only executed once, at DLL startup. |
+ try { |
+ /* |
+ * If any of these functions throw, we report an error. |
+ */ |
+ Config_Key ck; |
+ (void) ck.value_wstring( L"engine" ); |
+ (void) ck.value_wstring( L"locales_dir" ); |
+ (void) ck.value_wstring( L"html_dir" ); |
+ } catch ( ... ) { |
+ // Ignore any specific error. |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+std::wstring |
+Location::engine() |
+{ |
+ Config_Key ck; |
+ return ck.value_wstring( L"engine" ); |
+} |
+ |
+std::wstring |
+Location::locales_dir() |
+{ |
+ Config_Key ck; |
+ return ck.value_wstring( L"locales_dir" ); |
+} |
+ |
+std::wstring |
+Location::html_dir() |
+{ |
+ Config_Key ck; |
+ return ck.value_wstring( L"html_dir" ); |
+} |