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