• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,gunichar2 ** subkey_name,gsize * subkey_name_len,GError ** error)966 g_win32_registry_subkey_iter_get_name_w (GWin32RegistrySubkeyIter  *iter,
967                                          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,gchar ** subkey_name,gsize * subkey_name_len,GError ** error)1008 g_win32_registry_subkey_iter_get_name (GWin32RegistrySubkeyIter  *iter,
1009                                        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     {
1036       *subkey_name_len = subkey_name_len_glong;
1037       return TRUE;
1038     }
1039 
1040   return FALSE;
1041 }
1042 
1043 /**
1044  * g_win32_registry_value_iter_init:
1045  * @iter: (in) (transfer none): a pointer to a #GWin32RegistryValueIter
1046  * @key: (in) (transfer none): a #GWin32RegistryKey to iterate over
1047  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1048  *
1049  * Initialises (without allocating) a #GWin32RegistryValueIter.  @iter may be
1050  * completely uninitialised prior to this call; its old value is
1051  * ignored.
1052  *
1053  * The iterator remains valid for as long as @key exists.
1054  * Clean up its internal buffers with a call to
1055  * g_win32_registry_value_iter_clear() when done.
1056  *
1057  * Returns: %TRUE if iterator was initialized successfully, %FALSE on error.
1058  *
1059  * Since: 2.46
1060  **/
1061 gboolean
g_win32_registry_value_iter_init(GWin32RegistryValueIter * iter,GWin32RegistryKey * key,GError ** error)1062 g_win32_registry_value_iter_init (GWin32RegistryValueIter  *iter,
1063                                   GWin32RegistryKey        *key,
1064                                   GError                  **error)
1065 {
1066   LONG status;
1067   DWORD value_count;
1068   DWORD max_value_len;
1069   DWORD max_data_len;
1070 
1071   g_return_val_if_fail (iter != NULL, FALSE);
1072   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
1073   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1074 
1075   status = RegQueryInfoKeyW (key->priv->handle,
1076                              NULL, NULL, NULL, NULL, NULL, NULL,
1077                              &value_count, &max_value_len,
1078                              &max_data_len, NULL, NULL);
1079 
1080   if (status != ERROR_SUCCESS)
1081     {
1082       g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
1083                    "Failed to query info for registry key '%S'",
1084                    g_win32_registry_key_get_path_w (key));
1085       return FALSE;
1086     }
1087 
1088   iter->key = g_object_ref (key);
1089   iter->counter = -1;
1090   iter->value_count = value_count;
1091   iter->value_name_size = sizeof (gunichar2) * (max_value_len + 1);
1092   iter->value_name = g_malloc (iter->value_name_size);
1093   /* FIXME: max_value_data_len is said to have no size limit in newer W32
1094    * versions (and its size limit in older ones is 1MB!). Consider limiting it
1095    * with a hard-coded value, or by allowing the user to choose a limit.
1096    */
1097   /* Two extra gunichar2s is for cases when a string was stored in the
1098    * Registry without a 0-terminator (for multiline strings - 00-terminator),
1099    * and we need to terminate it ourselves.
1100    */
1101   iter->value_data_size = max_data_len + sizeof (gunichar2) * 2;
1102   iter->value_data = g_malloc (iter->value_data_size);
1103   iter->value_name_u8 = NULL;
1104   iter->value_data_u8 = NULL;
1105   iter->value_data_expanded = NULL;
1106   iter->value_data_expanded_charsize = 0;
1107   iter->value_data_expanded_u8 = NULL;
1108   iter->value_data_expanded_u8_size = 0;
1109   return TRUE;
1110 }
1111 
1112 /**
1113  * g_win32_registry_value_iter_clear:
1114  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1115  *
1116  * Frees internal buffers of a #GWin32RegistryValueIter.
1117  *
1118  * Since: 2.46
1119  **/
1120 void
g_win32_registry_value_iter_clear(GWin32RegistryValueIter * iter)1121 g_win32_registry_value_iter_clear (GWin32RegistryValueIter *iter)
1122 {
1123   g_return_if_fail (iter != NULL);
1124 
1125   g_free (iter->value_name);
1126   g_free (iter->value_data);
1127   g_free (iter->value_name_u8);
1128   g_free (iter->value_data_u8);
1129   g_free (iter->value_data_expanded);
1130   g_free (iter->value_data_expanded_u8);
1131   g_clear_object (&iter->key);
1132 }
1133 
1134 /**
1135  * g_win32_registry_value_iter_n_values:
1136  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1137  *
1138  * Queries the number of values items in the key that we are
1139  * iterating over.  This is the total number of values -- not the number
1140  * of items remaining.
1141  *
1142  * This information is accurate at the point of iterator initialization,
1143  * and may go out of sync with reality even while values are enumerated.
1144  *
1145  * Returns: the number of values in the key
1146  *
1147  * Since: 2.46
1148  **/
1149 gsize
g_win32_registry_value_iter_n_values(GWin32RegistryValueIter * iter)1150 g_win32_registry_value_iter_n_values (GWin32RegistryValueIter *iter)
1151 {
1152   g_return_val_if_fail (iter != NULL, 0);
1153 
1154   return iter->value_count;
1155 }
1156 
1157 static GWin32RegistryValueType
_g_win32_registry_type_w_to_g(DWORD value_type)1158 _g_win32_registry_type_w_to_g (DWORD value_type)
1159 {
1160   switch (value_type)
1161     {
1162     case REG_BINARY:
1163       return G_WIN32_REGISTRY_VALUE_BINARY;
1164     case REG_DWORD:
1165       return G_WIN32_REGISTRY_VALUE_UINT32;
1166 #if G_BYTE_ORDER == G_BIG_ENDIAN
1167     case REG_DWORD_LITTLE_ENDIAN:
1168       return G_WIN32_REGISTRY_VALUE_UINT32LE;
1169 #else
1170     case REG_DWORD_BIG_ENDIAN:
1171       return G_WIN32_REGISTRY_VALUE_UINT32BE;
1172 #endif
1173     case REG_EXPAND_SZ:
1174       return G_WIN32_REGISTRY_VALUE_EXPAND_STR;
1175     case REG_LINK:
1176       return G_WIN32_REGISTRY_VALUE_LINK;
1177     case REG_MULTI_SZ:
1178       return G_WIN32_REGISTRY_VALUE_MULTI_STR;
1179     case REG_NONE:
1180       return G_WIN32_REGISTRY_VALUE_NONE;
1181     case REG_QWORD:
1182       return G_WIN32_REGISTRY_VALUE_UINT64;
1183 #if G_BYTE_ORDER == G_BIG_ENDIAN
1184     case REG_QWORD_LITTLE_ENDIAN:
1185       return G_WIN32_REGISTRY_VALUE_UINT64LE;
1186 #endif
1187     case REG_SZ:
1188       return G_WIN32_REGISTRY_VALUE_STR;
1189     default:
1190       return G_WIN32_REGISTRY_VALUE_NONE;
1191     }
1192 }
1193 
1194 static gsize
ensure_nul_termination(GWin32RegistryValueType value_type,guint8 * value_data,gsize value_data_size)1195 ensure_nul_termination (GWin32RegistryValueType  value_type,
1196                         guint8                  *value_data,
1197                         gsize                    value_data_size)
1198 {
1199   gsize new_size = value_data_size;
1200 
1201   if (value_type == G_WIN32_REGISTRY_VALUE_EXPAND_STR ||
1202       value_type == G_WIN32_REGISTRY_VALUE_LINK ||
1203       value_type == G_WIN32_REGISTRY_VALUE_STR)
1204     {
1205       if ((value_data_size < 2) ||
1206           (value_data[value_data_size - 1] != 0) ||
1207           (value_data[value_data_size - 2] != 0))
1208         {
1209           value_data[value_data_size] = 0;
1210           value_data[value_data_size + 1] = 0;
1211           new_size += 2;
1212         }
1213     }
1214   else if (value_type == G_WIN32_REGISTRY_VALUE_MULTI_STR)
1215     {
1216       if ((value_data_size < 4) ||
1217           (value_data[value_data_size - 1] != 0) ||
1218           (value_data[value_data_size - 2] != 0) ||
1219           (value_data[value_data_size - 3] != 0) ||
1220           (value_data[value_data_size - 4] != 0))
1221         {
1222           value_data[value_data_size] = 0;
1223           value_data[value_data_size + 1] = 0;
1224           value_data[value_data_size + 2] = 0;
1225           value_data[value_data_size + 3] = 0;
1226           new_size += 4;
1227         }
1228     }
1229 
1230   return new_size;
1231 }
1232 
1233 /**
1234  * g_win32_registry_value_iter_next:
1235  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1236  * @skip_errors: (in): %TRUE if iterator should silently ignore errors (such as
1237  *     the actual number of values being less than expected) and
1238  *     proceed forward
1239  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1240  *
1241  * Advances iterator to the next value in the key. If no more values remain then
1242  * FALSE is returned.
1243  * Enumeration errors can be ignored if @skip_errors is %TRUE
1244  *
1245  * Here is an example for iterating with g_win32_registry_value_iter_next():
1246  * |[<!-- language="C" -->
1247  *   // iterate values of a key
1248  *   void
1249  *   iterate_values_recursive (GWin32RegistryKey *key)
1250  *   {
1251  *     GWin32RegistryValueIter iter;
1252  *     gchar *name;
1253  *     GWin32RegistryValueType val_type;
1254  *     gchar *val_data;
1255  *
1256  *     if (!g_win32_registry_value_iter_init (&iter, key, NULL))
1257  *       return;
1258  *
1259  *     while (g_win32_registry_value_iter_next (&iter, TRUE, NULL))
1260  *       {
1261  *         if ((!g_win32_registry_value_iter_get_value_type (&iter, &value)) ||
1262  *             ((val_type != G_WIN32_REGISTRY_VALUE_STR) &&
1263  *              (val_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR)))
1264  *           continue;
1265  *
1266  *         if (g_win32_registry_value_iter_get_value (&iter, TRUE, &name, NULL,
1267  *                                                    &val_data, NULL, NULL))
1268  *           g_print ("value '%s' = '%s'\n", name, val_data);
1269  *       }
1270  *
1271  *     g_win32_registry_value_iter_clear (&iter);
1272  *   }
1273  * ]|
1274  *
1275  * Returns: %TRUE if next value info was retrieved, %FALSE otherwise.
1276  *
1277  * Since: 2.46
1278  **/
1279 gboolean
g_win32_registry_value_iter_next(GWin32RegistryValueIter * iter,gboolean skip_errors,GError ** error)1280 g_win32_registry_value_iter_next (GWin32RegistryValueIter  *iter,
1281                                   gboolean                  skip_errors,
1282                                   GError                  **error)
1283 {
1284   LONG status;
1285   DWORD value_name_len_w;
1286   DWORD value_data_size_w;
1287   DWORD value_type_w;
1288   GWin32RegistryValueType value_type_g;
1289 
1290   g_return_val_if_fail (iter != NULL, FALSE);
1291   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1292 
1293   if G_UNLIKELY (iter->counter >= iter->value_count)
1294     {
1295       g_critical ("g_win32_registry_value_iter_next: must not be called "
1296                   "again after FALSE has already been returned.");
1297       return FALSE;
1298     }
1299 
1300   while (TRUE)
1301     {
1302       iter->counter += 1;
1303 
1304       if (iter->counter >= iter->value_count)
1305         return FALSE;
1306 
1307       g_clear_pointer (&iter->value_name_u8, g_free);
1308       g_clear_pointer (&iter->value_data_u8, g_free);
1309       g_clear_pointer (&iter->value_data_expanded_u8, g_free);
1310       /* Including 0-terminator */
1311       value_name_len_w = iter->value_name_size / sizeof (gunichar2);
1312       value_data_size_w = iter->value_data_size;
1313       status = RegEnumValueW (iter->key->priv->handle,
1314                               iter->counter,
1315                               iter->value_name,
1316                               &value_name_len_w,
1317                               NULL,
1318                               &value_type_w,
1319                               (LPBYTE) iter->value_data,
1320                               &value_data_size_w);
1321 
1322       if (status != ERROR_SUCCESS && !skip_errors)
1323         {
1324           g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
1325                        "Failed to enumerate value #%d for key '%S'",
1326                        iter->counter, g_win32_registry_key_get_path_w (iter->key));
1327           iter->value_count = 0;
1328 
1329           return FALSE;
1330         }
1331       else if (status != ERROR_SUCCESS && skip_errors)
1332         continue;
1333 
1334       value_type_g = _g_win32_registry_type_w_to_g (value_type_w);
1335       value_data_size_w = ensure_nul_termination (value_type_g,
1336                                                   iter->value_data,
1337                                                   value_data_size_w);
1338       iter->value_type = value_type_g;
1339       iter->value_expanded_type = value_type_g;
1340       iter->value_actual_data_size = value_data_size_w;
1341       iter->value_name_len = value_name_len_w;
1342 
1343       return TRUE;
1344     }
1345 }
1346 
1347 /**
1348  * g_win32_registry_value_iter_get_value_type:
1349  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1350  * @value_type: (out): Pointer to a location to store the type of
1351  *     the value.
1352  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1353  *
1354  * Stores the type of the value currently being iterated over in @value_type.
1355  *
1356  * Returns: %TRUE if value type was retrieved, %FALSE otherwise.
1357  *
1358  * Since: 2.46
1359  **/
1360 gboolean
g_win32_registry_value_iter_get_value_type(GWin32RegistryValueIter * iter,GWin32RegistryValueType * value_type,GError ** error)1361 g_win32_registry_value_iter_get_value_type (GWin32RegistryValueIter  *iter,
1362                                             GWin32RegistryValueType  *value_type,
1363                                             GError                  **error)
1364 {
1365   g_return_val_if_fail (iter != NULL, FALSE);
1366   g_return_val_if_fail (value_type != NULL, FALSE);
1367   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1368 
1369   if G_UNLIKELY (iter->counter >= iter->value_count)
1370     {
1371       g_critical ("g_win32_registry_value_iter_get_type: must not be called "
1372                   "again after NULL has already been returned.");
1373       return FALSE;
1374     }
1375 
1376   *value_type = iter->value_type;
1377 
1378   return TRUE;
1379 }
1380 
1381 /**
1382  * g_win32_registry_value_iter_get_name_w:
1383  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1384  * @value_name: (out callee-allocates) (transfer none): Pointer to a location
1385  *     to store the name of a value (in UTF-16).
1386  * @value_name_len: (out) (optional): Pointer to a location to store the length
1387  *     of @value_name, in gunichar2s, excluding NUL-terminator.
1388  *     %NULL if length is not needed.
1389  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1390  *
1391  * Stores the name of the value currently being iterated over in @value_name,
1392  * and its length - in @value_name (if not %NULL).
1393  *
1394  * Returns: %TRUE if value name was retrieved, %FALSE otherwise.
1395  *
1396  * Since: 2.46
1397  **/
1398 gboolean
g_win32_registry_value_iter_get_name_w(GWin32RegistryValueIter * iter,gunichar2 ** value_name,gsize * value_name_len,GError ** error)1399 g_win32_registry_value_iter_get_name_w (GWin32RegistryValueIter  *iter,
1400                                         gunichar2               **value_name,
1401                                         gsize                    *value_name_len,
1402                                         GError                  **error)
1403 {
1404   g_return_val_if_fail (iter != NULL, FALSE);
1405   g_return_val_if_fail (value_name != NULL, FALSE);
1406   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1407 
1408   if G_UNLIKELY (iter->counter >= iter->value_count)
1409     {
1410       g_critical ("g_win32_registry_value_iter_get_name_w: must not be called "
1411                   "again after NULL has already been returned.");
1412       return FALSE;
1413     }
1414 
1415   *value_name = iter->value_name;
1416 
1417   if (value_name_len)
1418     *value_name_len = iter->value_name_len;
1419 
1420   return TRUE;
1421 }
1422 
1423 /**
1424  * g_win32_registry_value_iter_get_name:
1425  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1426  * @value_name: (out callee-allocates) (transfer none): Pointer to a location
1427  *     to store the name of a value (in UTF-8).
1428  * @value_name_len: (out) (optional): Pointer to a location to store the length
1429  *     of @value_name, in gchars, excluding NUL-terminator.
1430  *     %NULL if length is not needed.
1431  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1432  *
1433  * Stores the name of the value currently being iterated over in @value_name,
1434  * and its length - in @value_name_len (if not %NULL).
1435  *
1436  * Returns: %TRUE if value name was retrieved, %FALSE otherwise.
1437  *
1438  * Since: 2.46
1439  **/
1440 gboolean
g_win32_registry_value_iter_get_name(GWin32RegistryValueIter * iter,gchar ** value_name,gsize * value_name_len,GError ** error)1441 g_win32_registry_value_iter_get_name (GWin32RegistryValueIter  *iter,
1442                                       gchar                   **value_name,
1443                                       gsize                    *value_name_len,
1444                                       GError                  **error)
1445 {
1446   glong value_name_len_glong;
1447 
1448   g_return_val_if_fail (iter != NULL, FALSE);
1449   g_return_val_if_fail (value_name != NULL, FALSE);
1450   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1451 
1452   if G_UNLIKELY (iter->counter >= iter->value_count)
1453     {
1454       g_critical ("g_win32_registry_value_iter_get_name: must not be called "
1455                   "again after NULL has already been returned.");
1456       return FALSE;
1457     }
1458 
1459   if (iter->value_name_u8 == NULL)
1460     {
1461       iter->value_name_u8 = g_utf16_to_utf8 (iter->value_name, iter->value_name_len, NULL,
1462                                              &value_name_len_glong, error);
1463 
1464       if (iter->value_name_u8 == NULL)
1465         return FALSE;
1466     }
1467 
1468   *value_name = iter->value_name_u8;
1469 
1470   if (value_name_len)
1471     *value_name_len = iter->value_name_u8_len;
1472 
1473   return TRUE;
1474 }
1475 
1476 static gboolean
expand_value(gunichar2 * value,const gunichar2 * value_name,gpointer * expanded_value,gsize * expanded_charsize,GError ** error)1477 expand_value (gunichar2  *value,
1478               const gunichar2  *value_name,
1479               gpointer   *expanded_value,
1480               gsize      *expanded_charsize,
1481               GError    **error)
1482 {
1483   DWORD value_data_expanded_charsize_w;
1484 
1485   value_data_expanded_charsize_w =
1486       ExpandEnvironmentStringsW (value,
1487                                  (gunichar2 *) *expanded_value,
1488                                  *expanded_charsize);
1489 
1490   if (value_data_expanded_charsize_w > *expanded_charsize)
1491     {
1492       *expanded_value = g_realloc (*expanded_value,
1493                                    value_data_expanded_charsize_w * sizeof (gunichar2));
1494       *expanded_charsize = value_data_expanded_charsize_w;
1495       value_data_expanded_charsize_w =
1496           ExpandEnvironmentStringsW (value,
1497                                      (gunichar2 *) *expanded_value,
1498                                      *expanded_charsize);
1499     }
1500 
1501   if (value_data_expanded_charsize_w == 0)
1502     {
1503       g_set_error (error, G_IO_ERROR,
1504                    g_io_error_from_win32_error (GetLastError ()),
1505                    "Failed to expand data '%S' of value %S",
1506                    value, value_name);
1507       return FALSE;
1508     }
1509 
1510   return TRUE;
1511 }
1512 
1513 /**
1514  * g_win32_registry_value_iter_get_data_w:
1515  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1516  * @auto_expand: (in): %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR to
1517  *     G_WIN32_REGISTRY_VALUE_STR
1518  * @value_data: (out callee-allocates) (optional) (transfer none): Pointer to a
1519  *     location to store the data of the value (in UTF-16, if it's a string)
1520  * @value_data_size: (out) (optional): Pointer to a location to store the size
1521  *     of @value_data, in bytes (including any NUL-terminators, if it's a string).
1522  *     %NULL if length is not needed.
1523  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1524  *
1525  * Stores the data of the value currently being iterated over in @value_data,
1526  * and its length - in @value_data_len (if not %NULL).
1527  *
1528  * Returns: %TRUE if value data was retrieved, %FALSE otherwise.
1529  *
1530  * Since: 2.46
1531  **/
1532 gboolean
g_win32_registry_value_iter_get_data_w(GWin32RegistryValueIter * iter,gboolean auto_expand,gpointer * value_data,gsize * value_data_size,GError ** error)1533 g_win32_registry_value_iter_get_data_w (GWin32RegistryValueIter  *iter,
1534                                         gboolean                  auto_expand,
1535                                         gpointer                 *value_data,
1536                                         gsize                    *value_data_size,
1537                                         GError                  **error)
1538 {
1539   g_return_val_if_fail (iter != NULL, FALSE);
1540   g_return_val_if_fail (value_data != NULL, FALSE);
1541   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1542 
1543   if G_UNLIKELY (iter->counter >= iter->value_count)
1544     {
1545       g_critical ("g_win32_registry_value_iter_get_data_w: must not be called "
1546                   "again after FALSE has already been returned.");
1547       return FALSE;
1548     }
1549 
1550   if (!auto_expand || (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR))
1551     {
1552       *value_data = iter->value_data;
1553 
1554       if (value_data_size)
1555         *value_data_size = iter->value_actual_data_size;
1556 
1557       return TRUE;
1558     }
1559 
1560   if (iter->value_type == iter->value_expanded_type)
1561     {
1562       if (!expand_value ((gunichar2 *) iter->value_data,
1563                          iter->value_name,
1564                          (gpointer *) &iter->value_data_expanded,
1565                          &iter->value_data_expanded_charsize,
1566                          error))
1567         return FALSE;
1568 
1569       iter->value_expanded_type = G_WIN32_REGISTRY_VALUE_STR;
1570     }
1571 
1572   *value_data = iter->value_data_expanded;
1573 
1574   if (value_data_size)
1575     *value_data_size = iter->value_data_expanded_charsize * sizeof (gunichar2);
1576 
1577   return TRUE;
1578 }
1579 
1580 /**
1581  * g_win32_registry_value_iter_get_data:
1582  * @iter: (in) (transfer none): a #GWin32RegistryValueIter
1583  * @auto_expand: (in): %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR to
1584  *     G_WIN32_REGISTRY_VALUE_STR
1585  * @value_data: (out callee-allocates) (optional) (transfer none): Pointer to a
1586  *     location to store the data of the value (in UTF-8, if it's a string)
1587  * @value_data_size: (out) (optional): Pointer to a location to store the length
1588  *     of @value_data, in bytes (including any NUL-terminators, if it's a string).
1589  *     %NULL if length is not needed
1590  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1591  *
1592  * Stores the data of the value currently being iterated over in @value_data,
1593  * and its length - in @value_data_len (if not %NULL).
1594  *
1595  * Returns: %TRUE if value data was retrieved, %FALSE otherwise.
1596  *
1597  * Since: 2.46
1598  **/
1599 gboolean
g_win32_registry_value_iter_get_data(GWin32RegistryValueIter * iter,gboolean auto_expand,gpointer * value_data,gsize * value_data_size,GError ** error)1600 g_win32_registry_value_iter_get_data (GWin32RegistryValueIter  *iter,
1601                                       gboolean                  auto_expand,
1602                                       gpointer                 *value_data,
1603                                       gsize                    *value_data_size,
1604                                       GError                  **error)
1605 {
1606   gsize value_data_len_gsize;
1607   gpointer tmp;
1608   gsize tmp_size;
1609 
1610   g_return_val_if_fail (iter != NULL, FALSE);
1611   g_return_val_if_fail (value_data != NULL, FALSE);
1612   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1613 
1614   if G_UNLIKELY (iter->counter >= iter->value_count)
1615     {
1616       g_critical ("g_win32_registry_value_iter_get_data: must not be called "
1617                   "again after FALSE has already been returned.");
1618       return FALSE;
1619     }
1620 
1621   if (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR &&
1622       iter->value_type != G_WIN32_REGISTRY_VALUE_LINK &&
1623       iter->value_type != G_WIN32_REGISTRY_VALUE_STR &&
1624       iter->value_type != G_WIN32_REGISTRY_VALUE_MULTI_STR)
1625     {
1626       *value_data = iter->value_data;
1627 
1628       if (value_data_size != NULL)
1629         *value_data_size = iter->value_actual_data_size;
1630 
1631       return TRUE;
1632     }
1633 
1634   if (!auto_expand || (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR))
1635     {
1636       if (iter->value_data_u8 == NULL)
1637         {
1638           iter->value_data_u8 = g_convert ((const gchar *) iter->value_data,
1639                                            iter->value_actual_data_size - sizeof (gunichar2) /* excl. 0 */,
1640                                            "UTF8", "UTF16", NULL,
1641                                            &value_data_len_gsize,
1642                                            error);
1643 
1644           if (iter->value_data_u8 == NULL)
1645             return FALSE;
1646 
1647           iter->value_data_u8_size = value_data_len_gsize + 1; /* incl. 0 */
1648         }
1649 
1650       *value_data = iter->value_data_u8;
1651 
1652       if (value_data_size != NULL)
1653         *value_data_size = iter->value_data_u8_size;
1654 
1655       return TRUE;
1656     }
1657 
1658   if (iter->value_data_expanded_u8 == NULL)
1659     {
1660       if (!g_win32_registry_value_iter_get_data_w (iter,
1661                                                    TRUE,
1662                                                    &tmp,
1663                                                    &tmp_size,
1664                                                    error))
1665         return FALSE;
1666 
1667       iter->value_data_expanded_u8 = g_convert ((const gchar *) iter->value_data_expanded,
1668                                                 iter->value_data_expanded_charsize * sizeof (gunichar2) - sizeof (gunichar2) /* excl. 0 */,
1669                                                 "UTF8", "UTF16", NULL,
1670                                                 &value_data_len_gsize,
1671                                                 error);
1672 
1673       if (iter->value_data_expanded_u8 == NULL)
1674         return FALSE;
1675 
1676       iter->value_data_u8_size = value_data_len_gsize + 1; /* incl. 0 */
1677     }
1678 
1679   *value_data = iter->value_data_expanded_u8;
1680 
1681   if (value_data_size != NULL)
1682     *value_data_size = iter->value_data_expanded_u8_size;
1683 
1684   return TRUE;
1685 }
1686 
1687 static void
_g_win32_registry_key_reread_kernel(GWin32RegistryKey * key,GWin32RegistryKeyPrivate * buf)1688 _g_win32_registry_key_reread_kernel (GWin32RegistryKey        *key,
1689                                      GWin32RegistryKeyPrivate *buf)
1690 {
1691   NTSTATUS status;
1692   KEY_BASIC_INFORMATION *basic_info;
1693   ULONG basic_info_size;
1694   ULONG datasize;
1695 
1696   basic_info_size = 256 * sizeof (gunichar2) + sizeof (KEY_BASIC_INFORMATION);
1697   basic_info = g_malloc (basic_info_size + sizeof (gunichar2));
1698   status = nt_query_key (key->priv->handle,
1699                          KeyBasicInformation,
1700                          basic_info,
1701                          basic_info_size,
1702                          &datasize);
1703 
1704   if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)
1705     {
1706       g_free (basic_info);
1707       basic_info_size = datasize;
1708        /* +1 for 0-terminator */
1709       basic_info = g_malloc (basic_info_size + sizeof (gunichar2));
1710       status = nt_query_key (key->priv->handle,
1711                              KeyBasicInformation,
1712                              basic_info,
1713                              basic_info_size,
1714                              &datasize);
1715     }
1716 
1717   if (status != STATUS_SUCCESS)
1718     {
1719       g_free (basic_info);
1720       return;
1721     }
1722 
1723   /* Ensure 0-termination */
1724   ((char *) basic_info)[datasize] = 0;
1725   ((char *) basic_info)[datasize + 1] = 0;
1726 
1727   buf->absolute_path_w = g_wcsdup (&basic_info->Name[0],
1728                                    basic_info->NameLength + sizeof (gunichar2));
1729   g_free (basic_info);
1730 }
1731 
1732 static void
_g_win32_registry_key_reread_user(GWin32RegistryKey * key,GWin32RegistryKeyPrivate * buf)1733 _g_win32_registry_key_reread_user (GWin32RegistryKey        *key,
1734                                    GWin32RegistryKeyPrivate *buf)
1735 {
1736   /* Use RegQueryInfoKey(). It's just like NtQueryKey(), but can't query
1737    * key name.
1738    * Since right now we only need the name, this function is a noop.
1739    */
1740 }
1741 
1742 static void
_g_win32_registry_key_reread(GWin32RegistryKey * key,GWin32RegistryKeyPrivate * buf)1743 _g_win32_registry_key_reread (GWin32RegistryKey        *key,
1744                               GWin32RegistryKeyPrivate *buf)
1745 {
1746   if (g_once_init_enter (&nt_query_key))
1747     {
1748       NtQueryKeyFunc func;
1749       HMODULE ntdll = GetModuleHandleW (L"ntdll.dll");
1750 
1751       if (ntdll != NULL)
1752         func = (NtQueryKeyFunc) GetProcAddress (ntdll, "NtQueryKey");
1753       else
1754         func = NULL;
1755 
1756       g_once_init_leave (&nt_query_key, func);
1757     }
1758 
1759   /* Assume that predefined keys never get renamed. Also, their handles probably
1760    * won't be accepted by NtQueryKey(), i suspect.
1761    */
1762   if (nt_query_key != NULL && !key->priv->predefined)
1763     _g_win32_registry_key_reread_kernel (key, buf);
1764   else
1765     _g_win32_registry_key_reread_user (key, buf);
1766 }
1767 
1768 static gboolean
_g_win32_registry_key_update_path(GWin32RegistryKey * key)1769 _g_win32_registry_key_update_path (GWin32RegistryKey *key)
1770 {
1771   GWin32RegistryKeyPrivate tmp;
1772   gboolean changed;
1773   gint change_indicator;
1774 
1775   change_indicator = g_atomic_int_get (&key->priv->change_indicator);
1776 
1777   if (change_indicator == G_WIN32_KEY_UNCHANGED)
1778     return FALSE;
1779 
1780   tmp.absolute_path_w = NULL;
1781   _g_win32_registry_key_reread (key, &tmp);
1782   changed = FALSE;
1783 
1784   if (wcscmp (key->priv->absolute_path_w, tmp.absolute_path_w) == 0)
1785     g_free (tmp.absolute_path_w);
1786   else
1787     {
1788       g_free (key->priv->absolute_path_w);
1789       key->priv->absolute_path_w = tmp.absolute_path_w;
1790       changed = TRUE;
1791     }
1792 
1793   return changed;
1794 }
1795 
1796 /**
1797  * g_win32_registry_key_get_path:
1798  * @key: (in) (transfer none): a #GWin32RegistryKey
1799  *
1800  * Get full path to the key
1801  *
1802  * Returns: (transfer none): a full path to the key (in UTF-8),
1803  *     or %NULL if it can't be converted to UTF-8.
1804  *
1805  * Since: 2.46
1806  **/
1807 const gchar *
g_win32_registry_key_get_path(GWin32RegistryKey * key)1808 g_win32_registry_key_get_path (GWin32RegistryKey *key)
1809 {
1810   gint change_indicator;
1811 
1812   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL);
1813 
1814   change_indicator = g_atomic_int_get (&key->priv->change_indicator);
1815 
1816   if (change_indicator == G_WIN32_KEY_CHANGED &&
1817       !(key->priv->update_flags & G_WIN32_REGISTRY_UPDATED_PATH))
1818     {
1819       _g_win32_registry_key_update_path (key);
1820       key->priv->update_flags |= G_WIN32_REGISTRY_UPDATED_PATH;
1821     }
1822 
1823   if (key->priv->absolute_path == NULL)
1824     {
1825       g_free (key->priv->absolute_path);
1826       key->priv->absolute_path =
1827           g_utf16_to_utf8 (key->priv->absolute_path_w, -1,
1828                            NULL, NULL, NULL);
1829     }
1830 
1831   return key->priv->absolute_path;
1832 }
1833 
1834 /**
1835  * g_win32_registry_key_get_path_w:
1836  * @key: (in) (transfer none): a #GWin32RegistryKey
1837  *
1838  * Get full path to the key
1839  *
1840  * Returns: (transfer none): a full path to the key (in UTF-16)
1841  *
1842  * Since: 2.46
1843  **/
1844 const gunichar2 *
g_win32_registry_key_get_path_w(GWin32RegistryKey * key)1845 g_win32_registry_key_get_path_w (GWin32RegistryKey *key)
1846 {
1847   gint change_indicator;
1848 
1849   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL);
1850 
1851   change_indicator = g_atomic_int_get (&key->priv->change_indicator);
1852 
1853   if (change_indicator == G_WIN32_KEY_CHANGED)
1854     _g_win32_registry_key_update_path (key);
1855 
1856   return key->priv->absolute_path_w;
1857 }
1858 
1859 /**
1860  * g_win32_registry_key_get_value:
1861  * @key: (in) (transfer none): a #GWin32RegistryKey
1862  * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR
1863  *     to G_WIN32_REGISTRY_VALUE_STR.
1864  * @value_name: (in) (transfer none): name of the value to get (in UTF-8).
1865  *   Empty string means the '(Default)' value.
1866  * @value_type: (out) (optional): type of the value retrieved.
1867  * @value_data: (out callee-allocates) (optional): contents of the value.
1868  * @value_data_size: (out) (optional): size of the buffer pointed
1869  *   by @value_data.
1870  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1871  *
1872  * Get data from a value of a key. String data is guaranteed to be
1873  * appropriately terminated and will be in UTF-8.
1874  *
1875  * Returns: %TRUE on success, %FALSE on failure.
1876  *
1877  * Since: 2.46
1878  **/
1879 gboolean
g_win32_registry_key_get_value(GWin32RegistryKey * key,gboolean auto_expand,const gchar * value_name,GWin32RegistryValueType * value_type,gpointer * value_data,gsize * value_data_size,GError ** error)1880 g_win32_registry_key_get_value (GWin32RegistryKey        *key,
1881                                 gboolean                  auto_expand,
1882                                 const gchar              *value_name,
1883                                 GWin32RegistryValueType  *value_type,
1884                                 gpointer                 *value_data,
1885                                 gsize                    *value_data_size,
1886                                 GError                  **error)
1887 {
1888   GWin32RegistryValueType value_type_g;
1889   gpointer value_data_w;
1890   gsize value_data_w_size;
1891   gunichar2 *value_name_w;
1892   gchar *value_data_u8;
1893   gsize value_data_u8_len;
1894   gboolean result;
1895 
1896   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
1897   g_return_val_if_fail (value_name != NULL, FALSE);
1898   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1899 
1900   /* No sense calling this function with all of these set to NULL */
1901   g_return_val_if_fail (value_type != NULL ||
1902                         value_data != NULL ||
1903                         value_data_size != NULL, FALSE);
1904 
1905   value_name_w = g_utf8_to_utf16 (value_name, -1, NULL, NULL, error);
1906 
1907   if (value_name_w == NULL)
1908     return FALSE;
1909 
1910   result = g_win32_registry_key_get_value_w (key,
1911                                              auto_expand,
1912                                              value_name_w,
1913                                              &value_type_g,
1914                                              &value_data_w,
1915                                              &value_data_w_size,
1916                                              error);
1917 
1918   g_free (value_name_w);
1919 
1920   if (!result)
1921     return FALSE;
1922 
1923   if (value_type_g == G_WIN32_REGISTRY_VALUE_EXPAND_STR ||
1924       value_type_g == G_WIN32_REGISTRY_VALUE_LINK ||
1925       value_type_g == G_WIN32_REGISTRY_VALUE_STR ||
1926       value_type_g == G_WIN32_REGISTRY_VALUE_MULTI_STR)
1927     {
1928       value_data_u8 = g_convert ((const gchar *) value_data_w,
1929                                  value_data_w_size - sizeof (gunichar2) /* excl. 0 */,
1930                                  "UTF8",
1931                                  "UTF16",
1932                                  NULL,
1933                                  &value_data_u8_len,
1934                                  error);
1935       g_free (value_data_w);
1936 
1937       if (value_data_u8 == NULL)
1938         return FALSE;
1939 
1940       if (value_data)
1941         *value_data = value_data_u8;
1942       else
1943         g_free (value_data_u8);
1944 
1945       if (value_data_size)
1946         *value_data_size = value_data_u8_len + 1;
1947     }
1948   else
1949     {
1950       if (value_data)
1951         *value_data = value_data_w;
1952       else
1953         g_free (value_data_w);
1954 
1955       if (value_data_size)
1956         *value_data_size = value_data_w_size;
1957     }
1958 
1959   if (value_type)
1960     *value_type = value_type_g;
1961 
1962   return TRUE;
1963 }
1964 
1965 /**
1966  * g_win32_registry_key_get_value_w:
1967  * @key: (in) (transfer none): a #GWin32RegistryKey
1968  * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR
1969  *     to G_WIN32_REGISTRY_VALUE_STR.
1970  * @value_name: (in) (transfer none): name of the value to get (in UTF-16).
1971  *   Empty string means the '(Default)' value.
1972  * @value_type: (out) (optional): type of the value retrieved.
1973  * @value_data: (out callee-allocates) (optional): contents of the value.
1974  * @value_data_size: (out) (optional): size of the buffer pointed
1975  *   by @value_data.
1976  * @error: (nullable): a pointer to %NULL #GError, or %NULL
1977  *
1978  * Get data from a value of a key.
1979  *
1980  * Get data from a value of a key. String data is guaranteed to be
1981  * appropriately terminated and will be in UTF-16.
1982  *
1983  * When calling with value_data == NULL (to get data size without getting
1984  * the data itself) remember that returned size corresponds to possibly
1985  * unterminated string data (if value is some kind of string), because
1986  * termination cannot be checked and fixed unless the data is retreived
1987  * too.
1988  *
1989  * Returns: %TRUE on success, %FALSE on failure.
1990  *
1991  * Since: 2.46
1992  **/
1993 gboolean
g_win32_registry_key_get_value_w(GWin32RegistryKey * key,gboolean auto_expand,const gunichar2 * value_name,GWin32RegistryValueType * value_type,gpointer * value_data,gsize * value_data_size,GError ** error)1994 g_win32_registry_key_get_value_w (GWin32RegistryKey        *key,
1995                                   gboolean                  auto_expand,
1996                                   const gunichar2          *value_name,
1997                                   GWin32RegistryValueType  *value_type,
1998                                   gpointer                 *value_data,
1999                                   gsize                    *value_data_size,
2000                                   GError                  **error)
2001 {
2002   LONG status;
2003   DWORD value_type_w;
2004   DWORD value_type_w2;
2005   char *req_value_data;
2006   GWin32RegistryValueType value_type_g;
2007   GWin32RegistryValueType value_type_g2;
2008   DWORD req_value_data_size;
2009   DWORD req_value_data_size2;
2010 
2011   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
2012   g_return_val_if_fail (value_name != NULL, FALSE);
2013   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2014 
2015   /* No sense calling this functions with all of these set to NULL */
2016   g_return_val_if_fail (value_type != NULL ||
2017                         value_data != NULL ||
2018                         value_data_size != NULL, FALSE);
2019 
2020   req_value_data_size = 0;
2021   status = RegQueryValueExW (key->priv->handle,
2022                              value_name,
2023                              NULL,
2024                              &value_type_w,
2025                              NULL,
2026                              &req_value_data_size);
2027 
2028   if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
2029     {
2030       g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
2031                    "Failed to query value '%S' for key '%S'",
2032                    value_name, g_win32_registry_key_get_path_w (key));
2033 
2034       return FALSE;
2035     }
2036 
2037   value_type_g = _g_win32_registry_type_w_to_g (value_type_w);
2038 
2039   if (value_data == NULL &&
2040       (!auto_expand || value_type_g != G_WIN32_REGISTRY_VALUE_EXPAND_STR))
2041     {
2042       if (value_type)
2043         *value_type = value_type_g;
2044 
2045       if (value_data_size)
2046         *value_data_size = req_value_data_size;
2047 
2048       return TRUE;
2049     }
2050 
2051   req_value_data = g_malloc (req_value_data_size + sizeof (gunichar2) * 2);
2052   req_value_data_size2 = req_value_data_size;
2053   status = RegQueryValueExW (key->priv->handle,
2054                              value_name,
2055                              NULL,
2056                              &value_type_w2,
2057                              (gpointer) req_value_data,
2058                              &req_value_data_size2);
2059 
2060   if (status != ERROR_SUCCESS)
2061     {
2062       g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
2063                    "Failed to query value '%S' of size %lu for key '%S'",
2064                    value_name,
2065                    req_value_data_size,
2066                    g_win32_registry_key_get_path_w (key));
2067       g_free (req_value_data);
2068       return FALSE;
2069     }
2070 
2071   value_type_g2 = _g_win32_registry_type_w_to_g (value_type_w2);
2072 
2073   if (value_type_w != value_type_w2)
2074     {
2075       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
2076                    "Type of value '%S' of key '%S' changed from %u to %u"
2077                    " between calls",
2078                    value_name,
2079                    g_win32_registry_key_get_path_w (key),
2080                    value_type_g, value_type_g2);
2081       g_free (req_value_data);
2082       return FALSE;
2083     }
2084 
2085   req_value_data_size = ensure_nul_termination (value_type_g,
2086                                                 (guint8 *) req_value_data,
2087                                                 req_value_data_size2);
2088 
2089   if (value_type_g == G_WIN32_REGISTRY_VALUE_EXPAND_STR && auto_expand)
2090     {
2091       gsize value_data_expanded_charsize_w = 0;
2092       gunichar2 *value_data_expanded = NULL;
2093 
2094       if (!expand_value ((gunichar2 *) req_value_data,
2095                          value_name,
2096                          (gpointer *) &value_data_expanded,
2097                          &value_data_expanded_charsize_w,
2098                          error))
2099         return FALSE;
2100 
2101       g_free (req_value_data);
2102 
2103       if (value_type)
2104         *value_type = G_WIN32_REGISTRY_VALUE_STR;
2105 
2106       if (value_data)
2107         *value_data = value_data_expanded;
2108       else
2109         g_free (value_data_expanded);
2110 
2111       if (value_data_size)
2112         *value_data_size = value_data_expanded_charsize_w * sizeof (gunichar2);
2113 
2114       return TRUE;
2115     }
2116 
2117   if (value_type)
2118     *value_type = value_type_g;
2119 
2120   if (value_data_size)
2121     *value_data_size = req_value_data_size;
2122 
2123   if (value_data)
2124     *value_data = req_value_data;
2125   else
2126     g_free (req_value_data);
2127 
2128   return TRUE;
2129 }
2130 
2131 static VOID NTAPI
key_changed(PVOID closure,PIO_STATUS_BLOCK status_block,ULONG reserved)2132 key_changed (PVOID            closure,
2133              PIO_STATUS_BLOCK status_block,
2134              ULONG            reserved)
2135 {
2136   GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (closure);
2137 
2138   g_free (status_block);
2139   g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_CHANGED);
2140   g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED);
2141   key->priv->update_flags = G_WIN32_REGISTRY_UPDATED_NOTHING;
2142 
2143   if (key->priv->callback)
2144     key->priv->callback (key, key->priv->user_data);
2145 
2146   key->priv->callback = NULL;
2147   key->priv->user_data = NULL;
2148   g_object_unref (key);
2149 }
2150 
2151 /**
2152  * g_win32_registry_key_watch:
2153  * @key: (in) (transfer none): a #GWin32RegistryKey
2154  * @watch_children: (in) %TRUE also watch the children of the @key, %FALSE
2155  *     to watch the key only.
2156  * @watch_flags: (in): specifies the types of changes to watch for.
2157  * @callback: (in) (nullable): a function to invoke when a change occurs.
2158  * @user_data: (in) (nullable): a pointer to pass to @callback on invocation.
2159  * @error: (nullable): a pointer to %NULL #GError, or %NULL
2160  *
2161  * Puts @key under a watch.
2162  *
2163  * When the key changes, an APC will be queued in the current thread. The APC
2164  * will run when the current thread enters alertable state (GLib main loop
2165  * should do that; if you are not using it, see MSDN documentation for W32API
2166  * calls that put thread into alertable state). When it runs, it will
2167  * atomically switch an indicator in the @key. If a callback was specified,
2168  * it is invoked at that point. Subsequent calls to
2169  * g_win32_registry_key_has_changed() will return %TRUE, and the callback (if
2170  * it was specified) will not be invoked anymore.
2171  * Calling g_win32_registry_key_erase_change_indicator() will reset the indicator,
2172  * and g_win32_registry_key_has_changed() will start returning %FALSE.
2173  * To resume the watch, call g_win32_registry_key_watch_for_changes() again.
2174  *
2175  * Calling g_win32_registry_key_watch_for_changes() for a key that is already
2176  * being watched is allowed and affects nothing.
2177  *
2178  * The fact that the key is being watched will be used internally to update
2179  * key path (if it changes).
2180  *
2181  * Returns: %TRUE on success, %FALSE on failure.
2182  *
2183  * Since: 2.46
2184  **/
2185 gboolean
g_win32_registry_key_watch(GWin32RegistryKey * key,gboolean watch_children,GWin32RegistryKeyWatcherFlags watch_flags,GWin32RegistryKeyWatchCallbackFunc callback,gpointer user_data,GError ** error)2186 g_win32_registry_key_watch (GWin32RegistryKey                   *key,
2187                             gboolean                             watch_children,
2188                             GWin32RegistryKeyWatcherFlags        watch_flags,
2189                             GWin32RegistryKeyWatchCallbackFunc   callback,
2190                             gpointer                             user_data,
2191                             GError                             **error)
2192 {
2193   ULONG filter;
2194   gboolean started_to_watch;
2195   NTSTATUS status;
2196   PIO_STATUS_BLOCK status_block;
2197 
2198   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
2199 
2200   filter = ((watch_flags & G_WIN32_REGISTRY_WATCH_NAME)       ? REG_NOTIFY_CHANGE_NAME       : 0) |
2201            ((watch_flags & G_WIN32_REGISTRY_WATCH_ATTRIBUTES) ? REG_NOTIFY_CHANGE_ATTRIBUTES : 0) |
2202            ((watch_flags & G_WIN32_REGISTRY_WATCH_VALUES)     ? REG_NOTIFY_CHANGE_LAST_SET   : 0) |
2203            ((watch_flags & G_WIN32_REGISTRY_WATCH_SECURITY)   ? REG_NOTIFY_CHANGE_SECURITY   : 0);
2204 
2205   if (filter == 0)
2206     {
2207       g_critical ("No supported flags specified in watch_flags (%x)", (guint) watch_flags);
2208       return FALSE;
2209     }
2210 
2211   if (g_once_init_enter (&nt_notify_change_multiple_keys))
2212   {
2213     NtNotifyChangeMultipleKeysFunc func;
2214     HMODULE ntdll = GetModuleHandle ("ntdll.dll");
2215 
2216     if (ntdll != NULL)
2217       func = (NtNotifyChangeMultipleKeysFunc) GetProcAddress (ntdll, "NtNotifyChangeMultipleKeys");
2218     else
2219       func = NULL;
2220 
2221     g_once_init_leave (&nt_notify_change_multiple_keys, func);
2222   }
2223 
2224   if (nt_notify_change_multiple_keys== NULL)
2225     {
2226       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
2227                    "Couldn't get NtNotifyChangeMultipleKeys() from ntdll");
2228       return FALSE;
2229     }
2230 
2231   started_to_watch =
2232       g_atomic_int_compare_and_exchange (&key->priv->watch_indicator,
2233                                          G_WIN32_KEY_UNWATCHED,
2234                                          G_WIN32_KEY_WATCHED);
2235 
2236   if (!started_to_watch)
2237     return TRUE;
2238 
2239   key->priv->callback = callback;
2240   key->priv->user_data = user_data;
2241 
2242   g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNCHANGED);
2243 
2244   /* Keep it alive until APC is called */
2245   g_object_ref (key);
2246 
2247   status_block = g_malloc (sizeof (IO_STATUS_BLOCK));
2248 
2249   status = nt_notify_change_multiple_keys (key->priv->handle,
2250                                            0,
2251                                            NULL,
2252                                            NULL,
2253                                            key_changed,
2254                                            (PVOID) key,
2255                                            status_block,
2256                                            filter,
2257                                            watch_children,
2258                                            NULL,
2259                                            0,
2260                                            TRUE);
2261 
2262   g_assert (status != STATUS_SUCCESS);
2263 
2264   if (status == STATUS_PENDING)
2265     return TRUE;
2266 
2267   g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN);
2268   g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED);
2269   g_object_unref (key);
2270   g_free (status_block);
2271 
2272   return FALSE;
2273 }
2274 
2275 /**
2276  * g_win32_registry_key_erase_change_indicator:
2277  * @key: (in) (transfer none): a #GWin32RegistryKey
2278  *
2279  * Erases change indicator of the @key.
2280  *
2281  * Subsequent calls to g_win32_registry_key_has_changed() will return %FALSE
2282  * until the key is put on watch again by calling
2283  * g_win32_registry_key_watch() again.
2284  *
2285  * Since: 2.46
2286  */
2287 void
g_win32_registry_key_erase_change_indicator(GWin32RegistryKey * key)2288 g_win32_registry_key_erase_change_indicator (GWin32RegistryKey *key)
2289 {
2290   g_return_if_fail (G_IS_WIN32_REGISTRY_KEY (key));
2291 
2292   g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN);
2293 }
2294 
2295 /**
2296  * g_win32_registry_key_has_changed:
2297  * @key: (in) (transfer none): a #GWin32RegistryKey
2298  *
2299  * Check the @key's status indicator.
2300  *
2301  * Returns: %TRUE if the @key was put under watch at some point and has changed
2302  * since then, %FALSE if it either wasn't changed or wasn't watched at all.
2303  *
2304  * Since: 2.46
2305  */
2306 gboolean
g_win32_registry_key_has_changed(GWin32RegistryKey * key)2307 g_win32_registry_key_has_changed (GWin32RegistryKey *key)
2308 {
2309   gint changed;
2310 
2311   g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
2312 
2313   changed = g_atomic_int_get (&key->priv->change_indicator);
2314 
2315   return (changed == G_WIN32_KEY_CHANGED ? TRUE : FALSE);
2316 }
2317 
2318 static void
g_win32_registry_key_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2319 g_win32_registry_key_get_property (GObject    *object,
2320                                    guint       prop_id,
2321                                    GValue     *value,
2322                                    GParamSpec *pspec)
2323 {
2324   GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (object);
2325 
2326   switch (prop_id)
2327     {
2328       case PROP_PATH:
2329         g_value_set_string (value, g_win32_registry_key_get_path (key));
2330         break;
2331 
2332       case PROP_PATH_UTF16:
2333         g_value_set_pointer (value, (gpointer) g_win32_registry_key_get_path_w (key));
2334         break;
2335 
2336       default:
2337         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2338     }
2339 }
2340 
2341 static void
g_win32_registry_key_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2342 g_win32_registry_key_set_property (GObject      *object,
2343                                    guint         prop_id,
2344                                    const GValue *value,
2345                                    GParamSpec   *pspec)
2346 {
2347   GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (object);
2348   GWin32RegistryKeyPrivate *priv = key->priv;
2349   const gchar *path;
2350   gunichar2 *path_w;
2351 
2352   switch (prop_id)
2353     {
2354     case PROP_PATH:
2355       g_assert (priv->absolute_path_w == NULL);
2356       g_assert (priv->absolute_path == NULL);
2357       path = g_value_get_string (value);
2358 
2359       if (path == NULL)
2360         break;
2361 
2362       path_w = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
2363 
2364       if (path_w == NULL)
2365         break;
2366 
2367       g_free (priv->absolute_path_w);
2368       g_free (priv->absolute_path);
2369       priv->absolute_path_w = path_w;
2370       priv->absolute_path = g_value_dup_string (value);
2371       break;
2372 
2373     case PROP_PATH_UTF16:
2374       g_assert (priv->absolute_path_w == NULL);
2375       g_assert (priv->absolute_path == NULL);
2376       path_w = (gunichar2 *) g_value_get_pointer (value);
2377 
2378       if (path_w == NULL)
2379         break;
2380 
2381       priv->absolute_path_w = g_wcsdup (path_w, -1);
2382       break;
2383 
2384     default:
2385       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2386     }
2387 }
2388 
2389 static void
g_win32_registry_key_class_init(GWin32RegistryKeyClass * klass)2390 g_win32_registry_key_class_init (GWin32RegistryKeyClass *klass)
2391 {
2392   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2393 
2394   gobject_class->dispose = g_win32_registry_key_dispose;
2395   gobject_class->set_property = g_win32_registry_key_set_property;
2396   gobject_class->get_property = g_win32_registry_key_get_property;
2397 
2398   /**
2399    * GWin32RegistryKey:path:
2400    *
2401    * A path to the key in the registry, in UTF-8.
2402    *
2403    * Since: 2.46
2404    */
2405   g_object_class_install_property (gobject_class,
2406                                    PROP_PATH,
2407                                    g_param_spec_string ("path",
2408                                                         "Path",
2409                                                         "Path to the key in the registry",
2410                                                         NULL,
2411                                                         G_PARAM_READWRITE |
2412                                                         G_PARAM_CONSTRUCT_ONLY |
2413                                                         G_PARAM_STATIC_STRINGS));
2414 
2415   /**
2416    * GWin32RegistryKey:path-utf16:
2417    *
2418    * A path to the key in the registry, in UTF-16.
2419    *
2420    * Since: 2.46
2421    */
2422   g_object_class_install_property (gobject_class,
2423                                    PROP_PATH_UTF16,
2424                                    g_param_spec_pointer ("path-utf16",
2425                                                         "Path (UTF-16)",
2426                                                         "Path to the key in the registry, in UTF-16",
2427                                                         G_PARAM_READWRITE |
2428                                                         G_PARAM_CONSTRUCT_ONLY |
2429                                                         G_PARAM_STATIC_STRINGS));
2430 }
2431 
2432 static void
g_win32_registry_key_init(GWin32RegistryKey * key)2433 g_win32_registry_key_init (GWin32RegistryKey *key)
2434 {
2435   key->priv = g_win32_registry_key_get_instance_private (key);
2436   key->priv->change_indicator = G_WIN32_KEY_UNKNOWN;
2437 }
2438