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