| 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" ); |
| +} |