nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
||
3 | * Copyright (C) 2014 Руслан Ижбулатов <lrn1986@gmail.com> |
||
4 | * |
||
5 | * This library is free software; you can redistribute it and/or |
||
6 | * modify it under the terms of the GNU Lesser General Public |
||
7 | * License as published by the Free Software Foundation; either |
||
8 | * version 2 of the License, or (at your option) any later version. |
||
9 | * |
||
10 | * This library is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
13 | * Lesser General Public License for more details. |
||
14 | * |
||
15 | * You should have received a copy of the GNU Lesser General |
||
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
||
17 | * |
||
18 | */ |
||
19 | |||
20 | #include "config.h" |
||
21 | #include "ginitable.h" |
||
22 | #include "gwin32registrykey.h" |
||
23 | #include <gio/gioerror.h> |
||
24 | #ifdef _MSC_VER |
||
25 | #pragma warning ( disable:4005 ) |
||
26 | #endif |
||
27 | #include <windows.h> |
||
28 | #include <ntstatus.h> |
||
29 | #include <winternl.h> |
||
30 | |||
31 | #ifndef _WDMDDK_ |
||
32 | typedef enum _KEY_INFORMATION_CLASS { |
||
33 | KeyBasicInformation, |
||
34 | KeyNodeInformation, |
||
35 | KeyFullInformation, |
||
36 | KeyNameInformation, |
||
37 | KeyCachedInformation, |
||
38 | KeyFlagsInformation, |
||
39 | KeyVirtualizationInformation, |
||
40 | KeyHandleTagsInformation, |
||
41 | MaxKeyInfoClass |
||
42 | } KEY_INFORMATION_CLASS; |
||
43 | |||
44 | typedef struct _KEY_BASIC_INFORMATION { |
||
45 | LARGE_INTEGER LastWriteTime; |
||
46 | ULONG TitleIndex; |
||
47 | ULONG NameLength; |
||
48 | WCHAR Name[1]; |
||
49 | } KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; |
||
50 | #endif |
||
51 | |||
52 | #if !defined (__OBJECT_ATTRIBUTES_DEFINED) && defined (__MINGW32_) |
||
53 | #define __OBJECT_ATTRIBUTES_DEFINED |
||
54 | typedef struct _OBJECT_ATTRIBUTES { |
||
55 | ULONG Length; |
||
56 | #ifdef _WIN64 |
||
57 | ULONG pad1; |
||
58 | #endif |
||
59 | HANDLE RootDirectory; |
||
60 | PUNICODE_STRING ObjectName; |
||
61 | ULONG Attributes; |
||
62 | #ifdef _WIN64 |
||
63 | ULONG pad2; |
||
64 | #endif |
||
65 | PVOID SecurityDescriptor; |
||
66 | PVOID SecurityQualityOfService; |
||
67 | } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; |
||
68 | #endif |
||
69 | |||
70 | #ifndef HKEY_CURRENT_USER_LOCAL_SETTINGS |
||
71 | #define HKEY_CURRENT_USER_LOCAL_SETTINGS ((HKEY) (ULONG_PTR)((LONG)0x80000007)) |
||
72 | #endif |
||
73 | |||
74 | #if !defined (__UNICODE_STRING_DEFINED) && defined (__MINGW32_) |
||
75 | #define __UNICODE_STRING_DEFINED |
||
76 | typedef struct _UNICODE_STRING { |
||
77 | USHORT Length; |
||
78 | USHORT MaximumLength; |
||
79 | PWSTR Buffer; |
||
80 | } UNICODE_STRING, *PUNICODE_STRING; |
||
81 | #endif |
||
82 | typedef const UNICODE_STRING* PCUNICODE_STRING; |
||
83 | |||
84 | typedef NTSTATUS |
||
85 | (NTAPI * NtQueryKeyFunc)(HANDLE key_handle, |
||
86 | KEY_INFORMATION_CLASS key_info_class, |
||
87 | PVOID key_info_buffer, |
||
88 | ULONG key_info_buffer_size, |
||
89 | PULONG result_size); |
||
90 | |||
91 | typedef NTSTATUS |
||
92 | (* NtNotifyChangeMultipleKeysFunc)(HANDLE key_handle, |
||
93 | ULONG subkey_count, |
||
94 | POBJECT_ATTRIBUTES subkeys, |
||
95 | HANDLE event, |
||
96 | PIO_APC_ROUTINE apc_routine, |
||
97 | PVOID apc_closure, |
||
98 | PIO_STATUS_BLOCK status_block, |
||
99 | ULONG filter, |
||
100 | BOOLEAN watch_tree, |
||
101 | PVOID buffer, |
||
102 | ULONG buffer_size, |
||
103 | BOOLEAN async); |
||
104 | |||
105 | static NtQueryKeyFunc nt_query_key = NULL; |
||
106 | static NtNotifyChangeMultipleKeysFunc nt_notify_change_multiple_keys = NULL; |
||
107 | |||
108 | #define G_WIN32_KEY_UNWATCHED 0 |
||
109 | #define G_WIN32_KEY_WATCHED 1 |
||
110 | #define G_WIN32_KEY_UNCHANGED 0 |
||
111 | #define G_WIN32_KEY_CHANGED 1 |
||
112 | #define G_WIN32_KEY_UNKNOWN -1 |
||
113 | |||
114 | enum |
||
115 | { |
||
116 | PROP_0, |
||
117 | PROP_PATH, |
||
118 | PROP_PATH_UTF16, |
||
119 | PROP_MAX, |
||
120 | }; |
||
121 | |||
122 | typedef enum |
||
123 | { |
||
124 | G_WIN32_REGISTRY_UPDATED_NOTHING = 0, |
||
125 | G_WIN32_REGISTRY_UPDATED_PATH = 1, |
||
126 | } GWin32RegistryKeyUpdateFlag; |
||
127 | |||
128 | static gunichar2 * |
||
129 | g_wcsdup (const gunichar2 *str, |
||
130 | gssize str_size) |
||
131 | { |
||
132 | if (str_size == -1) |
||
133 | { |
||
134 | str_size = wcslen (str) + 1; |
||
135 | str_size *= sizeof (gunichar2); |
||
136 | } |
||
137 | return g_memdup (str, str_size); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * g_win32_registry_subkey_iter_copy: |
||
142 | * @iter: an iterator |
||
143 | * |
||
144 | * Creates a dynamically-allocated copy of an iterator. Dynamically-allocated |
||
145 | * state of the iterator is duplicated too. |
||
146 | * |
||
147 | * Returns: (transfer full): a copy of the @iter, |
||
148 | * free with g_win32_registry_subkey_iter_free () |
||
149 | * |
||
150 | * Since: 2.46 |
||
151 | **/ |
||
152 | GWin32RegistrySubkeyIter * |
||
153 | g_win32_registry_subkey_iter_copy (const GWin32RegistrySubkeyIter *iter) |
||
154 | { |
||
155 | GWin32RegistrySubkeyIter *new_iter; |
||
156 | |||
157 | g_return_val_if_fail (iter != NULL, NULL); |
||
158 | |||
159 | new_iter = g_new0 (GWin32RegistrySubkeyIter, 1); |
||
160 | |||
161 | new_iter->key = g_object_ref (iter->key); |
||
162 | new_iter->counter = iter->counter; |
||
163 | new_iter->subkey_count = iter->subkey_count; |
||
164 | new_iter->subkey_name = g_wcsdup (iter->subkey_name, iter->subkey_name_size); |
||
165 | new_iter->subkey_name_size = iter->subkey_name_size; |
||
166 | |||
167 | if (iter->subkey_name_u8) |
||
168 | new_iter->subkey_name_u8 = iter->subkey_name_u8; |
||
169 | else |
||
170 | new_iter->subkey_name_u8 = NULL; |
||
171 | |||
172 | return new_iter; |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * g_win32_registry_subkey_iter_free: |
||
177 | * @iter: a dynamically-allocated iterator |
||
178 | * |
||
179 | * Free an iterator allocated on the heap. For iterators that are allocated |
||
180 | * on the stack use g_win32_registry_subkey_iter_clear () instead. |
||
181 | * |
||
182 | * Since: 2.46 |
||
183 | **/ |
||
184 | void |
||
185 | g_win32_registry_subkey_iter_free (GWin32RegistrySubkeyIter *iter) |
||
186 | { |
||
187 | g_return_if_fail (iter != NULL); |
||
188 | |||
189 | g_object_unref (iter->key); |
||
190 | g_free (iter->subkey_name); |
||
191 | g_free (iter->subkey_name_u8); |
||
192 | g_free (iter); |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * g_win32_registry_subkey_iter_assign: |
||
197 | * @iter: a #GWin32RegistrySubkeyIter |
||
198 | * @other: another #GWin32RegistrySubkeyIter |
||
199 | * |
||
200 | * Assigns the value of @other to @iter. This function |
||
201 | * is not useful in applications, because iterators can be assigned |
||
202 | * with `GWin32RegistrySubkeyIter i = j;`. The |
||
203 | * function is used by language bindings. |
||
204 | * |
||
205 | * Since: 2.46 |
||
206 | **/ |
||
207 | void |
||
208 | g_win32_registry_subkey_iter_assign (GWin32RegistrySubkeyIter *iter, |
||
209 | const GWin32RegistrySubkeyIter *other) |
||
210 | { |
||
211 | g_return_if_fail (iter != NULL); |
||
212 | g_return_if_fail (other != NULL); |
||
213 | |||
214 | *iter = *other; |
||
215 | } |
||
216 | |||
217 | |||
218 | G_DEFINE_BOXED_TYPE (GWin32RegistrySubkeyIter, g_win32_registry_subkey_iter, |
||
219 | g_win32_registry_subkey_iter_copy, |
||
220 | g_win32_registry_subkey_iter_free) |
||
221 | |||
222 | /** |
||
223 | * g_win32_registry_value_iter_copy: |
||
224 | * @iter: an iterator |
||
225 | * |
||
226 | * Creates a dynamically-allocated copy of an iterator. Dynamically-allocated |
||
227 | * state of the iterator is duplicated too. |
||
228 | * |
||
229 | * Returns: (transfer full): a copy of the @iter, |
||
230 | * free with g_win32_registry_value_iter_free (). |
||
231 | * |
||
232 | * Since: 2.46 |
||
233 | **/ |
||
234 | GWin32RegistryValueIter * |
||
235 | g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter) |
||
236 | { |
||
237 | GWin32RegistryValueIter *new_iter; |
||
238 | |||
239 | g_return_val_if_fail (iter != NULL, NULL); |
||
240 | |||
241 | new_iter = g_new0 (GWin32RegistryValueIter, 1); |
||
242 | |||
243 | new_iter->key = g_object_ref (iter->key); |
||
244 | new_iter->counter = iter->counter; |
||
245 | new_iter->value_count = iter->value_count; |
||
246 | new_iter->value_name = g_wcsdup (iter->value_name, iter->value_name_size); |
||
247 | new_iter->value_name_size = iter->value_name_size; |
||
248 | |||
249 | if (iter->value_data != NULL) |
||
250 | new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size); |
||
251 | |||
252 | new_iter->value_data_size = iter->value_data_size; |
||
253 | |||
254 | if (iter->value_name_u8 != NULL) |
||
255 | new_iter->value_name_u8 = g_strdup (iter->value_name_u8); |
||
256 | |||
257 | new_iter->value_name_u8_len = iter->value_name_u8_len; |
||
258 | |||
259 | if (iter->value_data_u8 != NULL) |
||
260 | new_iter->value_data_u8 = g_strdup (iter->value_data_u8); |
||
261 | |||
262 | new_iter->value_data_u8_size = iter->value_data_u8_size; |
||
263 | |||
264 | if (iter->value_data_expanded != NULL) |
||
265 | new_iter->value_data_expanded = g_wcsdup ((gunichar2 *) iter->value_data_expanded, |
||
266 | iter->value_data_expanded_charsize * sizeof (gunichar2)); |
||
267 | |||
268 | new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize; |
||
269 | |||
270 | if (iter->value_data_expanded_u8 != NULL) |
||
271 | new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8, |
||
272 | iter->value_data_expanded_charsize); |
||
273 | |||
274 | new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize; |
||
275 | |||
276 | return new_iter; |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * g_win32_registry_value_iter_free: |
||
281 | * @iter: a dynamically-allocated iterator |
||
282 | * |
||
283 | * Free an iterator allocated on the heap. For iterators that are allocated |
||
284 | * on the stack use g_win32_registry_value_iter_clear () instead. |
||
285 | * |
||
286 | * Since: 2.46 |
||
287 | **/ |
||
288 | void |
||
289 | g_win32_registry_value_iter_free (GWin32RegistryValueIter *iter) |
||
290 | { |
||
291 | g_return_if_fail (iter != NULL); |
||
292 | |||
293 | g_object_unref (iter->key); |
||
294 | g_free (iter->value_name); |
||
295 | g_free (iter->value_data); |
||
296 | g_free (iter->value_data_expanded); |
||
297 | g_free (iter->value_name_u8); |
||
298 | g_free (iter->value_data_u8); |
||
299 | g_free (iter->value_data_expanded_u8); |
||
300 | g_free (iter); |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * g_win32_registry_value_iter_assign: |
||
305 | * @iter: a #GWin32RegistryValueIter |
||
306 | * @other: another #GWin32RegistryValueIter |
||
307 | * |
||
308 | * Assigns the value of @other to @iter. This function |
||
309 | * is not useful in applications, because iterators can be assigned |
||
310 | * with `GWin32RegistryValueIter i = j;`. The |
||
311 | * function is used by language bindings. |
||
312 | * |
||
313 | * Since: 2.46 |
||
314 | **/ |
||
315 | void |
||
316 | g_win32_registry_value_iter_assign (GWin32RegistryValueIter *iter, |
||
317 | const GWin32RegistryValueIter *other) |
||
318 | { |
||
319 | g_return_if_fail (iter != NULL); |
||
320 | g_return_if_fail (other != NULL); |
||
321 | |||
322 | *iter = *other; |
||
323 | } |
||
324 | |||
325 | G_DEFINE_BOXED_TYPE (GWin32RegistryValueIter, g_win32_registry_value_iter, |
||
326 | g_win32_registry_value_iter_copy, |
||
327 | g_win32_registry_value_iter_free) |
||
328 | |||
329 | /** |
||
330 | * SECTION:gwin32registrykey |
||
331 | * @title: GWin32RegistryKey |
||
332 | * @short_description: W32 registry access helper |
||
333 | * @include: gio/win32/gwin32registrykey.h |
||
334 | * |
||
335 | * #GWin32RegistryKey represents a single Windows Registry key. |
||
336 | * |
||
337 | * #GWin32RegistryKey is used by a number of helper functions that read |
||
338 | * Windows Registry. All keys are opened with read-only access, and at |
||
339 | * the moment there is no API for writing into registry keys or creating |
||
340 | * new ones. |
||
341 | * |
||
342 | * #GWin32RegistryKey implements the #GInitable interface, so if it is manually |
||
343 | * constructed by e.g. g_object_new() you must call g_initable_init() and check |
||
344 | * the results before using the object. This is done automatically |
||
345 | * in g_win32_registry_key_new() and g_win32_registry_key_get_child(), so these |
||
346 | * functions can return %NULL. |
||
347 | * |
||
348 | * To increase efficiency, a UTF-16 variant is available for all functions |
||
349 | * that deal with key or value names in the registry. Use these to perform |
||
350 | * deep registry queries or other operations that require querying a name |
||
351 | * of a key or a value and then opening it (or querying its data). The use |
||
352 | * of UTF-16 functions avoids the overhead of converting names to UTF-8 and |
||
353 | * back. |
||
354 | * |
||
355 | * All functions operate in current user's context (it is not possible to |
||
356 | * access registry tree of a different user). |
||
357 | * |
||
358 | * Key paths must use '\\' as a separator, '/' is not supported. Key names |
||
359 | * must not include '\\', because it's used as a separator. Value names |
||
360 | * can include '\\'. |
||
361 | * |
||
362 | * Key and value names are not case sensitive. |
||
363 | * |
||
364 | * Full key name (excluding the pre-defined ancestor's name) can't exceed |
||
365 | * 255 UTF-16 characters, give or take. Value name can't exceed 16383 UTF-16 |
||
366 | * characters. Tree depth is limited to 512 levels. |
||
367 | **/ |
||
368 | |||
369 | struct _GWin32RegistryKeyPrivate { |
||
370 | /* Ancestor of this key. May not be the immediate parent, because |
||
371 | * RegOpenKeyEx() allows grand*-children to be opened transitively. |
||
372 | * May be NULL. |
||
373 | */ |
||
374 | GWin32RegistryKey *ancestor; |
||
375 | |||
376 | /* Handle to the key */ |
||
377 | HKEY handle; |
||
378 | |||
379 | /* Full absolute path of the key, in UTF-16. Always allocated. |
||
380 | * Can become out of sync if the key is renamed from while we have it |
||
381 | * open, check watch_indicator to see if anything changed. |
||
382 | */ |
||
383 | gunichar2 *absolute_path_w; |
||
384 | |||
385 | /* Full absolute path of the key, in UTF-8. Allocated when needed by |
||
386 | * converting the UTF-16 value from absolute_path_w. */ |
||
387 | gchar *absolute_path; |
||
388 | |||
389 | /* TRUE if this object represents one of the pre-defined keys |
||
390 | * (and thus must not be closed). |
||
391 | */ |
||
392 | gboolean predefined; |
||
393 | |||
394 | /* Set to G_WIN32_KEY_UNWATCHED if the key is not being watched. |
||
395 | * Set to G_WIN32_KEY_WATCHED when the key is put on watch notification. |
||
396 | */ |
||
397 | gint watch_indicator; |
||
398 | |||
399 | /* Set to G_WIN32_KEY_UNKNOWN while the key is not being watched. |
||
400 | * Set to G_WIN32_KEY_UNCHANGED once the key is put under watch. |
||
401 | * Set to G_WIN32_KEY_CHANGED by the watch notification APC on key change. |
||
402 | */ |
||
403 | gint change_indicator; |
||
404 | |||
405 | /* Unset after the key is changed, individual bits are set when their |
||
406 | * respective key parameters are updated from the registry. |
||
407 | * This prevents GLib from re-querying things like key name each time |
||
408 | * one is requested by the client while key is in G_WIN32_KEY_CHANGED state. |
||
409 | */ |
||
410 | GWin32RegistryKeyUpdateFlag update_flags; |
||
411 | |||
412 | GWin32RegistryKeyWatchCallbackFunc callback; |
||
413 | |||
414 | gpointer user_data; |
||
415 | }; |
||
416 | |||
417 | static void g_win32_registry_key_initable_iface_init (GInitableIface *iface); |
||
418 | static gboolean g_win32_registry_key_initable_init (GInitable *initable, |
||
419 | GCancellable *cancellable, |
||
420 | GError **error); |
||
421 | |||
422 | G_DEFINE_TYPE_WITH_CODE (GWin32RegistryKey, g_win32_registry_key, G_TYPE_OBJECT, |
||
423 | G_ADD_PRIVATE (GWin32RegistryKey) |
||
424 | G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, |
||
425 | g_win32_registry_key_initable_iface_init)); |
||
426 | |||
427 | static void |
||
428 | g_win32_registry_key_dispose (GObject *object) |
||
429 | { |
||
430 | GWin32RegistryKey *key; |
||
431 | GWin32RegistryKeyPrivate *priv; |
||
432 | |||
433 | key = G_WIN32_REGISTRY_KEY (object); |
||
434 | priv = key->priv; |
||
435 | |||
436 | g_clear_object (&priv->ancestor); |
||
437 | g_clear_pointer (&priv->absolute_path_w, g_free); |
||
438 | g_clear_pointer (&priv->absolute_path, g_free); |
||
439 | |||
440 | if (!priv->predefined && priv->handle != INVALID_HANDLE_VALUE) |
||
441 | { |
||
442 | RegCloseKey (priv->handle); |
||
443 | priv->handle = INVALID_HANDLE_VALUE; |
||
444 | } |
||
445 | |||
446 | G_OBJECT_CLASS (g_win32_registry_key_parent_class)->dispose (object); |
||
447 | } |
||
448 | |||
449 | /** |
||
450 | * g_win32_registry_key_new: |
||
451 | * @path: absolute full name of a key to open (in UTF-8) |
||
452 | * @error: (nullable): a pointer to a %NULL #GError, or %NULL |
||
453 | * |
||
454 | * Creates an object that represents a registry key specified by @path. |
||
455 | * @path must start with one of the following pre-defined names: |
||
456 | * - HKEY_CLASSES_ROOT |
||
457 | * - HKEY_CURRENT_CONFIG |
||
458 | * - HKEY_CURRENT_USER |
||
459 | * - HKEY_CURRENT_USER_LOCAL_SETTINGS |
||
460 | * - HKEY_LOCAL_MACHINE |
||
461 | * - HKEY_PERFORMANCE_DATA |
||
462 | * - HKEY_PERFORMANCE_NLSTEXT |
||
463 | * - HKEY_PERFORMANCE_TEXT |
||
464 | * - HKEY_USERS |
||
465 | * @path must not end with '\\'. |
||
466 | * |
||
467 | * Returns: (nullable) (transfer full): a #GWin32RegistryKey or %NULL if can't |
||
468 | * be opened. Free with g_object_unref(). |
||
469 | */ |
||
470 | GWin32RegistryKey * |
||
471 | g_win32_registry_key_new (const gchar *path, |
||
472 | GError **error) |
||
473 | { |
||
474 | g_return_val_if_fail (path != NULL, NULL); |
||
475 | |||
476 | return g_initable_new (G_TYPE_WIN32_REGISTRY_KEY, |
||
477 | NULL, |
||
478 | error, |
||
479 | "path", |
||
480 | path, |
||
481 | NULL); |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * g_win32_registry_key_new_w: |
||
486 | * @path: (in) (transfer none): absolute full name of a key to open (in UTF-16) |
||
487 | * @error: (inout) (nullable): a pointer to a %NULL #GError, or %NULL |
||
488 | * |
||
489 | * Creates an object that represents a registry key specified by @path. |
||
490 | * @path must start with one of the following pre-defined names: |
||
491 | * - HKEY_CLASSES_ROOT |
||
492 | * - HKEY_CURRENT_CONFIG |
||
493 | * - HKEY_CURRENT_USER |
||
494 | * - HKEY_CURRENT_USER_LOCAL_SETTINGS |
||
495 | * - HKEY_LOCAL_MACHINE |
||
496 | * - HKEY_PERFORMANCE_DATA |
||
497 | * - HKEY_PERFORMANCE_NLSTEXT |
||
498 | * - HKEY_PERFORMANCE_TEXT |
||
499 | * - HKEY_USERS |
||
500 | * @path must not end with L'\\'. |
||
501 | * |
||
502 | * Returns: (nullable) (transfer full): a #GWin32RegistryKey or %NULL if can't |
||
503 | * be opened. Free with g_object_unref(). |
||
504 | */ |
||
505 | GWin32RegistryKey * |
||
506 | g_win32_registry_key_new_w (const gunichar2 *path, |
||
507 | GError **error) |
||
508 | { |
||
509 | GObject *result; |
||
510 | |||
511 | g_return_val_if_fail (path != NULL, NULL); |
||
512 | |||
513 | result = g_initable_new (G_TYPE_WIN32_REGISTRY_KEY, |
||
514 | NULL, |
||
515 | error, |
||
516 | "path-utf16", |
||
517 | g_wcsdup (path, -1), |
||
518 | NULL); |
||
519 | |||
520 | return result ? G_WIN32_REGISTRY_KEY (result) : NULL; |
||
521 | } |
||
522 | |||
523 | static void |
||
524 | g_win32_registry_key_initable_iface_init (GInitableIface *iface) |
||
525 | { |
||
526 | iface->init = g_win32_registry_key_initable_init; |
||
527 | } |
||
528 | |||
529 | static gboolean |
||
530 | g_win32_registry_key_initable_init (GInitable *initable, |
||
531 | GCancellable *cancellable, |
||
532 | GError **error) |
||
533 | { |
||
534 | GWin32RegistryKey *key; |
||
535 | GWin32RegistryKeyPrivate *priv; |
||
536 | gunichar2 *path; |
||
537 | gunichar2 *first_chunk_end; |
||
538 | gsize first_chunk_len; |
||
539 | gunichar2 *second_chunk_begin; |
||
540 | gunichar2 *first_chunk; |
||
541 | HKEY ancestor; |
||
542 | HKEY key_handle; |
||
543 | LONG opened; |
||
544 | |||
545 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (initable), FALSE); |
||
546 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
547 | |||
548 | key = G_WIN32_REGISTRY_KEY (initable); |
||
549 | priv = key->priv; |
||
550 | |||
551 | if (priv->absolute_path_w == NULL) |
||
552 | { |
||
553 | priv->absolute_path_w = g_utf8_to_utf16 (priv->absolute_path, |
||
554 | -1, |
||
555 | NULL, |
||
556 | NULL, |
||
557 | error); |
||
558 | |||
559 | if (priv->absolute_path_w == NULL) |
||
560 | return FALSE; |
||
561 | } |
||
562 | |||
563 | path = priv->absolute_path_w; |
||
564 | |||
565 | first_chunk_end = wcschr (path, L'\\'); |
||
566 | |||
567 | if (first_chunk_end == NULL) |
||
568 | first_chunk_end = &path[wcslen (path)]; |
||
569 | |||
570 | first_chunk_len = first_chunk_end - path; |
||
571 | first_chunk = g_wcsdup (path, -1); |
||
572 | first_chunk[first_chunk_len] = L'\0'; |
||
573 | if (wcscmp (first_chunk, L"HKEY_CLASSES_ROOT") == 0) |
||
574 | ancestor = HKEY_CLASSES_ROOT; |
||
575 | else if (wcscmp (first_chunk, L"HKEY_LOCAL_MACHINE") == 0) |
||
576 | ancestor = HKEY_LOCAL_MACHINE; |
||
577 | else if (wcscmp (first_chunk, L"HKEY_CURRENT_USER") == 0) |
||
578 | ancestor = HKEY_CURRENT_USER; |
||
579 | else if (wcscmp (first_chunk, L"HKEY_CURRENT_CONFIG") == 0) |
||
580 | ancestor = HKEY_CURRENT_CONFIG; |
||
581 | else if (wcscmp (first_chunk, L"HKEY_CURRENT_USER_LOCAL_SETTINGS") == 0) |
||
582 | ancestor = HKEY_CURRENT_USER_LOCAL_SETTINGS; |
||
583 | else if (wcscmp (first_chunk, L"HKEY_USERS") == 0) |
||
584 | ancestor = HKEY_USERS; |
||
585 | else if (wcscmp (first_chunk, L"HKEY_PERFORMANCE_DATA") == 0) |
||
586 | ancestor = HKEY_PERFORMANCE_DATA; |
||
587 | else if (wcscmp (first_chunk, L"HKEY_PERFORMANCE_NLSTEXT") == 0) |
||
588 | ancestor = HKEY_PERFORMANCE_NLSTEXT; |
||
589 | else if (wcscmp (first_chunk, L"HKEY_PERFORMANCE_TEXT") == 0) |
||
590 | ancestor = HKEY_PERFORMANCE_TEXT; |
||
591 | else |
||
592 | { |
||
593 | g_critical ("Root key '%S' is not a pre-defined key", first_chunk); |
||
594 | g_free (first_chunk); |
||
595 | return FALSE; |
||
596 | } |
||
597 | |||
598 | g_free (first_chunk); |
||
599 | |||
600 | second_chunk_begin = first_chunk_end; |
||
601 | |||
602 | while (second_chunk_begin[0] != L'\0' && second_chunk_begin[0] == L'\\') |
||
603 | second_chunk_begin++; |
||
604 | |||
605 | if (second_chunk_begin != first_chunk_end && second_chunk_begin[0] == L'\0') |
||
606 | { |
||
607 | g_critical ("Key name '%S' ends with '\\'", path); |
||
608 | return FALSE; |
||
609 | } |
||
610 | |||
611 | opened = RegOpenKeyExW (ancestor, second_chunk_begin, 0, KEY_READ, &key_handle); |
||
612 | |||
613 | if (opened != ERROR_SUCCESS) |
||
614 | { |
||
615 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (opened), |
||
616 | "Failed to open registry key '%S'", path); |
||
617 | return FALSE; |
||
618 | } |
||
619 | |||
620 | priv->ancestor = NULL; |
||
621 | priv->handle = key_handle; |
||
622 | priv->predefined = (second_chunk_begin[0] == L'\0'); |
||
623 | |||
624 | return TRUE; |
||
625 | } |
||
626 | |||
627 | /** |
||
628 | * g_win32_registry_key_get_child: |
||
629 | * @key: (in) (transfer none): a parent #GWin32RegistryKey |
||
630 | * @subkey: (in) (transfer none): name of a child key to open (in UTF-8), relative to @key |
||
631 | * @error: (inout) (nullable): a pointer to a %NULL #GError, or %NULL |
||
632 | * |
||
633 | * Opens a @subkey of the @key. |
||
634 | * |
||
635 | * Returns: (nullable): a #GWin32RegistryKey or %NULL if can't be opened. Free |
||
636 | * with g_object_unref(). |
||
637 | */ |
||
638 | GWin32RegistryKey * |
||
639 | g_win32_registry_key_get_child (GWin32RegistryKey *key, |
||
640 | const gchar *subkey, |
||
641 | GError **error) |
||
642 | { |
||
643 | gunichar2 *subkey_w; |
||
644 | GWin32RegistryKey *result = NULL; |
||
645 | |||
646 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL); |
||
647 | g_return_val_if_fail (subkey != NULL, NULL); |
||
648 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
649 | |||
650 | subkey_w = g_utf8_to_utf16 (subkey, -1, NULL, NULL, error); |
||
651 | |||
652 | if (subkey_w != NULL) |
||
653 | { |
||
654 | result = g_win32_registry_key_get_child_w (key, subkey_w, error); |
||
655 | g_free (subkey_w); |
||
656 | } |
||
657 | |||
658 | return result; |
||
659 | } |
||
660 | |||
661 | /** |
||
662 | * g_win32_registry_key_get_child_w: |
||
663 | * @key: (in) (transfer none): a parent #GWin32RegistryKey |
||
664 | * @subkey: (in) (transfer none): name of a child key to open (in UTF-8), relative to @key |
||
665 | * @error: (inout) (nullable): a pointer to a %NULL #GError, or %NULL |
||
666 | * |
||
667 | * Opens a @subkey of the @key. |
||
668 | * |
||
669 | * Returns: (nullable): a #GWin32RegistryKey or %NULL if can't be opened. Free |
||
670 | * with g_object_unref(). |
||
671 | */ |
||
672 | GWin32RegistryKey * |
||
673 | g_win32_registry_key_get_child_w (GWin32RegistryKey *key, |
||
674 | const gunichar2 *subkey, |
||
675 | GError **error) |
||
676 | { |
||
677 | HKEY key_handle; |
||
678 | LONG opened; |
||
679 | const gunichar2 *end_of_subkey; |
||
680 | gsize subkey_len; |
||
681 | GWin32RegistryKey *result; |
||
682 | const gunichar2 *key_path; |
||
683 | |||
684 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL); |
||
685 | g_return_val_if_fail (subkey != NULL, NULL); |
||
686 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
687 | |||
688 | if (subkey[0] == L'\\') |
||
689 | { |
||
690 | g_critical ("Subkey name '%S' starts with '\\'", subkey); |
||
691 | return NULL; |
||
692 | } |
||
693 | |||
694 | subkey_len = wcslen (subkey); |
||
695 | end_of_subkey = &subkey[subkey_len]; |
||
696 | |||
697 | if (subkey_len == 0) |
||
698 | end_of_subkey = subkey; |
||
699 | |||
700 | if (end_of_subkey[0] == L'\\') |
||
701 | { |
||
702 | g_critical ("Subkey name '%S' ends with '\\'", subkey); |
||
703 | return NULL; |
||
704 | } |
||
705 | |||
706 | key_path = g_win32_registry_key_get_path_w (key); |
||
707 | opened = RegOpenKeyExW (key->priv->handle, subkey, 0, KEY_READ, &key_handle); |
||
708 | |||
709 | if (opened != ERROR_SUCCESS) |
||
710 | { |
||
711 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (opened), |
||
712 | "Failed to open registry subkey '%S' of key '%S'", |
||
713 | subkey, key_path); |
||
714 | return NULL; |
||
715 | } |
||
716 | |||
717 | result = g_object_new (G_TYPE_WIN32_REGISTRY_KEY, NULL); |
||
718 | |||
719 | result->priv->handle = key_handle; |
||
720 | result->priv->absolute_path_w = |
||
721 | g_malloc ((wcslen (key_path) + 2 + subkey_len) * sizeof (gunichar2)); |
||
722 | result->priv->absolute_path_w[0] = L'\0'; |
||
723 | wcscat (&result->priv->absolute_path_w[0], key_path); |
||
724 | wcscat (&result->priv->absolute_path_w[wcslen (key_path)], L"\\"); |
||
725 | wcscat (&result->priv->absolute_path_w[wcslen (key_path) + 1], subkey); |
||
726 | result->priv->predefined = (subkey[0] == L'\0' && key->priv->predefined); |
||
727 | |||
728 | if (subkey[0] != L'\0') |
||
729 | result->priv->ancestor = g_object_ref (key); |
||
730 | else |
||
731 | result->priv->ancestor = NULL; |
||
732 | |||
733 | result->priv->change_indicator = G_WIN32_KEY_UNKNOWN; |
||
734 | |||
735 | return result; |
||
736 | } |
||
737 | |||
738 | /** |
||
739 | * g_win32_registry_subkey_iter_init: |
||
740 | * @iter: (in) (transfer none): a pointer to a #GWin32RegistrySubkeyIter |
||
741 | * @key: (in) (transfer none): a #GWin32RegistryKey to iterate over |
||
742 | * @error: (inout) (nullable): a pointer to %NULL #GError, or %NULL |
||
743 | * |
||
744 | * Initialises (without allocating) a #GWin32RegistrySubkeyIter. @iter may be |
||
745 | * completely uninitialised prior to this call; its old value is |
||
746 | * ignored. |
||
747 | * |
||
748 | * The iterator remains valid for as long as @key exists. |
||
749 | * Clean up its internal buffers with a call to |
||
750 | * g_win32_registry_subkey_iter_clear() when done. |
||
751 | * |
||
752 | * Returns: %TRUE if iterator was initialized successfully, %FALSE on error. |
||
753 | * |
||
754 | * Since: 2.46 |
||
755 | **/ |
||
756 | gboolean |
||
757 | g_win32_registry_subkey_iter_init (GWin32RegistrySubkeyIter *iter, |
||
758 | GWin32RegistryKey *key, |
||
759 | GError **error) |
||
760 | { |
||
761 | LONG status; |
||
762 | DWORD subkey_count; |
||
763 | DWORD max_subkey_len; |
||
764 | |||
765 | g_return_val_if_fail (iter != NULL, FALSE); |
||
766 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); |
||
767 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
768 | |||
769 | status = RegQueryInfoKeyW (key->priv->handle, |
||
770 | NULL, NULL, NULL, |
||
771 | &subkey_count, &max_subkey_len, |
||
772 | NULL, NULL, NULL, NULL, NULL, NULL); |
||
773 | |||
774 | if (status != ERROR_SUCCESS) |
||
775 | { |
||
776 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status), |
||
777 | "Failed to query info for registry key '%S'", |
||
778 | g_win32_registry_key_get_path_w (key)); |
||
779 | return FALSE; |
||
780 | } |
||
781 | |||
782 | iter->key = g_object_ref (key); |
||
783 | iter->counter = -1; |
||
784 | iter->subkey_count = subkey_count; |
||
785 | iter->subkey_name_size = sizeof (gunichar2) * (max_subkey_len + 1); |
||
786 | iter->subkey_name = g_malloc (iter->subkey_name_size); |
||
787 | iter->subkey_name_u8 = NULL; |
||
788 | |||
789 | return TRUE; |
||
790 | } |
||
791 | |||
792 | /** |
||
793 | * g_win32_registry_subkey_iter_clear: |
||
794 | * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter |
||
795 | * |
||
796 | * Frees internal buffers of a #GWin32RegistrySubkeyIter. |
||
797 | * |
||
798 | * Since: 2.46 |
||
799 | **/ |
||
800 | void |
||
801 | g_win32_registry_subkey_iter_clear (GWin32RegistrySubkeyIter *iter) |
||
802 | { |
||
803 | g_return_if_fail (iter != NULL); |
||
804 | |||
805 | g_free (iter->subkey_name); |
||
806 | g_free (iter->subkey_name_u8); |
||
807 | g_clear_object (&iter->key); |
||
808 | } |
||
809 | |||
810 | /** |
||
811 | * g_win32_registry_subkey_iter_n_subkeys: |
||
812 | * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter |
||
813 | * |
||
814 | * Queries the number of subkeys items in the key that we are |
||
815 | * iterating over. This is the total number of subkeys -- not the number |
||
816 | * of items remaining. |
||
817 | * |
||
818 | * This information is accurate at the point of iterator initialization, |
||
819 | * and may go out of sync with reality even while subkeys are enumerated. |
||
820 | * |
||
821 | * Returns: the number of subkeys in the key |
||
822 | * |
||
823 | * Since: 2.46 |
||
824 | **/ |
||
825 | gsize |
||
826 | g_win32_registry_subkey_iter_n_subkeys (GWin32RegistrySubkeyIter *iter) |
||
827 | { |
||
828 | g_return_val_if_fail (iter != NULL, 0); |
||
829 | |||
830 | return iter->subkey_count; |
||
831 | } |
||
832 | |||
833 | /** |
||
834 | * g_win32_registry_subkey_iter_next: |
||
835 | * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter |
||
836 | * @skip_errors: (in): %TRUE if iterator should silently ignore errors (such as |
||
837 | * the actual number of subkeys being less than expected) and |
||
838 | * proceed forward |
||
839 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
840 | * |
||
841 | * Moves iterator to the next subkey. |
||
842 | * Enumeration errors can be ignored if @skip_errors is %TRUE |
||
843 | * |
||
844 | * Here is an example for iterating with g_win32_registry_subkey_iter_next(): |
||
845 | * |[<!-- language="C" --> |
||
846 | * // recursively iterate a key |
||
847 | * void |
||
848 | * iterate_key_recursive (GWin32RegistryKey *key) |
||
849 | * { |
||
850 | * GWin32RegistrySubkeyIter iter; |
||
851 | * gchar *name; |
||
852 | * GWin32RegistryKey *child; |
||
853 | * |
||
854 | * if (!g_win32_registry_subkey_iter_init (&iter, key, NULL)) |
||
855 | * return; |
||
856 | * |
||
857 | * while (g_win32_registry_subkey_iter_next (&iter, TRUE, NULL)) |
||
858 | * { |
||
859 | * if (!g_win32_registry_subkey_iter_get_name (&iter, &name, NULL, NULL)) |
||
860 | * continue; |
||
861 | * |
||
862 | * g_print ("subkey '%s'\n", name); |
||
863 | * child = g_win32_registry_key_get_child (key, name, NULL); |
||
864 | * |
||
865 | * if (child) |
||
866 | * iterate_key_recursive (child); |
||
867 | * } |
||
868 | * |
||
869 | * g_win32_registry_subkey_iter_clear (&iter); |
||
870 | * } |
||
871 | * ]| |
||
872 | * |
||
873 | * Returns: %TRUE if next subkey info was retrieved, %FALSE otherwise. |
||
874 | * |
||
875 | * Since: 2.46 |
||
876 | **/ |
||
877 | gboolean |
||
878 | g_win32_registry_subkey_iter_next (GWin32RegistrySubkeyIter *iter, |
||
879 | gboolean skip_errors, |
||
880 | GError **error) |
||
881 | { |
||
882 | LONG status; |
||
883 | DWORD subkey_len; |
||
884 | |||
885 | g_return_val_if_fail (iter != NULL, FALSE); |
||
886 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
887 | |||
888 | if G_UNLIKELY (iter->counter >= iter->subkey_count) |
||
889 | { |
||
890 | g_critical ("g_win32_registry_subkey_iter_get_next_w: must not be called again " |
||
891 | "after FALSE has already been returned."); |
||
892 | return FALSE; |
||
893 | } |
||
894 | |||
895 | while (TRUE) |
||
896 | { |
||
897 | iter->counter += 1; |
||
898 | |||
899 | if (iter->counter >= iter->subkey_count) |
||
900 | return FALSE; |
||
901 | |||
902 | /* Including 0-terminator */ |
||
903 | subkey_len = iter->subkey_name_size; |
||
904 | status = RegEnumKeyExW (iter->key->priv->handle, |
||
905 | iter->counter, |
||
906 | iter->subkey_name, |
||
907 | &subkey_len, |
||
908 | NULL, NULL, NULL, NULL); |
||
909 | |||
910 | if (status == ERROR_SUCCESS) |
||
911 | { |
||
912 | iter->subkey_name_len = subkey_len; |
||
913 | |||
914 | return TRUE; |
||
915 | } |
||
916 | |||
917 | if (!skip_errors) |
||
918 | { |
||
919 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status), |
||
920 | "Failed to enumerate subkey #%d for key '%S'", |
||
921 | iter->counter, g_win32_registry_key_get_path_w (iter->key)); |
||
922 | iter->subkey_count = 0; |
||
923 | |||
924 | return FALSE; |
||
925 | } |
||
926 | } |
||
927 | } |
||
928 | |||
929 | /** |
||
930 | * g_win32_registry_subkey_iter_get_name_w: |
||
931 | * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter |
||
932 | * @subkey_name: (out callee-allocates) (transfer none): Pointer to a location |
||
933 | * to store the name of a subkey (in UTF-16). |
||
934 | * @subkey_name_len: (out) (optional) (transfer none): Pointer to a location |
||
935 | * to store the length of @subkey_name, in gunichar2s, excluding |
||
936 | * NUL-terminator. |
||
937 | * %NULL if length is not needed. |
||
938 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
939 | * |
||
940 | * Same as g_win32_registry_subkey_iter_get_next(), but outputs UTF-16-encoded |
||
941 | * data, without converting it to UTF-8 first. |
||
942 | * |
||
943 | * Returns: %TRUE if the name was retrieved, %FALSE otherwise. |
||
944 | * |
||
945 | * Since: 2.46 |
||
946 | **/ |
||
947 | gboolean |
||
948 | g_win32_registry_subkey_iter_get_name_w (GWin32RegistrySubkeyIter *iter, |
||
949 | gunichar2 **subkey_name, |
||
950 | gsize *subkey_name_len, |
||
951 | GError **error) |
||
952 | { |
||
953 | g_return_val_if_fail (iter != NULL, FALSE); |
||
954 | g_return_val_if_fail (subkey_name != NULL, FALSE); |
||
955 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
956 | |||
957 | if G_UNLIKELY (iter->counter >= iter->subkey_count) |
||
958 | { |
||
959 | g_critical ("g_win32_registry_subkey_iter_get_name_w: must not be called " |
||
960 | "after FALSE has already been returned by " |
||
961 | "g_win32_registry_subkey_iter_next."); |
||
962 | return FALSE; |
||
963 | } |
||
964 | |||
965 | *subkey_name = iter->subkey_name; |
||
966 | |||
967 | if (subkey_name_len) |
||
968 | *subkey_name_len = iter->subkey_name_len; |
||
969 | |||
970 | return TRUE; |
||
971 | } |
||
972 | |||
973 | /** |
||
974 | * g_win32_registry_subkey_iter_get_name: |
||
975 | * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter |
||
976 | * @subkey_name: (out callee-allocates) (transfer none): Pointer to a location |
||
977 | * to store the name of a subkey (in UTF-8). Free with g_free(). |
||
978 | * @subkey_name_len: (out) (optional): Pointer to a location to store the |
||
979 | * length of @subkey_name, in gchars, excluding NUL-terminator. |
||
980 | * %NULL if length is not needed. |
||
981 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
982 | * |
||
983 | * Gets the name of the subkey at the @iter potision. |
||
984 | * |
||
985 | * Returns: %TRUE if the name was retrieved, %FALSE otherwise. |
||
986 | * |
||
987 | * Since: 2.46 |
||
988 | **/ |
||
989 | gboolean |
||
990 | g_win32_registry_subkey_iter_get_name (GWin32RegistrySubkeyIter *iter, |
||
991 | gchar **subkey_name, |
||
992 | gsize *subkey_name_len, |
||
993 | GError **error) |
||
994 | { |
||
995 | glong subkey_name_len_glong; |
||
996 | |||
997 | g_return_val_if_fail (iter != NULL, FALSE); |
||
998 | g_return_val_if_fail (subkey_name != NULL, FALSE); |
||
999 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1000 | |||
1001 | if G_UNLIKELY (iter->counter >= iter->subkey_count) |
||
1002 | { |
||
1003 | g_critical ("g_win32_registry_subkey_iter_get_name_w: must not be called " |
||
1004 | "after FALSE has already been returned by " |
||
1005 | "g_win32_registry_subkey_iter_next."); |
||
1006 | return FALSE; |
||
1007 | } |
||
1008 | |||
1009 | g_clear_pointer (&iter->subkey_name_u8, g_free); |
||
1010 | iter->subkey_name_u8 = g_utf16_to_utf8 (iter->subkey_name, |
||
1011 | iter->subkey_name_len, |
||
1012 | NULL, |
||
1013 | &subkey_name_len_glong, |
||
1014 | error); |
||
1015 | |||
1016 | if (iter->subkey_name_u8 != NULL) |
||
1017 | { |
||
1018 | *subkey_name_len = subkey_name_len_glong; |
||
1019 | return TRUE; |
||
1020 | } |
||
1021 | |||
1022 | return FALSE; |
||
1023 | } |
||
1024 | |||
1025 | /** |
||
1026 | * g_win32_registry_value_iter_init: |
||
1027 | * @iter: (in) (transfer none): a pointer to a #GWin32RegistryValueIter |
||
1028 | * @key: (in) (transfer none): a #GWin32RegistryKey to iterate over |
||
1029 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1030 | * |
||
1031 | * Initialises (without allocating) a #GWin32RegistryValueIter. @iter may be |
||
1032 | * completely uninitialised prior to this call; its old value is |
||
1033 | * ignored. |
||
1034 | * |
||
1035 | * The iterator remains valid for as long as @key exists. |
||
1036 | * Clean up its internal buffers with a call to |
||
1037 | * g_win32_registry_value_iter_clear() when done. |
||
1038 | * |
||
1039 | * Returns: %TRUE if iterator was initialized successfully, %FALSE on error. |
||
1040 | * |
||
1041 | * Since: 2.46 |
||
1042 | **/ |
||
1043 | gboolean |
||
1044 | g_win32_registry_value_iter_init (GWin32RegistryValueIter *iter, |
||
1045 | GWin32RegistryKey *key, |
||
1046 | GError **error) |
||
1047 | { |
||
1048 | LONG status; |
||
1049 | DWORD value_count; |
||
1050 | DWORD max_value_len; |
||
1051 | DWORD max_data_len; |
||
1052 | |||
1053 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1054 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); |
||
1055 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1056 | |||
1057 | status = RegQueryInfoKeyW (key->priv->handle, |
||
1058 | NULL, NULL, NULL, NULL, NULL, NULL, |
||
1059 | &value_count, &max_value_len, |
||
1060 | &max_data_len, NULL, NULL); |
||
1061 | |||
1062 | if (status != ERROR_SUCCESS) |
||
1063 | { |
||
1064 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status), |
||
1065 | "Failed to query info for registry key '%S'", |
||
1066 | g_win32_registry_key_get_path_w (key)); |
||
1067 | return FALSE; |
||
1068 | } |
||
1069 | |||
1070 | iter->key = g_object_ref (key); |
||
1071 | iter->counter = -1; |
||
1072 | iter->value_count = value_count; |
||
1073 | iter->value_name_size = sizeof (gunichar2) * (max_value_len + 1); |
||
1074 | iter->value_name = g_malloc (iter->value_name_size); |
||
1075 | /* FIXME: max_value_data_len is said to have no size limit in newer W32 |
||
1076 | * versions (and its size limit in older ones is 1MB!). Consider limiting it |
||
1077 | * with a hard-coded value, or by allowing the user to choose a limit. |
||
1078 | */ |
||
1079 | /* Two extra gunichar2s is for cases when a string was stored in the |
||
1080 | * Registry without a 0-terminator (for multiline strings - 00-terminator), |
||
1081 | * and we need to terminate it ourselves. |
||
1082 | */ |
||
1083 | iter->value_data_size = max_data_len + sizeof (gunichar2) * 2; |
||
1084 | iter->value_data = g_malloc (iter->value_data_size); |
||
1085 | iter->value_name_u8 = NULL; |
||
1086 | iter->value_data_u8 = NULL; |
||
1087 | iter->value_data_expanded = NULL; |
||
1088 | iter->value_data_expanded_charsize = 0; |
||
1089 | iter->value_data_expanded_u8 = NULL; |
||
1090 | iter->value_data_expanded_u8_size = 0; |
||
1091 | return TRUE; |
||
1092 | } |
||
1093 | |||
1094 | /** |
||
1095 | * g_win32_registry_value_iter_clear: |
||
1096 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1097 | * |
||
1098 | * Frees internal buffers of a #GWin32RegistryValueIter. |
||
1099 | * |
||
1100 | * Since: 2.46 |
||
1101 | **/ |
||
1102 | void |
||
1103 | g_win32_registry_value_iter_clear (GWin32RegistryValueIter *iter) |
||
1104 | { |
||
1105 | g_return_if_fail (iter != NULL); |
||
1106 | |||
1107 | g_free (iter->value_name); |
||
1108 | g_free (iter->value_data); |
||
1109 | g_free (iter->value_name_u8); |
||
1110 | g_free (iter->value_data_u8); |
||
1111 | g_free (iter->value_data_expanded); |
||
1112 | g_free (iter->value_data_expanded_u8); |
||
1113 | g_clear_object (&iter->key); |
||
1114 | } |
||
1115 | |||
1116 | /** |
||
1117 | * g_win32_registry_value_iter_n_values: |
||
1118 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1119 | * |
||
1120 | * Queries the number of values items in the key that we are |
||
1121 | * iterating over. This is the total number of values -- not the number |
||
1122 | * of items remaining. |
||
1123 | * |
||
1124 | * This information is accurate at the point of iterator initialization, |
||
1125 | * and may go out of sync with reality even while values are enumerated. |
||
1126 | * |
||
1127 | * Returns: the number of values in the key |
||
1128 | * |
||
1129 | * Since: 2.46 |
||
1130 | **/ |
||
1131 | gsize |
||
1132 | g_win32_registry_value_iter_n_values (GWin32RegistryValueIter *iter) |
||
1133 | { |
||
1134 | g_return_val_if_fail (iter != NULL, 0); |
||
1135 | |||
1136 | return iter->value_count; |
||
1137 | } |
||
1138 | |||
1139 | static GWin32RegistryValueType |
||
1140 | _g_win32_registry_type_w_to_g (DWORD value_type) |
||
1141 | { |
||
1142 | switch (value_type) |
||
1143 | { |
||
1144 | case REG_BINARY: |
||
1145 | return G_WIN32_REGISTRY_VALUE_BINARY; |
||
1146 | case REG_DWORD: |
||
1147 | return G_WIN32_REGISTRY_VALUE_UINT32; |
||
1148 | #if G_BYTE_ORDER == G_BIG_ENDIAN |
||
1149 | case REG_DWORD_LITTLE_ENDIAN: |
||
1150 | return G_WIN32_REGISTRY_VALUE_UINT32LE; |
||
1151 | #else |
||
1152 | case REG_DWORD_BIG_ENDIAN: |
||
1153 | return G_WIN32_REGISTRY_VALUE_UINT32BE; |
||
1154 | #endif |
||
1155 | case REG_EXPAND_SZ: |
||
1156 | return G_WIN32_REGISTRY_VALUE_EXPAND_STR; |
||
1157 | case REG_LINK: |
||
1158 | return G_WIN32_REGISTRY_VALUE_LINK; |
||
1159 | case REG_MULTI_SZ: |
||
1160 | return G_WIN32_REGISTRY_VALUE_MULTI_STR; |
||
1161 | case REG_NONE: |
||
1162 | return G_WIN32_REGISTRY_VALUE_NONE; |
||
1163 | case REG_QWORD: |
||
1164 | return G_WIN32_REGISTRY_VALUE_UINT64; |
||
1165 | #if G_BYTE_ORDER == G_BIG_ENDIAN |
||
1166 | case REG_QWORD_LITTLE_ENDIAN: |
||
1167 | return G_WIN32_REGISTRY_VALUE_UINT64LE; |
||
1168 | #endif |
||
1169 | case REG_SZ: |
||
1170 | return G_WIN32_REGISTRY_VALUE_STR; |
||
1171 | default: |
||
1172 | return G_WIN32_REGISTRY_VALUE_NONE; |
||
1173 | } |
||
1174 | } |
||
1175 | |||
1176 | static gsize |
||
1177 | ensure_nul_termination (GWin32RegistryValueType value_type, |
||
1178 | guint8 *value_data, |
||
1179 | gsize value_data_size) |
||
1180 | { |
||
1181 | gsize new_size = value_data_size; |
||
1182 | |||
1183 | if (value_type == G_WIN32_REGISTRY_VALUE_EXPAND_STR || |
||
1184 | value_type == G_WIN32_REGISTRY_VALUE_LINK || |
||
1185 | value_type == G_WIN32_REGISTRY_VALUE_STR) |
||
1186 | { |
||
1187 | if ((value_data_size < 2) || |
||
1188 | (value_data[value_data_size - 1] != 0) || |
||
1189 | (value_data[value_data_size - 2] != 0)) |
||
1190 | { |
||
1191 | value_data[value_data_size] = 0; |
||
1192 | value_data[value_data_size + 1] = 0; |
||
1193 | new_size += 2; |
||
1194 | } |
||
1195 | } |
||
1196 | else if (value_type == G_WIN32_REGISTRY_VALUE_MULTI_STR) |
||
1197 | { |
||
1198 | if ((value_data_size < 4) || |
||
1199 | (value_data[value_data_size - 1] != 0) || |
||
1200 | (value_data[value_data_size - 2] != 0) || |
||
1201 | (value_data[value_data_size - 3] != 0) || |
||
1202 | (value_data[value_data_size - 4] != 0)) |
||
1203 | { |
||
1204 | value_data[value_data_size] = 0; |
||
1205 | value_data[value_data_size + 1] = 0; |
||
1206 | value_data[value_data_size + 2] = 0; |
||
1207 | value_data[value_data_size + 3] = 0; |
||
1208 | new_size += 4; |
||
1209 | } |
||
1210 | } |
||
1211 | |||
1212 | return new_size; |
||
1213 | } |
||
1214 | |||
1215 | /** |
||
1216 | * g_win32_registry_value_iter_next: |
||
1217 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1218 | * @skip_errors: (in): %TRUE if iterator should silently ignore errors (such as |
||
1219 | * the actual number of values being less than expected) and |
||
1220 | * proceed forward |
||
1221 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1222 | * |
||
1223 | * Advances iterator to the next value in the key. If no more values remain then |
||
1224 | * FALSE is returned. |
||
1225 | * Enumeration errors can be ignored if @skip_errors is %TRUE |
||
1226 | * |
||
1227 | * Here is an example for iterating with g_win32_registry_value_iter_next(): |
||
1228 | * |[<!-- language="C" --> |
||
1229 | * // iterate values of a key |
||
1230 | * void |
||
1231 | * iterate_values_recursive (GWin32RegistryKey *key) |
||
1232 | * { |
||
1233 | * GWin32RegistryValueIter iter; |
||
1234 | * gchar *name; |
||
1235 | * GWin32RegistryValueType val_type; |
||
1236 | * gchar *val_data; |
||
1237 | * |
||
1238 | * if (!g_win32_registry_value_iter_init (&iter, key, NULL)) |
||
1239 | * return; |
||
1240 | * |
||
1241 | * while (g_win32_registry_value_iter_next (&iter, TRUE, NULL)) |
||
1242 | * { |
||
1243 | * if ((!g_win32_registry_value_iter_get_value_type (&iter, &value)) || |
||
1244 | * ((val_type != G_WIN32_REGISTRY_VALUE_STR) && |
||
1245 | * (val_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR))) |
||
1246 | * continue; |
||
1247 | * |
||
1248 | * if (g_win32_registry_value_iter_get_value (&iter, TRUE, &name, NULL, |
||
1249 | * &val_data, NULL, NULL)) |
||
1250 | * g_print ("value '%s' = '%s'\n", name, val_data); |
||
1251 | * } |
||
1252 | * |
||
1253 | * g_win32_registry_value_iter_clear (&iter); |
||
1254 | * } |
||
1255 | * ]| |
||
1256 | * |
||
1257 | * Returns: %TRUE if next value info was retrieved, %FALSE otherwise. |
||
1258 | * |
||
1259 | * Since: 2.46 |
||
1260 | **/ |
||
1261 | gboolean |
||
1262 | g_win32_registry_value_iter_next (GWin32RegistryValueIter *iter, |
||
1263 | gboolean skip_errors, |
||
1264 | GError **error) |
||
1265 | { |
||
1266 | LONG status; |
||
1267 | DWORD value_name_len_w; |
||
1268 | DWORD value_data_size_w; |
||
1269 | DWORD value_type_w; |
||
1270 | GWin32RegistryValueType value_type_g; |
||
1271 | |||
1272 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1273 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1274 | |||
1275 | if G_UNLIKELY (iter->counter >= iter->value_count) |
||
1276 | { |
||
1277 | g_critical ("g_win32_registry_value_iter_next: must not be called " |
||
1278 | "again after FALSE has already been returned."); |
||
1279 | return FALSE; |
||
1280 | } |
||
1281 | |||
1282 | while (TRUE) |
||
1283 | { |
||
1284 | iter->counter += 1; |
||
1285 | |||
1286 | if (iter->counter >= iter->value_count) |
||
1287 | return FALSE; |
||
1288 | |||
1289 | g_clear_pointer (&iter->value_name_u8, g_free); |
||
1290 | g_clear_pointer (&iter->value_data_u8, g_free); |
||
1291 | g_clear_pointer (&iter->value_data_expanded_u8, g_free); |
||
1292 | /* Including 0-terminator */ |
||
1293 | value_name_len_w = iter->value_name_size / sizeof (gunichar2); |
||
1294 | value_data_size_w = iter->value_data_size; |
||
1295 | status = RegEnumValueW (iter->key->priv->handle, |
||
1296 | iter->counter, |
||
1297 | iter->value_name, |
||
1298 | &value_name_len_w, |
||
1299 | NULL, |
||
1300 | &value_type_w, |
||
1301 | (LPBYTE) iter->value_data, |
||
1302 | &value_data_size_w); |
||
1303 | |||
1304 | if (status != ERROR_SUCCESS && !skip_errors) |
||
1305 | { |
||
1306 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status), |
||
1307 | "Failed to enumerate value #%d for key '%S'", |
||
1308 | iter->counter, g_win32_registry_key_get_path_w (iter->key)); |
||
1309 | iter->value_count = 0; |
||
1310 | |||
1311 | return FALSE; |
||
1312 | } |
||
1313 | else if (status != ERROR_SUCCESS && skip_errors) |
||
1314 | continue; |
||
1315 | |||
1316 | value_type_g = _g_win32_registry_type_w_to_g (value_type_w); |
||
1317 | value_data_size_w = ensure_nul_termination (value_type_g, |
||
1318 | iter->value_data, |
||
1319 | value_data_size_w); |
||
1320 | iter->value_type = value_type_g; |
||
1321 | iter->value_expanded_type = value_type_g; |
||
1322 | iter->value_actual_data_size = value_data_size_w; |
||
1323 | iter->value_name_len = value_name_len_w; |
||
1324 | |||
1325 | return TRUE; |
||
1326 | } |
||
1327 | } |
||
1328 | |||
1329 | /** |
||
1330 | * g_win32_registry_value_iter_get_value_type: |
||
1331 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1332 | * @value_type: (out): Pointer to a location to store the type of |
||
1333 | * the value. |
||
1334 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1335 | * |
||
1336 | * Stores the type of the value currently being iterated over in @value_type. |
||
1337 | * |
||
1338 | * Returns: %TRUE if value type was retrieved, %FALSE otherwise. |
||
1339 | * |
||
1340 | * Since: 2.46 |
||
1341 | **/ |
||
1342 | gboolean |
||
1343 | g_win32_registry_value_iter_get_value_type (GWin32RegistryValueIter *iter, |
||
1344 | GWin32RegistryValueType *value_type, |
||
1345 | GError **error) |
||
1346 | { |
||
1347 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1348 | g_return_val_if_fail (value_type != NULL, FALSE); |
||
1349 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1350 | |||
1351 | if G_UNLIKELY (iter->counter >= iter->value_count) |
||
1352 | { |
||
1353 | g_critical ("g_win32_registry_value_iter_get_type: must not be called " |
||
1354 | "again after NULL has already been returned."); |
||
1355 | return FALSE; |
||
1356 | } |
||
1357 | |||
1358 | *value_type = iter->value_type; |
||
1359 | |||
1360 | return TRUE; |
||
1361 | } |
||
1362 | |||
1363 | /** |
||
1364 | * g_win32_registry_value_iter_get_name_w: |
||
1365 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1366 | * @value_name: (out callee-allocates) (transfer none): Pointer to a location |
||
1367 | * to store the name of a value (in UTF-16). |
||
1368 | * @value_name_len: (out) (optional): Pointer to a location to store the length |
||
1369 | * of @value_name, in gunichar2s, excluding NUL-terminator. |
||
1370 | * %NULL if length is not needed. |
||
1371 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1372 | * |
||
1373 | * Stores the name of the value currently being iterated over in @value_name, |
||
1374 | * and its length - in @value_name (if not %NULL). |
||
1375 | * |
||
1376 | * Returns: %TRUE if value name was retrieved, %FALSE otherwise. |
||
1377 | * |
||
1378 | * Since: 2.46 |
||
1379 | **/ |
||
1380 | gboolean |
||
1381 | g_win32_registry_value_iter_get_name_w (GWin32RegistryValueIter *iter, |
||
1382 | gunichar2 **value_name, |
||
1383 | gsize *value_name_len, |
||
1384 | GError **error) |
||
1385 | { |
||
1386 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1387 | g_return_val_if_fail (value_name != NULL, FALSE); |
||
1388 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1389 | |||
1390 | if G_UNLIKELY (iter->counter >= iter->value_count) |
||
1391 | { |
||
1392 | g_critical ("g_win32_registry_value_iter_get_name_w: must not be called " |
||
1393 | "again after NULL has already been returned."); |
||
1394 | return FALSE; |
||
1395 | } |
||
1396 | |||
1397 | *value_name = iter->value_name; |
||
1398 | |||
1399 | if (value_name_len) |
||
1400 | *value_name_len = iter->value_name_len; |
||
1401 | |||
1402 | return TRUE; |
||
1403 | } |
||
1404 | |||
1405 | /** |
||
1406 | * g_win32_registry_value_iter_get_name: |
||
1407 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1408 | * @value_name: (out callee-allocates) (transfer none): Pointer to a location |
||
1409 | * to store the name of a value (in UTF-8). |
||
1410 | * @value_name_len: (out) (optional): Pointer to a location to store the length |
||
1411 | * of @value_name, in gchars, excluding NUL-terminator. |
||
1412 | * %NULL if length is not needed. |
||
1413 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1414 | * |
||
1415 | * Stores the name of the value currently being iterated over in @value_name, |
||
1416 | * and its length - in @value_name_len (if not %NULL). |
||
1417 | * |
||
1418 | * Returns: %TRUE if value name was retrieved, %FALSE otherwise. |
||
1419 | * |
||
1420 | * Since: 2.46 |
||
1421 | **/ |
||
1422 | gboolean |
||
1423 | g_win32_registry_value_iter_get_name (GWin32RegistryValueIter *iter, |
||
1424 | gchar **value_name, |
||
1425 | gsize *value_name_len, |
||
1426 | GError **error) |
||
1427 | { |
||
1428 | glong value_name_len_glong; |
||
1429 | |||
1430 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1431 | g_return_val_if_fail (value_name != NULL, FALSE); |
||
1432 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1433 | |||
1434 | if G_UNLIKELY (iter->counter >= iter->value_count) |
||
1435 | { |
||
1436 | g_critical ("g_win32_registry_value_iter_get_name: must not be called " |
||
1437 | "again after NULL has already been returned."); |
||
1438 | return FALSE; |
||
1439 | } |
||
1440 | |||
1441 | if (iter->value_name_u8 == NULL) |
||
1442 | { |
||
1443 | iter->value_name_u8 = g_utf16_to_utf8 (iter->value_name, iter->value_name_len, NULL, |
||
1444 | &value_name_len_glong, error); |
||
1445 | |||
1446 | if (iter->value_name_u8 == NULL) |
||
1447 | return FALSE; |
||
1448 | } |
||
1449 | |||
1450 | *value_name = iter->value_name_u8; |
||
1451 | |||
1452 | if (value_name_len) |
||
1453 | *value_name_len = iter->value_name_u8_len; |
||
1454 | |||
1455 | return TRUE; |
||
1456 | } |
||
1457 | |||
1458 | static gboolean |
||
1459 | expand_value (gunichar2 *value, |
||
1460 | const gunichar2 *value_name, |
||
1461 | gpointer *expanded_value, |
||
1462 | gsize *expanded_charsize, |
||
1463 | GError **error) |
||
1464 | { |
||
1465 | DWORD value_data_expanded_charsize_w; |
||
1466 | |||
1467 | value_data_expanded_charsize_w = |
||
1468 | ExpandEnvironmentStringsW (value, |
||
1469 | (gunichar2 *) *expanded_value, |
||
1470 | *expanded_charsize); |
||
1471 | |||
1472 | if (value_data_expanded_charsize_w > *expanded_charsize) |
||
1473 | { |
||
1474 | *expanded_value = g_realloc (*expanded_value, |
||
1475 | value_data_expanded_charsize_w * sizeof (gunichar2)); |
||
1476 | *expanded_charsize = value_data_expanded_charsize_w; |
||
1477 | value_data_expanded_charsize_w = |
||
1478 | ExpandEnvironmentStringsW (value, |
||
1479 | (gunichar2 *) *expanded_value, |
||
1480 | *expanded_charsize); |
||
1481 | } |
||
1482 | |||
1483 | if (value_data_expanded_charsize_w == 0) |
||
1484 | { |
||
1485 | g_set_error (error, G_IO_ERROR, |
||
1486 | g_io_error_from_win32_error (GetLastError ()), |
||
1487 | "Failed to expand data '%S' of value %S", |
||
1488 | value, value_name); |
||
1489 | return FALSE; |
||
1490 | } |
||
1491 | |||
1492 | return TRUE; |
||
1493 | } |
||
1494 | |||
1495 | /** |
||
1496 | * g_win32_registry_value_iter_get_data_w: |
||
1497 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1498 | * @auto_expand: (in): %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR to |
||
1499 | * G_WIN32_REGISTRY_VALUE_STR |
||
1500 | * @value_data: (out callee-allocates) (optional) (transfer none): Pointer to a |
||
1501 | * location to store the data of the value (in UTF-16, if it's a string) |
||
1502 | * @value_data_size: (out) (optional): Pointer to a location to store the size |
||
1503 | * of @value_data, in bytes (including any NUL-terminators, if it's a string). |
||
1504 | * %NULL if length is not needed. |
||
1505 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1506 | * |
||
1507 | * Stores the data of the value currently being iterated over in @value_data, |
||
1508 | * and its length - in @value_data_len (if not %NULL). |
||
1509 | * |
||
1510 | * Returns: %TRUE if value data was retrieved, %FALSE otherwise. |
||
1511 | * |
||
1512 | * Since: 2.46 |
||
1513 | **/ |
||
1514 | gboolean |
||
1515 | g_win32_registry_value_iter_get_data_w (GWin32RegistryValueIter *iter, |
||
1516 | gboolean auto_expand, |
||
1517 | gpointer *value_data, |
||
1518 | gsize *value_data_size, |
||
1519 | GError **error) |
||
1520 | { |
||
1521 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1522 | g_return_val_if_fail (value_data != NULL, FALSE); |
||
1523 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1524 | |||
1525 | if G_UNLIKELY (iter->counter >= iter->value_count) |
||
1526 | { |
||
1527 | g_critical ("g_win32_registry_value_iter_get_data_w: must not be called " |
||
1528 | "again after FALSE has already been returned."); |
||
1529 | return FALSE; |
||
1530 | } |
||
1531 | |||
1532 | if (!auto_expand || (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR)) |
||
1533 | { |
||
1534 | *value_data = iter->value_data; |
||
1535 | |||
1536 | if (value_data_size) |
||
1537 | *value_data_size = iter->value_actual_data_size; |
||
1538 | |||
1539 | return TRUE; |
||
1540 | } |
||
1541 | |||
1542 | if (iter->value_type == iter->value_expanded_type) |
||
1543 | { |
||
1544 | if (!expand_value ((gunichar2 *) iter->value_data, |
||
1545 | iter->value_name, |
||
1546 | (gpointer *) &iter->value_data_expanded, |
||
1547 | &iter->value_data_expanded_charsize, |
||
1548 | error)) |
||
1549 | return FALSE; |
||
1550 | |||
1551 | iter->value_expanded_type = G_WIN32_REGISTRY_VALUE_STR; |
||
1552 | } |
||
1553 | |||
1554 | *value_data = iter->value_data_expanded; |
||
1555 | |||
1556 | if (value_data_size) |
||
1557 | *value_data_size = iter->value_data_expanded_charsize * sizeof (gunichar2); |
||
1558 | |||
1559 | return TRUE; |
||
1560 | } |
||
1561 | |||
1562 | /** |
||
1563 | * g_win32_registry_value_iter_get_data: |
||
1564 | * @iter: (in) (transfer none): a #GWin32RegistryValueIter |
||
1565 | * @auto_expand: (in): %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR to |
||
1566 | * G_WIN32_REGISTRY_VALUE_STR |
||
1567 | * @value_data: (out callee-allocates) (optional) (transfer none): Pointer to a |
||
1568 | * location to store the data of the value (in UTF-8, if it's a string) |
||
1569 | * @value_data_size: (out) (optional): Pointer to a location to store the length |
||
1570 | * of @value_data, in bytes (including any NUL-terminators, if it's a string). |
||
1571 | * %NULL if length is not needed |
||
1572 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1573 | * |
||
1574 | * Stores the data of the value currently being iterated over in @value_data, |
||
1575 | * and its length - in @value_data_len (if not %NULL). |
||
1576 | * |
||
1577 | * Returns: %TRUE if value data was retrieved, %FALSE otherwise. |
||
1578 | * |
||
1579 | * Since: 2.46 |
||
1580 | **/ |
||
1581 | gboolean |
||
1582 | g_win32_registry_value_iter_get_data (GWin32RegistryValueIter *iter, |
||
1583 | gboolean auto_expand, |
||
1584 | gpointer *value_data, |
||
1585 | gsize *value_data_size, |
||
1586 | GError **error) |
||
1587 | { |
||
1588 | gsize value_data_len_gsize; |
||
1589 | gpointer tmp; |
||
1590 | gsize tmp_size; |
||
1591 | |||
1592 | g_return_val_if_fail (iter != NULL, FALSE); |
||
1593 | g_return_val_if_fail (value_data != NULL, FALSE); |
||
1594 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1595 | |||
1596 | if G_UNLIKELY (iter->counter >= iter->value_count) |
||
1597 | { |
||
1598 | g_critical ("g_win32_registry_value_iter_get_data: must not be called " |
||
1599 | "again after FALSE has already been returned."); |
||
1600 | return FALSE; |
||
1601 | } |
||
1602 | |||
1603 | if (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR && |
||
1604 | iter->value_type != G_WIN32_REGISTRY_VALUE_LINK && |
||
1605 | iter->value_type != G_WIN32_REGISTRY_VALUE_STR && |
||
1606 | iter->value_type != G_WIN32_REGISTRY_VALUE_MULTI_STR) |
||
1607 | { |
||
1608 | *value_data = iter->value_data; |
||
1609 | |||
1610 | if (value_data_size != NULL) |
||
1611 | *value_data_size = iter->value_actual_data_size; |
||
1612 | |||
1613 | return TRUE; |
||
1614 | } |
||
1615 | |||
1616 | if (!auto_expand || (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR)) |
||
1617 | { |
||
1618 | if (iter->value_data_u8 == NULL) |
||
1619 | { |
||
1620 | iter->value_data_u8 = g_convert ((const gchar *) iter->value_data, |
||
1621 | iter->value_actual_data_size - sizeof (gunichar2) /* excl. 0 */, |
||
1622 | "UTF8", "UTF16", NULL, |
||
1623 | &value_data_len_gsize, |
||
1624 | error); |
||
1625 | |||
1626 | if (iter->value_data_u8 == NULL) |
||
1627 | return FALSE; |
||
1628 | |||
1629 | iter->value_data_u8_size = value_data_len_gsize + 1; /* incl. 0 */ |
||
1630 | } |
||
1631 | |||
1632 | *value_data = iter->value_data_u8; |
||
1633 | |||
1634 | if (value_data_size != NULL) |
||
1635 | *value_data_size = iter->value_data_u8_size; |
||
1636 | |||
1637 | return TRUE; |
||
1638 | } |
||
1639 | |||
1640 | if (iter->value_data_expanded_u8 == NULL) |
||
1641 | { |
||
1642 | if (!g_win32_registry_value_iter_get_data_w (iter, |
||
1643 | TRUE, |
||
1644 | &tmp, |
||
1645 | &tmp_size, |
||
1646 | error)) |
||
1647 | return FALSE; |
||
1648 | |||
1649 | iter->value_data_expanded_u8 = g_convert ((const gchar *) iter->value_data_expanded, |
||
1650 | iter->value_data_expanded_charsize * sizeof (gunichar2) - sizeof (gunichar2) /* excl. 0 */, |
||
1651 | "UTF8", "UTF16", NULL, |
||
1652 | &value_data_len_gsize, |
||
1653 | error); |
||
1654 | |||
1655 | if (iter->value_data_expanded_u8 == NULL) |
||
1656 | return FALSE; |
||
1657 | |||
1658 | iter->value_data_u8_size = value_data_len_gsize + 1; /* incl. 0 */ |
||
1659 | } |
||
1660 | |||
1661 | *value_data = iter->value_data_expanded_u8; |
||
1662 | |||
1663 | if (value_data_size != NULL) |
||
1664 | *value_data_size = iter->value_data_expanded_u8_size; |
||
1665 | |||
1666 | return TRUE; |
||
1667 | } |
||
1668 | |||
1669 | static void |
||
1670 | _g_win32_registry_key_reread_kernel (GWin32RegistryKey *key, |
||
1671 | GWin32RegistryKeyPrivate *buf) |
||
1672 | { |
||
1673 | NTSTATUS status; |
||
1674 | KEY_BASIC_INFORMATION *basic_info; |
||
1675 | ULONG basic_info_size; |
||
1676 | ULONG datasize; |
||
1677 | |||
1678 | basic_info_size = 256 * sizeof (gunichar2) + sizeof (KEY_BASIC_INFORMATION); |
||
1679 | basic_info = g_malloc (basic_info_size + sizeof (gunichar2)); |
||
1680 | status = nt_query_key (key->priv->handle, |
||
1681 | KeyBasicInformation, |
||
1682 | basic_info, |
||
1683 | basic_info_size, |
||
1684 | &datasize); |
||
1685 | |||
1686 | if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) |
||
1687 | { |
||
1688 | g_free (basic_info); |
||
1689 | basic_info_size = datasize; |
||
1690 | /* +1 for 0-terminator */ |
||
1691 | basic_info = g_malloc (basic_info_size + sizeof (gunichar2)); |
||
1692 | status = nt_query_key (key->priv->handle, |
||
1693 | KeyBasicInformation, |
||
1694 | basic_info, |
||
1695 | basic_info_size, |
||
1696 | &datasize); |
||
1697 | } |
||
1698 | |||
1699 | if (status != STATUS_SUCCESS) |
||
1700 | { |
||
1701 | g_free (basic_info); |
||
1702 | return; |
||
1703 | } |
||
1704 | |||
1705 | /* Ensure 0-termination */ |
||
1706 | ((char *) basic_info)[datasize] = 0; |
||
1707 | ((char *) basic_info)[datasize + 1] = 0; |
||
1708 | |||
1709 | buf->absolute_path_w = g_wcsdup (&basic_info->Name[0], |
||
1710 | basic_info->NameLength + sizeof (gunichar2)); |
||
1711 | g_free (basic_info); |
||
1712 | } |
||
1713 | |||
1714 | static void |
||
1715 | _g_win32_registry_key_reread_user (GWin32RegistryKey *key, |
||
1716 | GWin32RegistryKeyPrivate *buf) |
||
1717 | { |
||
1718 | /* Use RegQueryInfoKey(). It's just like NtQueryKey(), but can't query |
||
1719 | * key name. |
||
1720 | * Since right now we only need the name, this function is a noop. |
||
1721 | */ |
||
1722 | } |
||
1723 | |||
1724 | static void |
||
1725 | _g_win32_registry_key_reread (GWin32RegistryKey *key, |
||
1726 | GWin32RegistryKeyPrivate *buf) |
||
1727 | { |
||
1728 | if (g_once_init_enter (&nt_query_key)) |
||
1729 | { |
||
1730 | NtQueryKeyFunc func; |
||
1731 | HMODULE ntdll = GetModuleHandleW (L"ntdll.dll"); |
||
1732 | |||
1733 | if (ntdll != NULL) |
||
1734 | func = (NtQueryKeyFunc) GetProcAddress (ntdll, "NtQueryKey"); |
||
1735 | else |
||
1736 | func = NULL; |
||
1737 | |||
1738 | g_once_init_leave (&nt_query_key, func); |
||
1739 | } |
||
1740 | |||
1741 | /* Assume that predefined keys never get renamed. Also, their handles probably |
||
1742 | * won't be accepted by NtQueryKey(), i suspect. |
||
1743 | */ |
||
1744 | if (nt_query_key != NULL && !key->priv->predefined) |
||
1745 | _g_win32_registry_key_reread_kernel (key, buf); |
||
1746 | else |
||
1747 | _g_win32_registry_key_reread_user (key, buf); |
||
1748 | } |
||
1749 | |||
1750 | static gboolean |
||
1751 | _g_win32_registry_key_update_path (GWin32RegistryKey *key) |
||
1752 | { |
||
1753 | GWin32RegistryKeyPrivate tmp; |
||
1754 | gboolean changed; |
||
1755 | gint change_indicator; |
||
1756 | |||
1757 | change_indicator = g_atomic_int_get (&key->priv->change_indicator); |
||
1758 | |||
1759 | if (change_indicator == G_WIN32_KEY_UNCHANGED) |
||
1760 | return FALSE; |
||
1761 | |||
1762 | tmp.absolute_path_w = NULL; |
||
1763 | _g_win32_registry_key_reread (key, &tmp); |
||
1764 | changed = FALSE; |
||
1765 | |||
1766 | if (wcscmp (key->priv->absolute_path_w, tmp.absolute_path_w) == 0) |
||
1767 | g_free (tmp.absolute_path_w); |
||
1768 | else |
||
1769 | { |
||
1770 | g_free (key->priv->absolute_path_w); |
||
1771 | key->priv->absolute_path_w = tmp.absolute_path_w; |
||
1772 | changed = TRUE; |
||
1773 | } |
||
1774 | |||
1775 | return changed; |
||
1776 | } |
||
1777 | |||
1778 | /** |
||
1779 | * g_win32_registry_key_get_path: |
||
1780 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
1781 | * |
||
1782 | * Get full path to the key |
||
1783 | * |
||
1784 | * Returns: (transfer none): a full path to the key (in UTF-8), |
||
1785 | * or %NULL if it can't be converted to UTF-8. |
||
1786 | * |
||
1787 | * Since: 2.46 |
||
1788 | **/ |
||
1789 | const gchar * |
||
1790 | g_win32_registry_key_get_path (GWin32RegistryKey *key) |
||
1791 | { |
||
1792 | gint change_indicator; |
||
1793 | |||
1794 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL); |
||
1795 | |||
1796 | change_indicator = g_atomic_int_get (&key->priv->change_indicator); |
||
1797 | |||
1798 | if (change_indicator == G_WIN32_KEY_CHANGED && |
||
1799 | !(key->priv->update_flags & G_WIN32_REGISTRY_UPDATED_PATH)) |
||
1800 | { |
||
1801 | _g_win32_registry_key_update_path (key); |
||
1802 | key->priv->update_flags |= G_WIN32_REGISTRY_UPDATED_PATH; |
||
1803 | } |
||
1804 | |||
1805 | if (key->priv->absolute_path == NULL) |
||
1806 | { |
||
1807 | g_free (key->priv->absolute_path); |
||
1808 | key->priv->absolute_path = |
||
1809 | g_utf16_to_utf8 (key->priv->absolute_path_w, -1, |
||
1810 | NULL, NULL, NULL); |
||
1811 | } |
||
1812 | |||
1813 | return key->priv->absolute_path; |
||
1814 | } |
||
1815 | |||
1816 | /** |
||
1817 | * g_win32_registry_key_get_path_w: |
||
1818 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
1819 | * |
||
1820 | * Get full path to the key |
||
1821 | * |
||
1822 | * Returns: (transfer none): a full path to the key (in UTF-16) |
||
1823 | * |
||
1824 | * Since: 2.46 |
||
1825 | **/ |
||
1826 | const gunichar2 * |
||
1827 | g_win32_registry_key_get_path_w (GWin32RegistryKey *key) |
||
1828 | { |
||
1829 | gint change_indicator; |
||
1830 | |||
1831 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL); |
||
1832 | |||
1833 | change_indicator = g_atomic_int_get (&key->priv->change_indicator); |
||
1834 | |||
1835 | if (change_indicator == G_WIN32_KEY_CHANGED) |
||
1836 | _g_win32_registry_key_update_path (key); |
||
1837 | |||
1838 | return key->priv->absolute_path_w; |
||
1839 | } |
||
1840 | |||
1841 | /** |
||
1842 | * g_win32_registry_key_get_value: |
||
1843 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
1844 | * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR |
||
1845 | * to G_WIN32_REGISTRY_VALUE_STR. |
||
1846 | * @value_name: (in) (transfer none): name of the value to get (in UTF-8). |
||
1847 | * Empty string means the '(Default)' value. |
||
1848 | * @value_type: (out) (optional): type of the value retrieved. |
||
1849 | * @value_data: (out callee-allocates) (optional): contents of the value. |
||
1850 | * @value_data_size: (out) (optional): size of the buffer pointed |
||
1851 | * by @value_data. |
||
1852 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1853 | * |
||
1854 | * Get data from a value of a key. String data is guaranteed to be |
||
1855 | * appropriately terminated and will be in UTF-8. |
||
1856 | * |
||
1857 | * Returns: %TRUE on success, %FALSE on failure. |
||
1858 | * |
||
1859 | * Since: 2.46 |
||
1860 | **/ |
||
1861 | gboolean |
||
1862 | g_win32_registry_key_get_value (GWin32RegistryKey *key, |
||
1863 | gboolean auto_expand, |
||
1864 | const gchar *value_name, |
||
1865 | GWin32RegistryValueType *value_type, |
||
1866 | gpointer *value_data, |
||
1867 | gsize *value_data_size, |
||
1868 | GError **error) |
||
1869 | { |
||
1870 | GWin32RegistryValueType value_type_g; |
||
1871 | gpointer value_data_w; |
||
1872 | gsize value_data_w_size; |
||
1873 | gunichar2 *value_name_w; |
||
1874 | gchar *value_data_u8; |
||
1875 | gsize value_data_u8_len; |
||
1876 | gboolean result; |
||
1877 | |||
1878 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); |
||
1879 | g_return_val_if_fail (value_name != NULL, FALSE); |
||
1880 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1881 | |||
1882 | /* No sense calling this function with all of these set to NULL */ |
||
1883 | g_return_val_if_fail (value_type != NULL || |
||
1884 | value_data != NULL || |
||
1885 | value_data_size != NULL, FALSE); |
||
1886 | |||
1887 | value_name_w = g_utf8_to_utf16 (value_name, -1, NULL, NULL, error); |
||
1888 | |||
1889 | if (value_name_w == NULL) |
||
1890 | return FALSE; |
||
1891 | |||
1892 | result = g_win32_registry_key_get_value_w (key, |
||
1893 | auto_expand, |
||
1894 | value_name_w, |
||
1895 | &value_type_g, |
||
1896 | &value_data_w, |
||
1897 | &value_data_w_size, |
||
1898 | error); |
||
1899 | |||
1900 | g_free (value_name_w); |
||
1901 | |||
1902 | if (!result) |
||
1903 | return FALSE; |
||
1904 | |||
1905 | if (value_type_g == G_WIN32_REGISTRY_VALUE_EXPAND_STR || |
||
1906 | value_type_g == G_WIN32_REGISTRY_VALUE_LINK || |
||
1907 | value_type_g == G_WIN32_REGISTRY_VALUE_STR || |
||
1908 | value_type_g == G_WIN32_REGISTRY_VALUE_MULTI_STR) |
||
1909 | { |
||
1910 | value_data_u8 = g_convert ((const gchar *) value_data_w, |
||
1911 | value_data_w_size - sizeof (gunichar2) /* excl. 0 */, |
||
1912 | "UTF8", |
||
1913 | "UTF16", |
||
1914 | NULL, |
||
1915 | &value_data_u8_len, |
||
1916 | error); |
||
1917 | g_free (value_data_w); |
||
1918 | |||
1919 | if (value_data_u8 == NULL) |
||
1920 | return FALSE; |
||
1921 | |||
1922 | if (value_data) |
||
1923 | *value_data = value_data_u8; |
||
1924 | else |
||
1925 | g_free (value_data_u8); |
||
1926 | |||
1927 | if (value_data_size) |
||
1928 | *value_data_size = value_data_u8_len + 1; |
||
1929 | } |
||
1930 | else |
||
1931 | { |
||
1932 | if (value_data) |
||
1933 | *value_data = value_data_w; |
||
1934 | else |
||
1935 | g_free (value_data_w); |
||
1936 | |||
1937 | if (value_data_size) |
||
1938 | *value_data_size = value_data_w_size; |
||
1939 | } |
||
1940 | |||
1941 | if (value_type) |
||
1942 | *value_type = value_type_g; |
||
1943 | |||
1944 | return TRUE; |
||
1945 | } |
||
1946 | |||
1947 | /** |
||
1948 | * g_win32_registry_key_get_value_w: |
||
1949 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
1950 | * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR |
||
1951 | * to G_WIN32_REGISTRY_VALUE_STR. |
||
1952 | * @value_name: (in) (transfer none): name of the value to get (in UTF-16). |
||
1953 | * Empty string means the '(Default)' value. |
||
1954 | * @value_type: (out) (optional): type of the value retrieved. |
||
1955 | * @value_data: (out callee-allocates) (optional): contents of the value. |
||
1956 | * @value_data_size: (out) (optional): size of the buffer pointed |
||
1957 | * by @value_data. |
||
1958 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
1959 | * |
||
1960 | * Get data from a value of a key. |
||
1961 | * |
||
1962 | * Get data from a value of a key. String data is guaranteed to be |
||
1963 | * appropriately terminated and will be in UTF-16. |
||
1964 | * |
||
1965 | * When calling with value_data == NULL (to get data size without getting |
||
1966 | * the data itself) remember that returned size corresponds to possibly |
||
1967 | * unterminated string data (if value is some kind of string), because |
||
1968 | * termination cannot be checked and fixed unless the data is retreived |
||
1969 | * too. |
||
1970 | * |
||
1971 | * Returns: %TRUE on success, %FALSE on failure. |
||
1972 | * |
||
1973 | * Since: 2.46 |
||
1974 | **/ |
||
1975 | gboolean |
||
1976 | g_win32_registry_key_get_value_w (GWin32RegistryKey *key, |
||
1977 | gboolean auto_expand, |
||
1978 | const gunichar2 *value_name, |
||
1979 | GWin32RegistryValueType *value_type, |
||
1980 | gpointer *value_data, |
||
1981 | gsize *value_data_size, |
||
1982 | GError **error) |
||
1983 | { |
||
1984 | LONG status; |
||
1985 | DWORD value_type_w; |
||
1986 | DWORD value_type_w2; |
||
1987 | char *req_value_data; |
||
1988 | GWin32RegistryValueType value_type_g; |
||
1989 | GWin32RegistryValueType value_type_g2; |
||
1990 | DWORD req_value_data_size; |
||
1991 | DWORD req_value_data_size2; |
||
1992 | |||
1993 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); |
||
1994 | g_return_val_if_fail (value_name != NULL, FALSE); |
||
1995 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
1996 | |||
1997 | /* No sense calling this functions with all of these set to NULL */ |
||
1998 | g_return_val_if_fail (value_type != NULL || |
||
1999 | value_data != NULL || |
||
2000 | value_data_size != NULL, FALSE); |
||
2001 | |||
2002 | req_value_data_size = 0; |
||
2003 | status = RegQueryValueExW (key->priv->handle, |
||
2004 | value_name, |
||
2005 | NULL, |
||
2006 | &value_type_w, |
||
2007 | NULL, |
||
2008 | &req_value_data_size); |
||
2009 | |||
2010 | if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS) |
||
2011 | { |
||
2012 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status), |
||
2013 | "Failed to query value '%S' for key '%S'", |
||
2014 | value_name, g_win32_registry_key_get_path_w (key)); |
||
2015 | |||
2016 | return FALSE; |
||
2017 | } |
||
2018 | |||
2019 | value_type_g = _g_win32_registry_type_w_to_g (value_type_w); |
||
2020 | |||
2021 | if (value_data == NULL && |
||
2022 | (!auto_expand || value_type_g != G_WIN32_REGISTRY_VALUE_EXPAND_STR)) |
||
2023 | { |
||
2024 | if (value_type) |
||
2025 | *value_type = value_type_g; |
||
2026 | |||
2027 | if (value_data_size) |
||
2028 | *value_data_size = req_value_data_size; |
||
2029 | |||
2030 | return TRUE; |
||
2031 | } |
||
2032 | |||
2033 | req_value_data = g_malloc (req_value_data_size + sizeof (gunichar2) * 2); |
||
2034 | req_value_data_size2 = req_value_data_size; |
||
2035 | status = RegQueryValueExW (key->priv->handle, |
||
2036 | value_name, |
||
2037 | NULL, |
||
2038 | &value_type_w2, |
||
2039 | (gpointer) req_value_data, |
||
2040 | &req_value_data_size2); |
||
2041 | |||
2042 | if (status != ERROR_SUCCESS) |
||
2043 | { |
||
2044 | g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status), |
||
2045 | "Failed to query value '%S' of size %lu for key '%S'", |
||
2046 | value_name, |
||
2047 | req_value_data_size, |
||
2048 | g_win32_registry_key_get_path_w (key)); |
||
2049 | g_free (req_value_data); |
||
2050 | return FALSE; |
||
2051 | } |
||
2052 | |||
2053 | value_type_g2 = _g_win32_registry_type_w_to_g (value_type_w2); |
||
2054 | |||
2055 | if (value_type_w != value_type_w2) |
||
2056 | { |
||
2057 | g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
||
2058 | "Type of value '%S' of key '%S' changed from %u to %u" |
||
2059 | " between calls", |
||
2060 | value_name, |
||
2061 | g_win32_registry_key_get_path_w (key), |
||
2062 | value_type_g, value_type_g2); |
||
2063 | g_free (req_value_data); |
||
2064 | return FALSE; |
||
2065 | } |
||
2066 | |||
2067 | req_value_data_size = ensure_nul_termination (value_type_g, |
||
2068 | (guint8 *) req_value_data, |
||
2069 | req_value_data_size2); |
||
2070 | |||
2071 | if (value_type_g == G_WIN32_REGISTRY_VALUE_EXPAND_STR && auto_expand) |
||
2072 | { |
||
2073 | gsize value_data_expanded_charsize_w = 0; |
||
2074 | gunichar2 *value_data_expanded = NULL; |
||
2075 | |||
2076 | if (!expand_value ((gunichar2 *) req_value_data, |
||
2077 | value_name, |
||
2078 | (gpointer *) &value_data_expanded, |
||
2079 | &value_data_expanded_charsize_w, |
||
2080 | error)) |
||
2081 | return FALSE; |
||
2082 | |||
2083 | g_free (req_value_data); |
||
2084 | |||
2085 | if (value_type) |
||
2086 | *value_type = G_WIN32_REGISTRY_VALUE_STR; |
||
2087 | |||
2088 | if (value_data) |
||
2089 | *value_data = value_data_expanded; |
||
2090 | else |
||
2091 | g_free (value_data_expanded); |
||
2092 | |||
2093 | if (value_data_size) |
||
2094 | *value_data_size = value_data_expanded_charsize_w * sizeof (gunichar2); |
||
2095 | |||
2096 | return TRUE; |
||
2097 | } |
||
2098 | |||
2099 | if (value_type) |
||
2100 | *value_type = value_type_g; |
||
2101 | |||
2102 | if (value_data_size) |
||
2103 | *value_data_size = req_value_data_size; |
||
2104 | |||
2105 | if (value_data) |
||
2106 | *value_data = req_value_data; |
||
2107 | else |
||
2108 | g_free (req_value_data); |
||
2109 | |||
2110 | return TRUE; |
||
2111 | } |
||
2112 | |||
2113 | static VOID NTAPI |
||
2114 | key_changed (PVOID closure, |
||
2115 | PIO_STATUS_BLOCK status_block, |
||
2116 | ULONG reserved) |
||
2117 | { |
||
2118 | GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (closure); |
||
2119 | |||
2120 | g_free (status_block); |
||
2121 | g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_CHANGED); |
||
2122 | g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED); |
||
2123 | key->priv->update_flags = G_WIN32_REGISTRY_UPDATED_NOTHING; |
||
2124 | |||
2125 | if (key->priv->callback) |
||
2126 | key->priv->callback (key, key->priv->user_data); |
||
2127 | |||
2128 | key->priv->callback = NULL; |
||
2129 | key->priv->user_data = NULL; |
||
2130 | g_object_unref (key); |
||
2131 | } |
||
2132 | |||
2133 | /** |
||
2134 | * g_win32_registry_key_watch: |
||
2135 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
2136 | * @watch_children: (in) %TRUE also watch the children of the @key, %FALSE |
||
2137 | * to watch the key only. |
||
2138 | * @watch_flags: (in): specifies the types of changes to watch for. |
||
2139 | * @callback: (in) (nullable): a function to invoke when a change occurs. |
||
2140 | * @user_data: (in) (nullable): a pointer to pass to @callback on invocation. |
||
2141 | * @error: (nullable): a pointer to %NULL #GError, or %NULL |
||
2142 | * |
||
2143 | * Puts @key under a watch. |
||
2144 | * |
||
2145 | * When the key changes, an APC will be queued in the current thread. The APC |
||
2146 | * will run when the current thread enters alertable state (GLib main loop |
||
2147 | * should do that; if you are not using it, see MSDN documentation for W32API |
||
2148 | * calls that put thread into alertable state). When it runs, it will |
||
2149 | * atomically switch an indicator in the @key. If a callback was specified, |
||
2150 | * it is invoked at that point. Subsequent calls to |
||
2151 | * g_win32_registry_key_has_changed() will return %TRUE, and the callback (if |
||
2152 | * it was specified) will not be invoked anymore. |
||
2153 | * Calling g_win32_registry_key_erase_change_indicator() will reset the indicator, |
||
2154 | * and g_win32_registry_key_has_changed() will start returning %FALSE. |
||
2155 | * To resume the watch, call g_win32_registry_key_watch_for_changes() again. |
||
2156 | * |
||
2157 | * Calling g_win32_registry_key_watch_for_changes() for a key that is already |
||
2158 | * being watched is allowed and affects nothing. |
||
2159 | * |
||
2160 | * The fact that the key is being watched will be used internally to update |
||
2161 | * key path (if it changes). |
||
2162 | * |
||
2163 | * Returns: %TRUE on success, %FALSE on failure. |
||
2164 | * |
||
2165 | * Since: 2.46 |
||
2166 | **/ |
||
2167 | gboolean |
||
2168 | g_win32_registry_key_watch (GWin32RegistryKey *key, |
||
2169 | gboolean watch_children, |
||
2170 | GWin32RegistryKeyWatcherFlags watch_flags, |
||
2171 | GWin32RegistryKeyWatchCallbackFunc callback, |
||
2172 | gpointer user_data, |
||
2173 | GError **error) |
||
2174 | { |
||
2175 | ULONG filter; |
||
2176 | gboolean started_to_watch; |
||
2177 | NTSTATUS status; |
||
2178 | PIO_STATUS_BLOCK status_block; |
||
2179 | |||
2180 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); |
||
2181 | |||
2182 | filter = ((watch_flags & G_WIN32_REGISTRY_WATCH_NAME) ? REG_NOTIFY_CHANGE_NAME : 0) | |
||
2183 | ((watch_flags & G_WIN32_REGISTRY_WATCH_ATTRIBUTES) ? REG_NOTIFY_CHANGE_ATTRIBUTES : 0) | |
||
2184 | ((watch_flags & G_WIN32_REGISTRY_WATCH_VALUES) ? REG_NOTIFY_CHANGE_LAST_SET : 0) | |
||
2185 | ((watch_flags & G_WIN32_REGISTRY_WATCH_SECURITY) ? REG_NOTIFY_CHANGE_SECURITY : 0); |
||
2186 | |||
2187 | if (filter == 0) |
||
2188 | { |
||
2189 | g_critical ("No supported flags specified in watch_flags (%x)", (guint) watch_flags); |
||
2190 | return FALSE; |
||
2191 | } |
||
2192 | |||
2193 | if (g_once_init_enter (&nt_notify_change_multiple_keys)) |
||
2194 | { |
||
2195 | NtNotifyChangeMultipleKeysFunc func; |
||
2196 | HMODULE ntdll = GetModuleHandle ("ntdll.dll"); |
||
2197 | |||
2198 | if (ntdll != NULL) |
||
2199 | func = (NtNotifyChangeMultipleKeysFunc) GetProcAddress (ntdll, "NtNotifyChangeMultipleKeys"); |
||
2200 | else |
||
2201 | func = NULL; |
||
2202 | |||
2203 | g_once_init_leave (&nt_notify_change_multiple_keys, func); |
||
2204 | } |
||
2205 | |||
2206 | if (nt_notify_change_multiple_keys== NULL) |
||
2207 | { |
||
2208 | g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, |
||
2209 | "Couldn't get NtNotifyChangeMultipleKeys() from ntdll"); |
||
2210 | return FALSE; |
||
2211 | } |
||
2212 | |||
2213 | started_to_watch = |
||
2214 | g_atomic_int_compare_and_exchange (&key->priv->watch_indicator, |
||
2215 | G_WIN32_KEY_UNWATCHED, |
||
2216 | G_WIN32_KEY_WATCHED); |
||
2217 | |||
2218 | if (!started_to_watch) |
||
2219 | return TRUE; |
||
2220 | |||
2221 | key->priv->callback = callback; |
||
2222 | key->priv->user_data = user_data; |
||
2223 | |||
2224 | g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNCHANGED); |
||
2225 | |||
2226 | /* Keep it alive until APC is called */ |
||
2227 | g_object_ref (key); |
||
2228 | |||
2229 | status_block = g_malloc (sizeof (IO_STATUS_BLOCK)); |
||
2230 | |||
2231 | status = nt_notify_change_multiple_keys (key->priv->handle, |
||
2232 | 0, |
||
2233 | NULL, |
||
2234 | NULL, |
||
2235 | key_changed, |
||
2236 | (PVOID) key, |
||
2237 | status_block, |
||
2238 | filter, |
||
2239 | watch_children, |
||
2240 | NULL, |
||
2241 | 0, |
||
2242 | TRUE); |
||
2243 | |||
2244 | g_assert (status != STATUS_SUCCESS); |
||
2245 | |||
2246 | if (status == STATUS_PENDING) |
||
2247 | return TRUE; |
||
2248 | |||
2249 | g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN); |
||
2250 | g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED); |
||
2251 | g_object_unref (key); |
||
2252 | g_free (status_block); |
||
2253 | |||
2254 | return FALSE; |
||
2255 | } |
||
2256 | |||
2257 | /** |
||
2258 | * g_win32_registry_key_erase_change_indicator: |
||
2259 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
2260 | * |
||
2261 | * Erases change indicator of the @key. |
||
2262 | * |
||
2263 | * Subsequent calls to g_win32_registry_key_has_changed() will return %FALSE |
||
2264 | * until the key is put on watch again by calling |
||
2265 | * g_win32_registry_key_watch() again. |
||
2266 | * |
||
2267 | * Since: 2.46 |
||
2268 | */ |
||
2269 | void |
||
2270 | g_win32_registry_key_erase_change_indicator (GWin32RegistryKey *key) |
||
2271 | { |
||
2272 | g_return_if_fail (G_IS_WIN32_REGISTRY_KEY (key)); |
||
2273 | |||
2274 | g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN); |
||
2275 | } |
||
2276 | |||
2277 | /** |
||
2278 | * g_win32_registry_key_has_changed: |
||
2279 | * @key: (in) (transfer none): a #GWin32RegistryKey |
||
2280 | * |
||
2281 | * Check the @key's status indicator. |
||
2282 | * |
||
2283 | * Returns: %TRUE if the @key was put under watch at some point and has changed |
||
2284 | * since then, %FALSE if it either wasn't changed or wasn't watched at all. |
||
2285 | * |
||
2286 | * Since: 2.46 |
||
2287 | */ |
||
2288 | gboolean |
||
2289 | g_win32_registry_key_has_changed (GWin32RegistryKey *key) |
||
2290 | { |
||
2291 | gint changed; |
||
2292 | |||
2293 | g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE); |
||
2294 | |||
2295 | changed = g_atomic_int_get (&key->priv->change_indicator); |
||
2296 | |||
2297 | return (changed == G_WIN32_KEY_CHANGED ? TRUE : FALSE); |
||
2298 | } |
||
2299 | |||
2300 | static void |
||
2301 | g_win32_registry_key_get_property (GObject *object, |
||
2302 | guint prop_id, |
||
2303 | GValue *value, |
||
2304 | GParamSpec *pspec) |
||
2305 | { |
||
2306 | GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (object); |
||
2307 | |||
2308 | switch (prop_id) |
||
2309 | { |
||
2310 | case PROP_PATH: |
||
2311 | g_value_set_string (value, g_win32_registry_key_get_path (key)); |
||
2312 | break; |
||
2313 | |||
2314 | case PROP_PATH_UTF16: |
||
2315 | g_value_set_pointer (value, (gpointer) g_win32_registry_key_get_path_w (key)); |
||
2316 | break; |
||
2317 | |||
2318 | default: |
||
2319 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
||
2320 | } |
||
2321 | } |
||
2322 | |||
2323 | static void |
||
2324 | g_win32_registry_key_set_property (GObject *object, |
||
2325 | guint prop_id, |
||
2326 | const GValue *value, |
||
2327 | GParamSpec *pspec) |
||
2328 | { |
||
2329 | GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (object); |
||
2330 | GWin32RegistryKeyPrivate *priv = key->priv; |
||
2331 | const gchar *path; |
||
2332 | gunichar2 *path_w; |
||
2333 | |||
2334 | switch (prop_id) |
||
2335 | { |
||
2336 | case PROP_PATH: |
||
2337 | g_assert (priv->absolute_path_w == NULL); |
||
2338 | g_assert (priv->absolute_path == NULL); |
||
2339 | path = g_value_get_string (value); |
||
2340 | |||
2341 | if (path == NULL) |
||
2342 | break; |
||
2343 | |||
2344 | path_w = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); |
||
2345 | |||
2346 | if (path_w == NULL) |
||
2347 | break; |
||
2348 | |||
2349 | g_free (priv->absolute_path_w); |
||
2350 | g_free (priv->absolute_path); |
||
2351 | priv->absolute_path_w = path_w; |
||
2352 | priv->absolute_path = g_value_dup_string (value); |
||
2353 | break; |
||
2354 | |||
2355 | case PROP_PATH_UTF16: |
||
2356 | g_assert (priv->absolute_path_w == NULL); |
||
2357 | g_assert (priv->absolute_path == NULL); |
||
2358 | path_w = (gunichar2 *) g_value_get_pointer (value); |
||
2359 | |||
2360 | if (path_w == NULL) |
||
2361 | break; |
||
2362 | |||
2363 | priv->absolute_path_w = g_wcsdup (path_w, -1); |
||
2364 | break; |
||
2365 | |||
2366 | default: |
||
2367 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
||
2368 | } |
||
2369 | } |
||
2370 | |||
2371 | static void |
||
2372 | g_win32_registry_key_class_init (GWin32RegistryKeyClass *klass) |
||
2373 | { |
||
2374 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
||
2375 | |||
2376 | gobject_class->dispose = g_win32_registry_key_dispose; |
||
2377 | gobject_class->set_property = g_win32_registry_key_set_property; |
||
2378 | gobject_class->get_property = g_win32_registry_key_get_property; |
||
2379 | |||
2380 | /** |
||
2381 | * GWin32RegistryKey:path: |
||
2382 | * |
||
2383 | * A path to the key in the registry, in UTF-8. |
||
2384 | * |
||
2385 | * Since: 2.46 |
||
2386 | */ |
||
2387 | g_object_class_install_property (gobject_class, |
||
2388 | PROP_PATH, |
||
2389 | g_param_spec_string ("path", |
||
2390 | "Path", |
||
2391 | "Path to the key in the registry", |
||
2392 | NULL, |
||
2393 | G_PARAM_READWRITE | |
||
2394 | G_PARAM_CONSTRUCT_ONLY | |
||
2395 | G_PARAM_STATIC_STRINGS)); |
||
2396 | |||
2397 | /** |
||
2398 | * GWin32RegistryKey:path-utf16: |
||
2399 | * |
||
2400 | * A path to the key in the registry, in UTF-16. |
||
2401 | * |
||
2402 | * Since: 2.46 |
||
2403 | */ |
||
2404 | g_object_class_install_property (gobject_class, |
||
2405 | PROP_PATH_UTF16, |
||
2406 | g_param_spec_pointer ("path-utf16", |
||
2407 | "Path (UTF-16)", |
||
2408 | "Path to the key in the registry, in UTF-16", |
||
2409 | G_PARAM_READWRITE | |
||
2410 | G_PARAM_CONSTRUCT_ONLY | |
||
2411 | G_PARAM_STATIC_STRINGS)); |
||
2412 | } |
||
2413 | |||
2414 | static void |
||
2415 | g_win32_registry_key_init (GWin32RegistryKey *key) |
||
2416 | { |
||
2417 | key->priv = g_win32_registry_key_get_instance_private (key); |
||
2418 | key->priv->change_indicator = G_WIN32_KEY_UNKNOWN; |
||
2419 | } |