Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/shared/Utils.cpp

Issue 11254007: Installation with registry keys
Patch Set: Created July 25, 2013, 9:57 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/shared/Utils.h ('k') | test/DictionaryTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « src/shared/Utils.h ('k') | test/DictionaryTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld