1 |
package net.oni2.aeinstaller.backend; |
2 |
|
3 |
import java.lang.reflect.InvocationTargetException; |
4 |
import java.lang.reflect.Method; |
5 |
import java.util.ArrayList; |
6 |
import java.util.HashMap; |
7 |
import java.util.List; |
8 |
import java.util.Map; |
9 |
import java.util.prefs.Preferences; |
10 |
|
11 |
/** |
12 |
* @author Unknown |
13 |
*/ |
14 |
public class WinRegistry { |
15 |
/** |
16 |
* Constant for accessing HKCU |
17 |
*/ |
18 |
public static final int HKEY_CURRENT_USER = 0x80000001; |
19 |
/** |
20 |
* Constant for accessing HKLM |
21 |
*/ |
22 |
public static final int HKEY_LOCAL_MACHINE = 0x80000002; |
23 |
/** |
24 |
* Constant for successful accesses |
25 |
*/ |
26 |
public static final int REG_SUCCESS = 0; |
27 |
/** |
28 |
* Constant for not found |
29 |
*/ |
30 |
public static final int REG_NOTFOUND = 2; |
31 |
/** |
32 |
* Constant for access denied |
33 |
*/ |
34 |
public static final int REG_ACCESSDENIED = 5; |
35 |
|
36 |
/** |
37 |
* Access 32bit registry view when running as 64bit application |
38 |
*/ |
39 |
public static final int KEY_WOW64_32KEY = 0x0200; |
40 |
/** |
41 |
* Access 64bit registry view when running as 32bit application |
42 |
*/ |
43 |
public static final int KEY_WOW64_64KEY = 0x0100; |
44 |
|
45 |
private static final int KEY_ALL_ACCESS = 0xf003f; |
46 |
private static final int KEY_READ = 0x20019; |
47 |
private static Preferences userRoot = Preferences.userRoot(); |
48 |
private static Preferences systemRoot = Preferences.systemRoot(); |
49 |
private static Class<? extends Preferences> userClass = userRoot.getClass(); |
50 |
private static Method regOpenKey = null; |
51 |
private static Method regCloseKey = null; |
52 |
private static Method regQueryValueEx = null; |
53 |
private static Method regEnumValue = null; |
54 |
private static Method regQueryInfoKey = null; |
55 |
private static Method regEnumKeyEx = null; |
56 |
private static Method regCreateKeyEx = null; |
57 |
private static Method regSetValueEx = null; |
58 |
private static Method regDeleteKey = null; |
59 |
private static Method regDeleteValue = null; |
60 |
|
61 |
private static boolean usable = false; |
62 |
|
63 |
static { |
64 |
try { |
65 |
regOpenKey = userClass.getDeclaredMethod("WindowsRegOpenKey", |
66 |
new Class[] { int.class, byte[].class, int.class }); |
67 |
regOpenKey.setAccessible(true); |
68 |
regCloseKey = userClass.getDeclaredMethod("WindowsRegCloseKey", |
69 |
new Class[] { int.class }); |
70 |
regCloseKey.setAccessible(true); |
71 |
regQueryValueEx = userClass.getDeclaredMethod( |
72 |
"WindowsRegQueryValueEx", new Class[] { int.class, |
73 |
byte[].class }); |
74 |
regQueryValueEx.setAccessible(true); |
75 |
regEnumValue = userClass.getDeclaredMethod("WindowsRegEnumValue", |
76 |
new Class[] { int.class, int.class, int.class }); |
77 |
regEnumValue.setAccessible(true); |
78 |
regQueryInfoKey = userClass.getDeclaredMethod( |
79 |
"WindowsRegQueryInfoKey1", new Class[] { int.class }); |
80 |
regQueryInfoKey.setAccessible(true); |
81 |
regEnumKeyEx = userClass.getDeclaredMethod("WindowsRegEnumKeyEx", |
82 |
new Class[] { int.class, int.class, int.class }); |
83 |
regEnumKeyEx.setAccessible(true); |
84 |
regCreateKeyEx = userClass.getDeclaredMethod( |
85 |
"WindowsRegCreateKeyEx", new Class[] { int.class, |
86 |
byte[].class }); |
87 |
regCreateKeyEx.setAccessible(true); |
88 |
regSetValueEx = userClass.getDeclaredMethod("WindowsRegSetValueEx", |
89 |
new Class[] { int.class, byte[].class, byte[].class }); |
90 |
regSetValueEx.setAccessible(true); |
91 |
regDeleteValue = userClass.getDeclaredMethod( |
92 |
"WindowsRegDeleteValue", new Class[] { int.class, |
93 |
byte[].class }); |
94 |
regDeleteValue.setAccessible(true); |
95 |
regDeleteKey = userClass.getDeclaredMethod("WindowsRegDeleteKey", |
96 |
new Class[] { int.class, byte[].class }); |
97 |
regDeleteKey.setAccessible(true); |
98 |
usable = true; |
99 |
} catch (Exception e) { |
100 |
// e.printStackTrace(); |
101 |
} |
102 |
} |
103 |
|
104 |
private WinRegistry() { |
105 |
} |
106 |
|
107 |
/** |
108 |
* Read a value from key and value name |
109 |
* |
110 |
* @param hkey |
111 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
112 |
* @param key |
113 |
* Key to access |
114 |
* @param valueName |
115 |
* Name of value to read |
116 |
* @param wow64 |
117 |
* 0 for standard registry access (32-bits for 32-bit app, |
118 |
* 64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to |
119 |
* 32-bit registry view, or KEY_WOW64_64KEY to force access to |
120 |
* 64-bit registry view |
121 |
* @return the value |
122 |
* @throws Exception |
123 |
* If registry access impossible |
124 |
* @throws IllegalArgumentException |
125 |
* On illegal arguments |
126 |
* @throws IllegalAccessException |
127 |
* On illegal access |
128 |
* @throws InvocationTargetException |
129 |
* On reflection problems |
130 |
*/ |
131 |
public static String readString(int hkey, String key, String valueName, |
132 |
int wow64) throws Exception, IllegalArgumentException, |
133 |
IllegalAccessException, InvocationTargetException { |
134 |
if (!usable) |
135 |
throw new Exception( |
136 |
"Registry access not supported (not a Windows OS?)."); |
137 |
if (hkey == HKEY_LOCAL_MACHINE) { |
138 |
return readString(systemRoot, hkey, key, valueName, wow64); |
139 |
} else if (hkey == HKEY_CURRENT_USER) { |
140 |
return readString(userRoot, hkey, key, valueName, wow64); |
141 |
} else { |
142 |
throw new IllegalArgumentException("hkey=" + hkey); |
143 |
} |
144 |
} |
145 |
|
146 |
/** |
147 |
* Read value(s) and value name(s) form given key |
148 |
* |
149 |
* @param hkey |
150 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
151 |
* @param key |
152 |
* Key to access |
153 |
* @param wow64 |
154 |
* 0 for standard registry access (32-bits for 32-bit app, |
155 |
* 64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to |
156 |
* 32-bit registry view, or KEY_WOW64_64KEY to force access to |
157 |
* 64-bit registry view |
158 |
* @return the value name(s) plus the value(s) |
159 |
* @throws Exception |
160 |
* If registry access impossible |
161 |
* @throws IllegalArgumentException |
162 |
* On illegal arguments |
163 |
* @throws IllegalAccessException |
164 |
* On illegal access |
165 |
* @throws InvocationTargetException |
166 |
* On reflection problems |
167 |
*/ |
168 |
public static Map<String, String> readStringValues(int hkey, String key, |
169 |
int wow64) throws Exception, IllegalArgumentException, |
170 |
IllegalAccessException, InvocationTargetException { |
171 |
if (!usable) |
172 |
throw new Exception( |
173 |
"Registry access not supported (not a Windows OS?)."); |
174 |
if (hkey == HKEY_LOCAL_MACHINE) { |
175 |
return readStringValues(systemRoot, hkey, key, wow64); |
176 |
} else if (hkey == HKEY_CURRENT_USER) { |
177 |
return readStringValues(userRoot, hkey, key, wow64); |
178 |
} else { |
179 |
throw new IllegalArgumentException("hkey=" + hkey); |
180 |
} |
181 |
} |
182 |
|
183 |
/** |
184 |
* Read the value name(s) from a given key |
185 |
* |
186 |
* @param hkey |
187 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
188 |
* @param key |
189 |
* Key to access |
190 |
* @param wow64 |
191 |
* 0 for standard registry access (32-bits for 32-bit app, |
192 |
* 64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to |
193 |
* 32-bit registry view, or KEY_WOW64_64KEY to force access to |
194 |
* 64-bit registry view |
195 |
* @return the value name(s) |
196 |
* @throws Exception |
197 |
* If registry access impossible |
198 |
* @throws IllegalArgumentException |
199 |
* On illegal arguments |
200 |
* @throws IllegalAccessException |
201 |
* On illegal access |
202 |
* @throws InvocationTargetException |
203 |
* On reflection problems |
204 |
*/ |
205 |
public static List<String> readStringSubKeys(int hkey, String key, int wow64) |
206 |
throws Exception, IllegalArgumentException, IllegalAccessException, |
207 |
InvocationTargetException { |
208 |
if (!usable) |
209 |
throw new Exception( |
210 |
"Registry access not supported (not a Windows OS?)."); |
211 |
if (hkey == HKEY_LOCAL_MACHINE) { |
212 |
return readStringSubKeys(systemRoot, hkey, key, wow64); |
213 |
} else if (hkey == HKEY_CURRENT_USER) { |
214 |
return readStringSubKeys(userRoot, hkey, key, wow64); |
215 |
} else { |
216 |
throw new IllegalArgumentException("hkey=" + hkey); |
217 |
} |
218 |
} |
219 |
|
220 |
/** |
221 |
* Create a key |
222 |
* |
223 |
* @param hkey |
224 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
225 |
* @param key |
226 |
* Key to access |
227 |
* @throws Exception |
228 |
* If registry access impossible |
229 |
* @throws IllegalArgumentException |
230 |
* On illegal arguments |
231 |
* @throws IllegalAccessException |
232 |
* On illegal access |
233 |
* @throws InvocationTargetException |
234 |
* On reflection problems |
235 |
*/ |
236 |
public static void createKey(int hkey, String key) throws Exception, |
237 |
IllegalArgumentException, IllegalAccessException, |
238 |
InvocationTargetException { |
239 |
int[] ret; |
240 |
if (!usable) |
241 |
throw new Exception( |
242 |
"Registry access not supported (not a Windows OS?)."); |
243 |
if (hkey == HKEY_LOCAL_MACHINE) { |
244 |
ret = createKey(systemRoot, hkey, key); |
245 |
regCloseKey |
246 |
.invoke(systemRoot, new Object[] { new Integer(ret[0]) }); |
247 |
} else if (hkey == HKEY_CURRENT_USER) { |
248 |
ret = createKey(userRoot, hkey, key); |
249 |
regCloseKey.invoke(userRoot, new Object[] { new Integer(ret[0]) }); |
250 |
} else { |
251 |
throw new IllegalArgumentException("hkey=" + hkey); |
252 |
} |
253 |
if (ret[1] != REG_SUCCESS) { |
254 |
throw new IllegalArgumentException("rc=" + ret[1] + " key=" + key); |
255 |
} |
256 |
} |
257 |
|
258 |
/** |
259 |
* Write a value in a given key/value name |
260 |
* |
261 |
* @param hkey |
262 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
263 |
* @param key |
264 |
* Key to access |
265 |
* @param valueName |
266 |
* Name of value to write to |
267 |
* @param value |
268 |
* String to write |
269 |
* @param wow64 |
270 |
* 0 for standard registry access (32-bits for 32-bit app, |
271 |
* 64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to |
272 |
* 32-bit registry view, or KEY_WOW64_64KEY to force access to |
273 |
* 64-bit registry view |
274 |
* @throws Exception |
275 |
* If registry access impossible |
276 |
* @throws IllegalArgumentException |
277 |
* On illegal arguments |
278 |
* @throws IllegalAccessException |
279 |
* On illegal access |
280 |
* @throws InvocationTargetException |
281 |
* On reflection problems |
282 |
*/ |
283 |
public static void writeStringValue(int hkey, String key, String valueName, |
284 |
String value, int wow64) throws Exception, |
285 |
IllegalArgumentException, IllegalAccessException, |
286 |
InvocationTargetException { |
287 |
if (!usable) |
288 |
throw new Exception( |
289 |
"Registry access not supported (not a Windows OS?)."); |
290 |
if (hkey == HKEY_LOCAL_MACHINE) { |
291 |
writeStringValue(systemRoot, hkey, key, valueName, value, wow64); |
292 |
} else if (hkey == HKEY_CURRENT_USER) { |
293 |
writeStringValue(userRoot, hkey, key, valueName, value, wow64); |
294 |
} else { |
295 |
throw new IllegalArgumentException("hkey=" + hkey); |
296 |
} |
297 |
} |
298 |
|
299 |
/** |
300 |
* Delete a given key |
301 |
* |
302 |
* @param hkey |
303 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
304 |
* @param key |
305 |
* Key to delete |
306 |
* @throws Exception |
307 |
* If registry access impossible |
308 |
* @throws IllegalArgumentException |
309 |
* On illegal arguments |
310 |
* @throws IllegalAccessException |
311 |
* On illegal access |
312 |
* @throws InvocationTargetException |
313 |
* On reflection problems |
314 |
*/ |
315 |
public static void deleteKey(int hkey, String key) throws Exception, |
316 |
IllegalArgumentException, IllegalAccessException, |
317 |
InvocationTargetException { |
318 |
int rc = -1; |
319 |
if (!usable) |
320 |
throw new Exception( |
321 |
"Registry access not supported (not a Windows OS?)."); |
322 |
if (hkey == HKEY_LOCAL_MACHINE) { |
323 |
rc = deleteKey(systemRoot, hkey, key); |
324 |
} else if (hkey == HKEY_CURRENT_USER) { |
325 |
rc = deleteKey(userRoot, hkey, key); |
326 |
} |
327 |
if (rc != REG_SUCCESS) { |
328 |
throw new IllegalArgumentException("rc=" + rc + " key=" + key); |
329 |
} |
330 |
} |
331 |
|
332 |
/** |
333 |
* delete a value from a given key/value name |
334 |
* |
335 |
* @param hkey |
336 |
* HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE |
337 |
* @param key |
338 |
* Key to access |
339 |
* @param value |
340 |
* Name of value to delete |
341 |
* @param wow64 |
342 |
* 0 for standard registry access (32-bits for 32-bit app, |
343 |
* 64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to |
344 |
* 32-bit registry view, or KEY_WOW64_64KEY to force access to |
345 |
* 64-bit registry view |
346 |
* @throws Exception |
347 |
* If registry access impossible |
348 |
* @throws IllegalArgumentException |
349 |
* On illegal arguments |
350 |
* @throws IllegalAccessException |
351 |
* On illegal access |
352 |
* @throws InvocationTargetException |
353 |
* On reflection problems |
354 |
*/ |
355 |
public static void deleteValue(int hkey, String key, String value, int wow64) |
356 |
throws Exception, IllegalArgumentException, IllegalAccessException, |
357 |
InvocationTargetException { |
358 |
if (!usable) |
359 |
throw new Exception( |
360 |
"Registry access not supported (not a Windows OS?)."); |
361 |
int rc = -1; |
362 |
if (hkey == HKEY_LOCAL_MACHINE) { |
363 |
rc = deleteValue(systemRoot, hkey, key, value, wow64); |
364 |
} else if (hkey == HKEY_CURRENT_USER) { |
365 |
rc = deleteValue(userRoot, hkey, key, value, wow64); |
366 |
} |
367 |
if (rc != REG_SUCCESS) { |
368 |
throw new IllegalArgumentException("rc=" + rc + " key=" + key |
369 |
+ " value=" + value); |
370 |
} |
371 |
} |
372 |
|
373 |
// ======================================================================== |
374 |
private static int deleteValue(Preferences root, int hkey, String key, |
375 |
String value, int wow64) throws IllegalArgumentException, |
376 |
IllegalAccessException, InvocationTargetException { |
377 |
int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { |
378 |
new Integer(hkey), toCstr(key), |
379 |
new Integer(KEY_ALL_ACCESS | wow64) }); |
380 |
if (handles[1] != REG_SUCCESS) { |
381 |
return handles[1]; // can be REG_NOTFOUND, REG_ACCESSDENIED |
382 |
} |
383 |
int rc = ((Integer) regDeleteValue.invoke(root, new Object[] { |
384 |
new Integer(handles[0]), toCstr(value) })).intValue(); |
385 |
regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); |
386 |
return rc; |
387 |
} |
388 |
|
389 |
// ======================================================================== |
390 |
private static int deleteKey(Preferences root, int hkey, String key) |
391 |
throws IllegalArgumentException, IllegalAccessException, |
392 |
InvocationTargetException { |
393 |
int rc = ((Integer) regDeleteKey.invoke(root, new Object[] { |
394 |
new Integer(hkey), toCstr(key) })).intValue(); |
395 |
return rc; // can REG_NOTFOUND, REG_ACCESSDENIED, REG_SUCCESS |
396 |
} |
397 |
|
398 |
// ======================================================================== |
399 |
private static String readString(Preferences root, int hkey, String key, |
400 |
String value, int wow64) throws IllegalArgumentException, |
401 |
IllegalAccessException, InvocationTargetException { |
402 |
int[] handles = (int[]) regOpenKey |
403 |
.invoke(root, new Object[] { new Integer(hkey), toCstr(key), |
404 |
new Integer(KEY_READ | wow64) }); |
405 |
if (handles[1] != REG_SUCCESS) { |
406 |
return null; |
407 |
} |
408 |
byte[] valb = (byte[]) regQueryValueEx.invoke(root, new Object[] { |
409 |
new Integer(handles[0]), toCstr(value) }); |
410 |
regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); |
411 |
return (valb != null ? new String(valb).trim() : null); |
412 |
} |
413 |
|
414 |
// ======================================================================== |
415 |
private static Map<String, String> readStringValues(Preferences root, |
416 |
int hkey, String key, int wow64) throws Exception, |
417 |
IllegalArgumentException, IllegalAccessException, |
418 |
InvocationTargetException { |
419 |
HashMap<String, String> results = new HashMap<String, String>(); |
420 |
int[] handles = (int[]) regOpenKey |
421 |
.invoke(root, new Object[] { new Integer(hkey), toCstr(key), |
422 |
new Integer(KEY_READ | wow64) }); |
423 |
if (handles[1] != REG_SUCCESS) { |
424 |
return null; |
425 |
} |
426 |
int[] info = (int[]) regQueryInfoKey.invoke(root, |
427 |
new Object[] { new Integer(handles[0]) }); |
428 |
|
429 |
int count = info[2]; // count |
430 |
int maxlen = info[4]; // value length max |
431 |
for (int index = 0; index < count; index++) { |
432 |
byte[] name = (byte[]) regEnumValue.invoke(root, new Object[] { |
433 |
new Integer(handles[0]), new Integer(index), |
434 |
new Integer(maxlen + 1) }); |
435 |
String value = readString(hkey, key, new String(name), wow64); |
436 |
results.put(new String(name).trim(), value); |
437 |
} |
438 |
regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); |
439 |
return results; |
440 |
} |
441 |
|
442 |
// ======================================================================== |
443 |
private static List<String> readStringSubKeys(Preferences root, int hkey, |
444 |
String key, int wow64) throws IllegalArgumentException, |
445 |
IllegalAccessException, InvocationTargetException { |
446 |
List<String> results = new ArrayList<String>(); |
447 |
int[] handles = (int[]) regOpenKey |
448 |
.invoke(root, new Object[] { new Integer(hkey), toCstr(key), |
449 |
new Integer(KEY_READ | wow64) }); |
450 |
if (handles[1] != REG_SUCCESS) { |
451 |
return null; |
452 |
} |
453 |
int[] info = (int[]) regQueryInfoKey.invoke(root, |
454 |
new Object[] { new Integer(handles[0]) }); |
455 |
|
456 |
int count = info[0]; // Fix: info[2] was being used here with wrong |
457 |
// results. Suggested by davenpcj, confirmed by |
458 |
// Petrucio |
459 |
int maxlen = info[3]; // value length max |
460 |
for (int index = 0; index < count; index++) { |
461 |
byte[] name = (byte[]) regEnumKeyEx.invoke(root, new Object[] { |
462 |
new Integer(handles[0]), new Integer(index), |
463 |
new Integer(maxlen + 1) }); |
464 |
results.add(new String(name).trim()); |
465 |
} |
466 |
regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); |
467 |
return results; |
468 |
} |
469 |
|
470 |
// ======================================================================== |
471 |
private static int[] createKey(Preferences root, int hkey, String key) |
472 |
throws IllegalArgumentException, IllegalAccessException, |
473 |
InvocationTargetException { |
474 |
return (int[]) regCreateKeyEx.invoke(root, new Object[] { |
475 |
new Integer(hkey), toCstr(key) }); |
476 |
} |
477 |
|
478 |
// ======================================================================== |
479 |
private static void writeStringValue(Preferences root, int hkey, |
480 |
String key, String valueName, String value, int wow64) |
481 |
throws IllegalArgumentException, IllegalAccessException, |
482 |
InvocationTargetException { |
483 |
int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { |
484 |
new Integer(hkey), toCstr(key), |
485 |
new Integer(KEY_ALL_ACCESS | wow64) }); |
486 |
regSetValueEx.invoke(root, new Object[] { new Integer(handles[0]), |
487 |
toCstr(valueName), toCstr(value) }); |
488 |
regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); |
489 |
} |
490 |
|
491 |
// ======================================================================== |
492 |
// utility |
493 |
private static byte[] toCstr(String str) { |
494 |
byte[] result = new byte[str.length() + 1]; |
495 |
|
496 |
for (int i = 0; i < str.length(); i++) { |
497 |
result[i] = (byte) str.charAt(i); |
498 |
} |
499 |
result[str.length()] = 0; |
500 |
return result; |
501 |
} |
502 |
} |