Blame gio/gwin32registrykey.c

Packit ae235b
/* GIO - GLib Input, Output and Streaming Library
Packit ae235b
 *
Packit ae235b
 * Copyright (C) 2014 Руслан Ижбулатов <lrn1986@gmail.com>
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
#include "ginitable.h"
Packit ae235b
#include "gwin32registrykey.h"
Packit ae235b
#include <gio/gioerror.h>
Packit ae235b
#ifdef _MSC_VER
Packit ae235b
#pragma warning ( disable:4005 )
Packit ae235b
#endif
Packit ae235b
#include <windows.h>
Packit ae235b
#include <ntstatus.h>
Packit ae235b
#include <winternl.h>
Packit ae235b
Packit ae235b
#ifndef _WDMDDK_
Packit ae235b
typedef enum _KEY_INFORMATION_CLASS {
Packit ae235b
  KeyBasicInformation,
Packit ae235b
  KeyNodeInformation,
Packit ae235b
  KeyFullInformation,
Packit ae235b
  KeyNameInformation,
Packit ae235b
  KeyCachedInformation,
Packit ae235b
  KeyFlagsInformation,
Packit ae235b
  KeyVirtualizationInformation,
Packit ae235b
  KeyHandleTagsInformation,
Packit ae235b
  MaxKeyInfoClass
Packit ae235b
} KEY_INFORMATION_CLASS;
Packit ae235b
Packit ae235b
typedef struct _KEY_BASIC_INFORMATION {
Packit ae235b
  LARGE_INTEGER LastWriteTime;
Packit ae235b
  ULONG TitleIndex;
Packit ae235b
  ULONG NameLength;
Packit ae235b
  WCHAR Name[1];
Packit ae235b
} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#if !defined (__OBJECT_ATTRIBUTES_DEFINED) && defined (__MINGW32_)
Packit ae235b
#define __OBJECT_ATTRIBUTES_DEFINED
Packit ae235b
  typedef struct _OBJECT_ATTRIBUTES {
Packit ae235b
    ULONG Length;
Packit ae235b
#ifdef _WIN64
Packit ae235b
    ULONG pad1;
Packit ae235b
#endif
Packit ae235b
    HANDLE RootDirectory;
Packit ae235b
    PUNICODE_STRING ObjectName;
Packit ae235b
    ULONG Attributes;
Packit ae235b
#ifdef _WIN64
Packit ae235b
    ULONG pad2;
Packit ae235b
#endif
Packit ae235b
    PVOID SecurityDescriptor;
Packit ae235b
    PVOID SecurityQualityOfService;
Packit ae235b
  } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifndef HKEY_CURRENT_USER_LOCAL_SETTINGS
Packit ae235b
#define HKEY_CURRENT_USER_LOCAL_SETTINGS ((HKEY) (ULONG_PTR)((LONG)0x80000007))
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#if !defined (__UNICODE_STRING_DEFINED) && defined (__MINGW32_)
Packit ae235b
#define __UNICODE_STRING_DEFINED
Packit ae235b
typedef struct _UNICODE_STRING {
Packit ae235b
  USHORT Length;
Packit ae235b
  USHORT MaximumLength;
Packit ae235b
  PWSTR  Buffer;
Packit ae235b
} UNICODE_STRING, *PUNICODE_STRING;
Packit ae235b
#endif
Packit ae235b
typedef const UNICODE_STRING* PCUNICODE_STRING;
Packit ae235b
Packit ae235b
typedef NTSTATUS
Packit ae235b
(NTAPI * NtQueryKeyFunc)(HANDLE                key_handle,
Packit ae235b
                         KEY_INFORMATION_CLASS key_info_class,
Packit ae235b
                         PVOID                 key_info_buffer,
Packit ae235b
                         ULONG                 key_info_buffer_size,
Packit ae235b
                         PULONG                result_size);
Packit ae235b
Packit ae235b
typedef NTSTATUS
Packit ae235b
(NTAPI * NtNotifyChangeMultipleKeysFunc)(HANDLE             key_handle,
Packit ae235b
                                         ULONG              subkey_count,
Packit ae235b
                                         POBJECT_ATTRIBUTES subkeys,
Packit ae235b
                                         HANDLE             event,
Packit ae235b
                                         PIO_APC_ROUTINE    apc_routine,
Packit ae235b
                                         PVOID              apc_closure,
Packit ae235b
                                         PIO_STATUS_BLOCK   status_block,
Packit ae235b
                                         ULONG              filter,
Packit ae235b
                                         BOOLEAN            watch_tree,
Packit ae235b
                                         PVOID              buffer,
Packit ae235b
                                         ULONG              buffer_size,
Packit ae235b
                                         BOOLEAN            async);
Packit ae235b
Packit ae235b
static NtQueryKeyFunc nt_query_key = NULL;
Packit ae235b
static NtNotifyChangeMultipleKeysFunc nt_notify_change_multiple_keys = NULL;
Packit ae235b
Packit ae235b
#define G_WIN32_KEY_UNWATCHED 0
Packit ae235b
#define G_WIN32_KEY_WATCHED 1
Packit ae235b
#define G_WIN32_KEY_UNCHANGED 0
Packit ae235b
#define G_WIN32_KEY_CHANGED 1
Packit ae235b
#define G_WIN32_KEY_UNKNOWN -1
Packit ae235b
Packit ae235b
enum
Packit ae235b
{
Packit ae235b
  PROP_0,
Packit ae235b
  PROP_PATH,
Packit ae235b
  PROP_PATH_UTF16,
Packit ae235b
  PROP_MAX,
Packit ae235b
};
Packit ae235b
Packit ae235b
typedef enum
Packit ae235b
{
Packit ae235b
  G_WIN32_REGISTRY_UPDATED_NOTHING = 0,
Packit ae235b
  G_WIN32_REGISTRY_UPDATED_PATH = 1,
Packit ae235b
} GWin32RegistryKeyUpdateFlag;
Packit ae235b
Packit ae235b
static gunichar2 *
Packit ae235b
g_wcsdup (const gunichar2 *str,
Packit ae235b
          gssize           str_size)
Packit ae235b
{
Packit ae235b
  if (str_size == -1)
Packit ae235b
    {
Packit ae235b
      str_size = wcslen (str) + 1;
Packit ae235b
      str_size *= sizeof (gunichar2);
Packit ae235b
    }
Packit ae235b
  return g_memdup (str, str_size);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_copy:
Packit ae235b
 * @iter: an iterator
Packit ae235b
 *
Packit ae235b
 * Creates a dynamically-allocated copy of an iterator. Dynamically-allocated
Packit ae235b
 * state of the iterator is duplicated too.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a copy of the @iter,
Packit ae235b
 * free with g_win32_registry_subkey_iter_free ()
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
GWin32RegistrySubkeyIter *
Packit ae235b
g_win32_registry_subkey_iter_copy (const GWin32RegistrySubkeyIter *iter)
Packit ae235b
{
Packit ae235b
  GWin32RegistrySubkeyIter *new_iter;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, NULL);
Packit ae235b
Packit ae235b
  new_iter = g_new0 (GWin32RegistrySubkeyIter, 1);
Packit ae235b
Packit ae235b
  new_iter->key = g_object_ref (iter->key);
Packit ae235b
  new_iter->counter = iter->counter;
Packit ae235b
  new_iter->subkey_count = iter->subkey_count;
Packit ae235b
  new_iter->subkey_name = g_wcsdup (iter->subkey_name, iter->subkey_name_size);
Packit ae235b
  new_iter->subkey_name_size = iter->subkey_name_size;
Packit ae235b
Packit ae235b
  if (iter->subkey_name_u8)
Packit ae235b
    new_iter->subkey_name_u8 = iter->subkey_name_u8;
Packit ae235b
  else
Packit ae235b
    new_iter->subkey_name_u8 = NULL;
Packit ae235b
Packit ae235b
  return new_iter;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_free:
Packit ae235b
 * @iter: a dynamically-allocated iterator
Packit ae235b
 *
Packit ae235b
 * Free an iterator allocated on the heap. For iterators that are allocated
Packit ae235b
 * on the stack use g_win32_registry_subkey_iter_clear () instead.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_win32_registry_subkey_iter_free (GWin32RegistrySubkeyIter *iter)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (iter != NULL);
Packit ae235b
Packit ae235b
  g_object_unref (iter->key);
Packit ae235b
  g_free (iter->subkey_name);
Packit ae235b
  g_free (iter->subkey_name_u8);
Packit ae235b
  g_free (iter);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_assign:
Packit ae235b
 * @iter: a #GWin32RegistrySubkeyIter
Packit ae235b
 * @other: another #GWin32RegistrySubkeyIter
Packit ae235b
 *
Packit ae235b
 * Assigns the value of @other to @iter.  This function
Packit ae235b
 * is not useful in applications, because iterators can be assigned
Packit ae235b
 * with `GWin32RegistrySubkeyIter i = j;`. The
Packit ae235b
 * function is used by language bindings.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_win32_registry_subkey_iter_assign (GWin32RegistrySubkeyIter       *iter,
Packit ae235b
                                     const GWin32RegistrySubkeyIter *other)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (iter != NULL);
Packit ae235b
  g_return_if_fail (other != NULL);
Packit ae235b
Packit ae235b
  *iter = *other;
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
G_DEFINE_BOXED_TYPE (GWin32RegistrySubkeyIter, g_win32_registry_subkey_iter,
Packit ae235b
                     g_win32_registry_subkey_iter_copy,
Packit ae235b
                     g_win32_registry_subkey_iter_free)
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_copy:
Packit ae235b
 * @iter: an iterator
Packit ae235b
 *
Packit ae235b
 * Creates a dynamically-allocated copy of an iterator. Dynamically-allocated
Packit ae235b
 * state of the iterator is duplicated too.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a copy of the @iter,
Packit ae235b
 * free with g_win32_registry_value_iter_free ().
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
GWin32RegistryValueIter *
Packit ae235b
g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
Packit ae235b
{
Packit ae235b
  GWin32RegistryValueIter *new_iter;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, NULL);
Packit ae235b
Packit ae235b
  new_iter = g_new0 (GWin32RegistryValueIter, 1);
Packit ae235b
Packit ae235b
  new_iter->key = g_object_ref (iter->key);
Packit ae235b
  new_iter->counter = iter->counter;
Packit ae235b
  new_iter->value_count = iter->value_count;
Packit ae235b
  new_iter->value_name = g_wcsdup (iter->value_name, iter->value_name_size);
Packit ae235b
  new_iter->value_name_size = iter->value_name_size;
Packit ae235b
Packit ae235b
  if (iter->value_data != NULL)
Packit ae235b
    new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size);
Packit ae235b
Packit ae235b
  new_iter->value_data_size = iter->value_data_size;
Packit ae235b
Packit ae235b
  if (iter->value_name_u8 != NULL)
Packit ae235b
    new_iter->value_name_u8 = g_strdup (iter->value_name_u8);
Packit ae235b
Packit ae235b
  new_iter->value_name_u8_len = iter->value_name_u8_len;
Packit ae235b
Packit ae235b
  if (iter->value_data_u8 != NULL)
Packit ae235b
    new_iter->value_data_u8 = g_strdup (iter->value_data_u8);
Packit ae235b
Packit ae235b
  new_iter->value_data_u8_size = iter->value_data_u8_size;
Packit ae235b
Packit ae235b
  if (iter->value_data_expanded != NULL)
Packit ae235b
    new_iter->value_data_expanded = g_wcsdup ((gunichar2 *) iter->value_data_expanded,
Packit ae235b
                                              iter->value_data_expanded_charsize * sizeof (gunichar2));
Packit ae235b
Packit ae235b
  new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize;
Packit ae235b
Packit ae235b
  if (iter->value_data_expanded_u8 != NULL)
Packit ae235b
    new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8,
Packit ae235b
                                                 iter->value_data_expanded_charsize);
Packit ae235b
Packit ae235b
  new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize;
Packit ae235b
Packit ae235b
  return new_iter;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_free:
Packit ae235b
 * @iter: a dynamically-allocated iterator
Packit ae235b
 *
Packit ae235b
 * Free an iterator allocated on the heap. For iterators that are allocated
Packit ae235b
 * on the stack use g_win32_registry_value_iter_clear () instead.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_win32_registry_value_iter_free (GWin32RegistryValueIter *iter)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (iter != NULL);
Packit ae235b
Packit ae235b
  g_object_unref (iter->key);
Packit ae235b
  g_free (iter->value_name);
Packit ae235b
  g_free (iter->value_data);
Packit ae235b
  g_free (iter->value_data_expanded);
Packit ae235b
  g_free (iter->value_name_u8);
Packit ae235b
  g_free (iter->value_data_u8);
Packit ae235b
  g_free (iter->value_data_expanded_u8);
Packit ae235b
  g_free (iter);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_assign:
Packit ae235b
 * @iter: a #GWin32RegistryValueIter
Packit ae235b
 * @other: another #GWin32RegistryValueIter
Packit ae235b
 *
Packit ae235b
 * Assigns the value of @other to @iter.  This function
Packit ae235b
 * is not useful in applications, because iterators can be assigned
Packit ae235b
 * with `GWin32RegistryValueIter i = j;`. The
Packit ae235b
 * function is used by language bindings.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_win32_registry_value_iter_assign (GWin32RegistryValueIter       *iter,
Packit ae235b
                                    const GWin32RegistryValueIter *other)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (iter != NULL);
Packit ae235b
  g_return_if_fail (other != NULL);
Packit ae235b
Packit ae235b
  *iter = *other;
Packit ae235b
}
Packit ae235b
Packit ae235b
G_DEFINE_BOXED_TYPE (GWin32RegistryValueIter, g_win32_registry_value_iter,
Packit ae235b
                     g_win32_registry_value_iter_copy,
Packit ae235b
                     g_win32_registry_value_iter_free)
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:gwin32registrykey
Packit ae235b
 * @title: GWin32RegistryKey
Packit ae235b
 * @short_description: W32 registry access helper
Packit ae235b
 * @include: gio/win32/gwin32registrykey.h
Packit ae235b
 *
Packit ae235b
 * #GWin32RegistryKey represents a single Windows Registry key.
Packit ae235b
 *
Packit ae235b
 * #GWin32RegistryKey is used by a number of helper functions that read
Packit ae235b
 * Windows Registry. All keys are opened with read-only access, and at
Packit ae235b
 * the moment there is no API for writing into registry keys or creating
Packit ae235b
 * new ones.
Packit ae235b
 *
Packit ae235b
 * #GWin32RegistryKey implements the #GInitable interface, so if it is manually
Packit ae235b
 * constructed by e.g. g_object_new() you must call g_initable_init() and check
Packit ae235b
 * the results before using the object. This is done automatically
Packit ae235b
 * in g_win32_registry_key_new() and g_win32_registry_key_get_child(), so these
Packit ae235b
 * functions can return %NULL.
Packit ae235b
 *
Packit ae235b
 * To increase efficiency, a UTF-16 variant is available for all functions
Packit ae235b
 * that deal with key or value names in the registry. Use these to perform
Packit ae235b
 * deep registry queries or other operations that require querying a name
Packit ae235b
 * of a key or a value and then opening it (or querying its data). The use
Packit ae235b
 * of UTF-16 functions avoids the overhead of converting names to UTF-8 and
Packit ae235b
 * back.
Packit ae235b
 *
Packit ae235b
 * All functions operate in current user's context (it is not possible to
Packit ae235b
 * access registry tree of a different user).
Packit ae235b
 *
Packit ae235b
 * Key paths must use '\\' as a separator, '/' is not supported. Key names
Packit ae235b
 * must not include '\\', because it's used as a separator. Value names
Packit ae235b
 * can include '\\'.
Packit ae235b
 *
Packit ae235b
 * Key and value names are not case sensitive.
Packit ae235b
 *
Packit ae235b
 * Full key name (excluding the pre-defined ancestor's name) can't exceed
Packit ae235b
 * 255 UTF-16 characters, give or take. Value name can't exceed 16383 UTF-16
Packit ae235b
 * characters. Tree depth is limited to 512 levels.
Packit ae235b
 **/
Packit ae235b
Packit ae235b
struct _GWin32RegistryKeyPrivate {
Packit ae235b
  /* Ancestor of this key. May not be the immediate parent, because
Packit ae235b
   * RegOpenKeyEx() allows grand*-children to be opened transitively.
Packit ae235b
   * May be NULL.
Packit ae235b
   */
Packit ae235b
  GWin32RegistryKey *ancestor;
Packit ae235b
Packit ae235b
  /* Handle to the key */
Packit ae235b
  HKEY handle;
Packit ae235b
Packit ae235b
  /* Full absolute path of the key, in UTF-16. Always allocated.
Packit ae235b
   * Can become out of sync if the key is renamed from while we have it
Packit ae235b
   * open, check watch_indicator to see if anything changed.
Packit ae235b
   */
Packit ae235b
  gunichar2 *absolute_path_w;
Packit ae235b
Packit ae235b
  /* Full absolute path of the key, in UTF-8. Allocated when needed by
Packit ae235b
   * converting the UTF-16 value from absolute_path_w. */
Packit ae235b
  gchar *absolute_path;
Packit ae235b
Packit ae235b
  /* TRUE if this object represents one of the pre-defined keys
Packit ae235b
   * (and thus must not be closed).
Packit ae235b
   */
Packit ae235b
  gboolean predefined;
Packit ae235b
Packit ae235b
  /* Set to G_WIN32_KEY_UNWATCHED if the key is not being watched.
Packit ae235b
   * Set to G_WIN32_KEY_WATCHED when the key is put on watch notification.
Packit ae235b
   */
Packit ae235b
  gint watch_indicator;
Packit ae235b
Packit ae235b
  /* Set to G_WIN32_KEY_UNKNOWN while the key is not being watched.
Packit ae235b
   * Set to G_WIN32_KEY_UNCHANGED once the key is put under watch.
Packit ae235b
   * Set to G_WIN32_KEY_CHANGED by the watch notification APC on key change.
Packit ae235b
   */
Packit ae235b
  gint change_indicator;
Packit ae235b
Packit ae235b
  /* Unset after the key is changed, individual bits are set when their
Packit ae235b
   * respective key parameters are updated from the registry.
Packit ae235b
   * This prevents GLib from re-querying things like key name each time
Packit ae235b
   * one is requested by the client while key is in G_WIN32_KEY_CHANGED state.
Packit ae235b
   */
Packit ae235b
  GWin32RegistryKeyUpdateFlag update_flags;
Packit ae235b
Packit ae235b
  GWin32RegistryKeyWatchCallbackFunc callback;
Packit ae235b
Packit ae235b
  gpointer user_data;
Packit ae235b
};
Packit ae235b
Packit ae235b
static void     g_win32_registry_key_initable_iface_init (GInitableIface  *iface);
Packit ae235b
static gboolean g_win32_registry_key_initable_init       (GInitable       *initable,
Packit ae235b
                                                          GCancellable    *cancellable,
Packit ae235b
                                                          GError         **error);
Packit ae235b
Packit ae235b
G_DEFINE_TYPE_WITH_CODE (GWin32RegistryKey, g_win32_registry_key, G_TYPE_OBJECT,
Packit ae235b
                         G_ADD_PRIVATE (GWin32RegistryKey)
Packit ae235b
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
Packit ae235b
                                                g_win32_registry_key_initable_iface_init));
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_win32_registry_key_dispose (GObject *object)
Packit ae235b
{
Packit ae235b
  GWin32RegistryKey *key;
Packit ae235b
  GWin32RegistryKeyPrivate *priv;
Packit ae235b
Packit ae235b
  key = G_WIN32_REGISTRY_KEY (object);
Packit ae235b
  priv = key->priv;
Packit ae235b
Packit ae235b
  g_clear_object (&priv->ancestor);
Packit ae235b
  g_clear_pointer (&priv->absolute_path_w, g_free);
Packit ae235b
  g_clear_pointer (&priv->absolute_path, g_free);
Packit ae235b
Packit ae235b
  if (!priv->predefined && priv->handle != INVALID_HANDLE_VALUE)
Packit ae235b
    {
Packit ae235b
      RegCloseKey (priv->handle);
Packit ae235b
      priv->handle = INVALID_HANDLE_VALUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (g_win32_registry_key_parent_class)->dispose (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_new:
Packit ae235b
 * @path: absolute full name of a key to open (in UTF-8)
Packit ae235b
 * @error: (nullable): a pointer to a %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Creates an object that represents a registry key specified by @path.
Packit ae235b
 * @path must start with one of the following pre-defined names:
Packit ae235b
 * - HKEY_CLASSES_ROOT
Packit ae235b
 * - HKEY_CURRENT_CONFIG
Packit ae235b
 * - HKEY_CURRENT_USER
Packit ae235b
 * - HKEY_CURRENT_USER_LOCAL_SETTINGS
Packit ae235b
 * - HKEY_LOCAL_MACHINE
Packit ae235b
 * - HKEY_PERFORMANCE_DATA
Packit ae235b
 * - HKEY_PERFORMANCE_NLSTEXT
Packit ae235b
 * - HKEY_PERFORMANCE_TEXT
Packit ae235b
 * - HKEY_USERS
Packit ae235b
 * @path must not end with '\\'.
Packit ae235b
 *
Packit ae235b
 * Returns: (nullable) (transfer full): a #GWin32RegistryKey or %NULL if can't
Packit ae235b
 *   be opened. Free with g_object_unref().
Packit ae235b
 */
Packit ae235b
GWin32RegistryKey *
Packit ae235b
g_win32_registry_key_new (const gchar  *path,
Packit ae235b
                          GError      **error)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (path != NULL, NULL);
Packit ae235b
Packit ae235b
  return g_initable_new (G_TYPE_WIN32_REGISTRY_KEY,
Packit ae235b
                         NULL,
Packit ae235b
                         error,
Packit ae235b
                         "path",
Packit ae235b
                         path,
Packit ae235b
                         NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_new_w:
Packit ae235b
 * @path: (in) (transfer none): absolute full name of a key to open (in UTF-16)
Packit ae235b
 * @error: (inout) (optional) (nullable): a pointer to a %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Creates an object that represents a registry key specified by @path.
Packit ae235b
 * @path must start with one of the following pre-defined names:
Packit ae235b
 * - HKEY_CLASSES_ROOT
Packit ae235b
 * - HKEY_CURRENT_CONFIG
Packit ae235b
 * - HKEY_CURRENT_USER
Packit ae235b
 * - HKEY_CURRENT_USER_LOCAL_SETTINGS
Packit ae235b
 * - HKEY_LOCAL_MACHINE
Packit ae235b
 * - HKEY_PERFORMANCE_DATA
Packit ae235b
 * - HKEY_PERFORMANCE_NLSTEXT
Packit ae235b
 * - HKEY_PERFORMANCE_TEXT
Packit ae235b
 * - HKEY_USERS
Packit ae235b
 * @path must not end with L'\\'.
Packit ae235b
 *
Packit ae235b
 * Returns: (nullable) (transfer full): a #GWin32RegistryKey or %NULL if can't
Packit ae235b
 *   be opened. Free with g_object_unref().
Packit ae235b
 */
Packit ae235b
GWin32RegistryKey *
Packit ae235b
g_win32_registry_key_new_w (const gunichar2  *path,
Packit ae235b
                            GError          **error)
Packit ae235b
{
Packit ae235b
  GObject *result;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (path != NULL, NULL);
Packit ae235b
Packit ae235b
  result = g_initable_new (G_TYPE_WIN32_REGISTRY_KEY,
Packit ae235b
                           NULL,
Packit ae235b
                           error,
Packit ae235b
                           "path-utf16",
Packit ae235b
                           g_wcsdup (path, -1),
Packit ae235b
                           NULL);
Packit ae235b
Packit ae235b
  return result ? G_WIN32_REGISTRY_KEY (result) : NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_win32_registry_key_initable_iface_init (GInitableIface *iface)
Packit ae235b
{
Packit ae235b
  iface->init = g_win32_registry_key_initable_init;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_win32_registry_key_initable_init (GInitable     *initable,
Packit ae235b
                                    GCancellable  *cancellable,
Packit ae235b
                                    GError       **error)
Packit ae235b
{
Packit ae235b
  GWin32RegistryKey *key;
Packit ae235b
  GWin32RegistryKeyPrivate *priv;
Packit ae235b
  gunichar2 *path;
Packit ae235b
  gunichar2 *first_chunk_end;
Packit ae235b
  gsize first_chunk_len;
Packit ae235b
  gunichar2 *second_chunk_begin;
Packit ae235b
  gunichar2 *first_chunk;
Packit ae235b
  HKEY ancestor;
Packit ae235b
  HKEY key_handle;
Packit ae235b
  LONG opened;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (initable), FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  key = G_WIN32_REGISTRY_KEY (initable);
Packit ae235b
  priv = key->priv;
Packit ae235b
Packit ae235b
  if (priv->absolute_path_w == NULL)
Packit ae235b
    {
Packit ae235b
      priv->absolute_path_w = g_utf8_to_utf16 (priv->absolute_path,
Packit ae235b
                                               -1,
Packit ae235b
                                               NULL,
Packit ae235b
                                               NULL,
Packit ae235b
                                               error);
Packit ae235b
Packit ae235b
      if (priv->absolute_path_w == NULL)
Packit ae235b
        return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  path = priv->absolute_path_w;
Packit ae235b
Packit ae235b
  first_chunk_end = wcschr (path, L'\\');
Packit ae235b
Packit ae235b
  if (first_chunk_end == NULL)
Packit ae235b
    first_chunk_end = &path[wcslen (path)];
Packit ae235b
Packit ae235b
  first_chunk_len = first_chunk_end - path;
Packit ae235b
  first_chunk = g_wcsdup (path, -1);
Packit ae235b
  first_chunk[first_chunk_len] = L'\0';
Packit ae235b
  if (wcscmp (first_chunk, L"HKEY_CLASSES_ROOT") == 0)
Packit ae235b
    ancestor = HKEY_CLASSES_ROOT;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_LOCAL_MACHINE") == 0)
Packit ae235b
    ancestor = HKEY_LOCAL_MACHINE;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_CURRENT_USER") == 0)
Packit ae235b
    ancestor = HKEY_CURRENT_USER;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_CURRENT_CONFIG") == 0)
Packit ae235b
    ancestor = HKEY_CURRENT_CONFIG;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_CURRENT_USER_LOCAL_SETTINGS") == 0)
Packit ae235b
    ancestor = HKEY_CURRENT_USER_LOCAL_SETTINGS;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_USERS") == 0)
Packit ae235b
    ancestor = HKEY_USERS;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_PERFORMANCE_DATA") == 0)
Packit ae235b
    ancestor = HKEY_PERFORMANCE_DATA;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_PERFORMANCE_NLSTEXT") == 0)
Packit ae235b
    ancestor = HKEY_PERFORMANCE_NLSTEXT;
Packit ae235b
  else if (wcscmp (first_chunk, L"HKEY_PERFORMANCE_TEXT") == 0)
Packit ae235b
    ancestor = HKEY_PERFORMANCE_TEXT;
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_critical ("Root key '%S' is not a pre-defined key", first_chunk);
Packit ae235b
      g_free (first_chunk);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_free (first_chunk);
Packit ae235b
Packit ae235b
  second_chunk_begin = first_chunk_end;
Packit ae235b
Packit ae235b
  while (second_chunk_begin[0] != L'\0' && second_chunk_begin[0] == L'\\')
Packit ae235b
    second_chunk_begin++;
Packit ae235b
Packit ae235b
  if (second_chunk_begin != first_chunk_end && second_chunk_begin[0] == L'\0')
Packit ae235b
    {
Packit ae235b
      g_critical ("Key name '%S' ends with '\\'", path);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  opened = RegOpenKeyExW (ancestor, second_chunk_begin, 0, KEY_READ, &key_handle);
Packit ae235b
Packit ae235b
  if (opened != ERROR_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (opened),
Packit ae235b
                   "Failed to open registry key '%S'", path);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  priv->ancestor = NULL;
Packit ae235b
  priv->handle = key_handle;
Packit ae235b
  priv->predefined = (second_chunk_begin[0] == L'\0');
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_get_child:
Packit ae235b
 * @key: (in) (transfer none): a parent #GWin32RegistryKey
Packit ae235b
 * @subkey: (in) (transfer none): name of a child key to open (in UTF-8), relative to @key
Packit ae235b
 * @error: (inout) (optional) (nullable): a pointer to a %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Opens a @subkey of the @key.
Packit ae235b
 *
Packit ae235b
 * Returns: (nullable): a #GWin32RegistryKey or %NULL if can't be opened. Free
Packit ae235b
 *                      with g_object_unref().
Packit ae235b
 */
Packit ae235b
GWin32RegistryKey *
Packit ae235b
g_win32_registry_key_get_child (GWin32RegistryKey  *key,
Packit ae235b
                                const gchar        *subkey,
Packit ae235b
                                GError            **error)
Packit ae235b
{
Packit ae235b
  gunichar2 *subkey_w;
Packit ae235b
  GWin32RegistryKey *result = NULL;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL);
Packit ae235b
  g_return_val_if_fail (subkey != NULL, NULL);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit ae235b
Packit ae235b
  subkey_w = g_utf8_to_utf16 (subkey, -1, NULL, NULL, error);
Packit ae235b
Packit ae235b
  if (subkey_w != NULL)
Packit ae235b
    {
Packit ae235b
      result = g_win32_registry_key_get_child_w (key, subkey_w, error);
Packit ae235b
      g_free (subkey_w);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return result;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_get_child_w:
Packit ae235b
 * @key: (in) (transfer none): a parent #GWin32RegistryKey
Packit ae235b
 * @subkey: (in) (transfer none): name of a child key to open (in UTF-8), relative to @key
Packit ae235b
 * @error: (inout) (optional) (nullable): a pointer to a %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Opens a @subkey of the @key.
Packit ae235b
 *
Packit ae235b
 * Returns: (nullable): a #GWin32RegistryKey or %NULL if can't be opened. Free
Packit ae235b
 *                      with g_object_unref().
Packit ae235b
 */
Packit ae235b
GWin32RegistryKey *
Packit ae235b
g_win32_registry_key_get_child_w (GWin32RegistryKey  *key,
Packit ae235b
                                  const gunichar2    *subkey,
Packit ae235b
                                  GError            **error)
Packit ae235b
{
Packit ae235b
  HKEY key_handle;
Packit ae235b
  LONG opened;
Packit ae235b
  const gunichar2 *end_of_subkey;
Packit ae235b
  gsize subkey_len;
Packit ae235b
  GWin32RegistryKey *result;
Packit ae235b
  const gunichar2 *key_path;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL);
Packit ae235b
  g_return_val_if_fail (subkey != NULL, NULL);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit ae235b
Packit ae235b
  if (subkey[0] == L'\\')
Packit ae235b
    {
Packit ae235b
      g_critical ("Subkey name '%S' starts with '\\'", subkey);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  subkey_len = wcslen (subkey);
Packit ae235b
  end_of_subkey = &subkey[subkey_len];
Packit ae235b
Packit ae235b
  if (subkey_len == 0)
Packit ae235b
    end_of_subkey = subkey;
Packit ae235b
Packit ae235b
  if (end_of_subkey[0] == L'\\')
Packit ae235b
    {
Packit ae235b
      g_critical ("Subkey name '%S' ends with '\\'", subkey);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  key_path = g_win32_registry_key_get_path_w (key);
Packit ae235b
  opened = RegOpenKeyExW (key->priv->handle, subkey, 0, KEY_READ, &key_handle);
Packit ae235b
Packit ae235b
  if (opened != ERROR_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (opened),
Packit ae235b
                   "Failed to open registry subkey '%S' of key '%S'",
Packit ae235b
                   subkey, key_path);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  result = g_object_new (G_TYPE_WIN32_REGISTRY_KEY, NULL);
Packit ae235b
Packit ae235b
  result->priv->handle = key_handle;
Packit ae235b
  result->priv->absolute_path_w =
Packit ae235b
      g_malloc ((wcslen (key_path) + 2 + subkey_len) * sizeof (gunichar2));
Packit ae235b
  result->priv->absolute_path_w[0] = L'\0';
Packit ae235b
  wcscat (&result->priv->absolute_path_w[0], key_path);
Packit ae235b
  wcscat (&result->priv->absolute_path_w[wcslen (key_path)], L"\\");
Packit ae235b
  wcscat (&result->priv->absolute_path_w[wcslen (key_path) + 1], subkey);
Packit ae235b
  result->priv->predefined = (subkey[0] == L'\0' && key->priv->predefined);
Packit ae235b
Packit ae235b
  if (subkey[0] != L'\0')
Packit ae235b
    result->priv->ancestor = g_object_ref (key);
Packit ae235b
  else
Packit ae235b
    result->priv->ancestor = NULL;
Packit ae235b
Packit ae235b
  result->priv->change_indicator = G_WIN32_KEY_UNKNOWN;
Packit ae235b
Packit ae235b
  return result;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_init:
Packit ae235b
 * @iter: (in) (transfer none): a pointer to a #GWin32RegistrySubkeyIter
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey to iterate over
Packit ae235b
 * @error: (inout) (optional) (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Initialises (without allocating) a #GWin32RegistrySubkeyIter.  @iter may be
Packit ae235b
 * completely uninitialised prior to this call; its old value is
Packit ae235b
 * ignored.
Packit ae235b
 *
Packit ae235b
 * The iterator remains valid for as long as @key exists.
Packit ae235b
 * Clean up its internal buffers with a call to
Packit ae235b
 * g_win32_registry_subkey_iter_clear() when done.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if iterator was initialized successfully, %FALSE on error.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_subkey_iter_init (GWin32RegistrySubkeyIter  *iter,
Packit ae235b
                                   GWin32RegistryKey         *key,
Packit ae235b
                                   GError                   **error)
Packit ae235b
{
Packit ae235b
  LONG status;
Packit ae235b
  DWORD subkey_count;
Packit ae235b
  DWORD max_subkey_len;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  status = RegQueryInfoKeyW (key->priv->handle,
Packit ae235b
                             NULL, NULL, NULL,
Packit ae235b
                             &subkey_count, &max_subkey_len,
Packit ae235b
                             NULL, NULL, NULL, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
  if (status != ERROR_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
Packit ae235b
                   "Failed to query info for registry key '%S'",
Packit ae235b
                   g_win32_registry_key_get_path_w (key));
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  iter->key = g_object_ref (key);
Packit ae235b
  iter->counter = -1;
Packit ae235b
  iter->subkey_count = subkey_count;
Packit ae235b
  iter->subkey_name_size = sizeof (gunichar2) * (max_subkey_len + 1);
Packit ae235b
  iter->subkey_name = g_malloc (iter->subkey_name_size);
Packit ae235b
  iter->subkey_name_u8 = NULL;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_clear:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter
Packit ae235b
 *
Packit ae235b
 * Frees internal buffers of a #GWin32RegistrySubkeyIter.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_win32_registry_subkey_iter_clear (GWin32RegistrySubkeyIter *iter)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (iter != NULL);
Packit ae235b
Packit ae235b
  g_free (iter->subkey_name);
Packit ae235b
  g_free (iter->subkey_name_u8);
Packit ae235b
  g_clear_object (&iter->key);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_n_subkeys:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter
Packit ae235b
 *
Packit ae235b
 * Queries the number of subkeys items in the key that we are
Packit ae235b
 * iterating over.  This is the total number of subkeys -- not the number
Packit ae235b
 * of items remaining.
Packit ae235b
 *
Packit ae235b
 * This information is accurate at the point of iterator initialization,
Packit ae235b
 * and may go out of sync with reality even while subkeys are enumerated.
Packit ae235b
 *
Packit ae235b
 * Returns: the number of subkeys in the key
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gsize
Packit ae235b
g_win32_registry_subkey_iter_n_subkeys (GWin32RegistrySubkeyIter *iter)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (iter != NULL, 0);
Packit ae235b
Packit ae235b
  return iter->subkey_count;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_next:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter
Packit ae235b
 * @skip_errors: (in): %TRUE if iterator should silently ignore errors (such as
Packit ae235b
 *     the actual number of subkeys being less than expected) and
Packit ae235b
 *     proceed forward
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Moves iterator to the next subkey.
Packit ae235b
 * Enumeration errors can be ignored if @skip_errors is %TRUE
Packit ae235b
 *
Packit ae235b
 * Here is an example for iterating with g_win32_registry_subkey_iter_next():
Packit ae235b
 * |[
Packit ae235b
 *   // recursively iterate a key
Packit ae235b
 *   void
Packit ae235b
 *   iterate_key_recursive (GWin32RegistryKey *key)
Packit ae235b
 *   {
Packit ae235b
 *     GWin32RegistrySubkeyIter iter;
Packit ae235b
 *     gchar *name;
Packit ae235b
 *     GWin32RegistryKey *child;
Packit ae235b
 *
Packit ae235b
 *     if (!g_win32_registry_subkey_iter_init (&iter, key, NULL))
Packit ae235b
 *       return;
Packit ae235b
 *
Packit ae235b
 *     while (g_win32_registry_subkey_iter_next (&iter, TRUE, NULL))
Packit ae235b
 *       {
Packit ae235b
 *         if (!g_win32_registry_subkey_iter_get_name (&iter, &name, NULL, NULL))
Packit ae235b
 *           continue;
Packit ae235b
 *
Packit ae235b
 *         g_print ("subkey '%s'\n", name);
Packit ae235b
 *         child = g_win32_registry_key_get_child (key, name, NULL);
Packit ae235b
 *
Packit ae235b
 *         if (child)
Packit ae235b
 *           iterate_key_recursive (child);
Packit ae235b
 *       }
Packit ae235b
 *
Packit ae235b
 *     g_win32_registry_subkey_iter_clear (&iter);
Packit ae235b
 *   }
Packit ae235b
 * ]|
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if next subkey info was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_subkey_iter_next (GWin32RegistrySubkeyIter  *iter,
Packit ae235b
                                   gboolean                   skip_errors,
Packit ae235b
                                   GError                   **error)
Packit ae235b
{
Packit ae235b
  LONG status;
Packit ae235b
  DWORD subkey_len;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->subkey_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_subkey_iter_get_next_w: must not be called again "
Packit ae235b
                  "after FALSE has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      iter->counter += 1;
Packit ae235b
Packit ae235b
      if (iter->counter >= iter->subkey_count)
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      /* Including 0-terminator */
Packit ae235b
      subkey_len = iter->subkey_name_size;
Packit ae235b
      status = RegEnumKeyExW (iter->key->priv->handle,
Packit ae235b
                              iter->counter,
Packit ae235b
                              iter->subkey_name,
Packit ae235b
                              &subkey_len,
Packit ae235b
                              NULL, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
      if (status == ERROR_SUCCESS)
Packit ae235b
        {
Packit ae235b
          iter->subkey_name_len = subkey_len;
Packit ae235b
Packit ae235b
          return TRUE;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      if (!skip_errors)
Packit ae235b
        {
Packit ae235b
          g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
Packit ae235b
                       "Failed to enumerate subkey #%d for key '%S'",
Packit ae235b
                       iter->counter, g_win32_registry_key_get_path_w (iter->key));
Packit ae235b
          iter->subkey_count = 0;
Packit ae235b
Packit ae235b
          return FALSE;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_get_name_w:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter
Packit ae235b
 * @subkey_name: (out callee-allocates) (transfer none): Pointer to a location
Packit ae235b
 *     to store the name of a subkey (in UTF-16).
Packit ae235b
 * @subkey_name_len: (out) (optional) (transfer none): Pointer to a location
Packit ae235b
 *     to store the length of @subkey_name, in gunichar2s, excluding
Packit ae235b
 *     NUL-terminator.
Packit ae235b
 *     %NULL if length is not needed.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Same as g_win32_registry_subkey_iter_get_next(), but outputs UTF-16-encoded
Packit ae235b
 * data, without converting it to UTF-8 first.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the name was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_subkey_iter_get_name_w (GWin32RegistrySubkeyIter  *iter,
Packit ae235b
                                         gunichar2                **subkey_name,
Packit ae235b
                                         gsize                     *subkey_name_len,
Packit ae235b
                                         GError                   **error)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (subkey_name != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->subkey_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_subkey_iter_get_name_w: must not be called "
Packit ae235b
                  "after FALSE has already been returned by "
Packit ae235b
                  "g_win32_registry_subkey_iter_next.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  *subkey_name = iter->subkey_name;
Packit ae235b
Packit ae235b
  if (subkey_name_len)
Packit ae235b
    *subkey_name_len = iter->subkey_name_len;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_subkey_iter_get_name:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistrySubkeyIter
Packit ae235b
 * @subkey_name: (out callee-allocates) (transfer none): Pointer to a location
Packit ae235b
 *     to store the name of a subkey (in UTF-8). Free with g_free().
Packit ae235b
 * @subkey_name_len: (out) (optional): Pointer to a location to store the
Packit ae235b
 *     length of @subkey_name, in gchars, excluding NUL-terminator.
Packit ae235b
 *     %NULL if length is not needed.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Gets the name of the subkey at the @iter potision.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the name was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_subkey_iter_get_name (GWin32RegistrySubkeyIter  *iter,
Packit ae235b
                                       gchar                    **subkey_name,
Packit ae235b
                                       gsize                     *subkey_name_len,
Packit ae235b
                                       GError                   **error)
Packit ae235b
{
Packit ae235b
  glong subkey_name_len_glong;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (subkey_name != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->subkey_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_subkey_iter_get_name_w: must not be called "
Packit ae235b
                  "after FALSE has already been returned by "
Packit ae235b
                  "g_win32_registry_subkey_iter_next.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_clear_pointer (&iter->subkey_name_u8, g_free);
Packit ae235b
  iter->subkey_name_u8 = g_utf16_to_utf8 (iter->subkey_name,
Packit ae235b
                                          iter->subkey_name_len,
Packit ae235b
                                          NULL,
Packit ae235b
                                          &subkey_name_len_glong,
Packit ae235b
                                          error);
Packit ae235b
Packit ae235b
  if (iter->subkey_name_u8 != NULL)
Packit ae235b
    {
Packit ae235b
      *subkey_name_len = subkey_name_len_glong;
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_init:
Packit ae235b
 * @iter: (in) (transfer none): a pointer to a #GWin32RegistryValueIter
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey to iterate over
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Initialises (without allocating) a #GWin32RegistryValueIter.  @iter may be
Packit ae235b
 * completely uninitialised prior to this call; its old value is
Packit ae235b
 * ignored.
Packit ae235b
 *
Packit ae235b
 * The iterator remains valid for as long as @key exists.
Packit ae235b
 * Clean up its internal buffers with a call to
Packit ae235b
 * g_win32_registry_value_iter_clear() when done.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if iterator was initialized successfully, %FALSE on error.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_init (GWin32RegistryValueIter  *iter,
Packit ae235b
                                  GWin32RegistryKey        *key,
Packit ae235b
                                  GError                  **error)
Packit ae235b
{
Packit ae235b
  LONG status;
Packit ae235b
  DWORD value_count;
Packit ae235b
  DWORD max_value_len;
Packit ae235b
  DWORD max_data_len;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  status = RegQueryInfoKeyW (key->priv->handle,
Packit ae235b
                             NULL, NULL, NULL, NULL, NULL, NULL,
Packit ae235b
                             &value_count, &max_value_len,
Packit ae235b
                             &max_data_len, NULL, NULL);
Packit ae235b
Packit ae235b
  if (status != ERROR_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
Packit ae235b
                   "Failed to query info for registry key '%S'",
Packit ae235b
                   g_win32_registry_key_get_path_w (key));
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  iter->key = g_object_ref (key);
Packit ae235b
  iter->counter = -1;
Packit ae235b
  iter->value_count = value_count;
Packit ae235b
  iter->value_name_size = sizeof (gunichar2) * (max_value_len + 1);
Packit ae235b
  iter->value_name = g_malloc (iter->value_name_size);
Packit ae235b
  /* FIXME: max_value_data_len is said to have no size limit in newer W32
Packit ae235b
   * versions (and its size limit in older ones is 1MB!). Consider limiting it
Packit ae235b
   * with a hard-coded value, or by allowing the user to choose a limit.
Packit ae235b
   */
Packit ae235b
  /* Two extra gunichar2s is for cases when a string was stored in the
Packit ae235b
   * Registry without a 0-terminator (for multiline strings - 00-terminator),
Packit ae235b
   * and we need to terminate it ourselves.
Packit ae235b
   */
Packit ae235b
  iter->value_data_size = max_data_len + sizeof (gunichar2) * 2;
Packit ae235b
  iter->value_data = g_malloc (iter->value_data_size);
Packit ae235b
  iter->value_name_u8 = NULL;
Packit ae235b
  iter->value_data_u8 = NULL;
Packit ae235b
  iter->value_data_expanded = NULL;
Packit ae235b
  iter->value_data_expanded_charsize = 0;
Packit ae235b
  iter->value_data_expanded_u8 = NULL;
Packit ae235b
  iter->value_data_expanded_u8_size = 0;
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_clear:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 *
Packit ae235b
 * Frees internal buffers of a #GWin32RegistryValueIter.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_win32_registry_value_iter_clear (GWin32RegistryValueIter *iter)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (iter != NULL);
Packit ae235b
Packit ae235b
  g_free (iter->value_name);
Packit ae235b
  g_free (iter->value_data);
Packit ae235b
  g_free (iter->value_name_u8);
Packit ae235b
  g_free (iter->value_data_u8);
Packit ae235b
  g_free (iter->value_data_expanded);
Packit ae235b
  g_free (iter->value_data_expanded_u8);
Packit ae235b
  g_clear_object (&iter->key);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_n_values:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 *
Packit ae235b
 * Queries the number of values items in the key that we are
Packit ae235b
 * iterating over.  This is the total number of values -- not the number
Packit ae235b
 * of items remaining.
Packit ae235b
 *
Packit ae235b
 * This information is accurate at the point of iterator initialization,
Packit ae235b
 * and may go out of sync with reality even while values are enumerated.
Packit ae235b
 *
Packit ae235b
 * Returns: the number of values in the key
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gsize
Packit ae235b
g_win32_registry_value_iter_n_values (GWin32RegistryValueIter *iter)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (iter != NULL, 0);
Packit ae235b
Packit ae235b
  return iter->value_count;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GWin32RegistryValueType
Packit ae235b
_g_win32_registry_type_w_to_g (DWORD value_type)
Packit ae235b
{
Packit ae235b
  switch (value_type)
Packit ae235b
    {
Packit ae235b
    case REG_BINARY:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_BINARY;
Packit ae235b
    case REG_DWORD:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_UINT32;
Packit ae235b
#if G_BYTE_ORDER == G_BIG_ENDIAN
Packit ae235b
    case REG_DWORD_LITTLE_ENDIAN:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_UINT32LE;
Packit ae235b
#else
Packit ae235b
    case REG_DWORD_BIG_ENDIAN:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_UINT32BE;
Packit ae235b
#endif
Packit ae235b
    case REG_EXPAND_SZ:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_EXPAND_STR;
Packit ae235b
    case REG_LINK:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_LINK;
Packit ae235b
    case REG_MULTI_SZ:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_MULTI_STR;
Packit ae235b
    case REG_NONE:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_NONE;
Packit ae235b
    case REG_QWORD:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_UINT64;
Packit ae235b
#if G_BYTE_ORDER == G_BIG_ENDIAN
Packit ae235b
    case REG_QWORD_LITTLE_ENDIAN:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_UINT64LE;
Packit ae235b
#endif
Packit ae235b
    case REG_SZ:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_STR;
Packit ae235b
    default:
Packit ae235b
      return G_WIN32_REGISTRY_VALUE_NONE;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static gsize
Packit ae235b
ensure_nul_termination (GWin32RegistryValueType  value_type,
Packit ae235b
                        guint8                  *value_data,
Packit ae235b
                        gsize                    value_data_size)
Packit ae235b
{
Packit ae235b
  gsize new_size = value_data_size;
Packit ae235b
Packit ae235b
  if (value_type == G_WIN32_REGISTRY_VALUE_EXPAND_STR ||
Packit ae235b
      value_type == G_WIN32_REGISTRY_VALUE_LINK ||
Packit ae235b
      value_type == G_WIN32_REGISTRY_VALUE_STR)
Packit ae235b
    {
Packit ae235b
      if ((value_data_size < 2) ||
Packit ae235b
          (value_data[value_data_size - 1] != 0) ||
Packit ae235b
          (value_data[value_data_size - 2] != 0))
Packit ae235b
        {
Packit ae235b
          value_data[value_data_size] = 0;
Packit ae235b
          value_data[value_data_size + 1] = 0;
Packit ae235b
          new_size += 2;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  else if (value_type == G_WIN32_REGISTRY_VALUE_MULTI_STR)
Packit ae235b
    {
Packit ae235b
      if ((value_data_size < 4) ||
Packit ae235b
          (value_data[value_data_size - 1] != 0) ||
Packit ae235b
          (value_data[value_data_size - 2] != 0) ||
Packit ae235b
          (value_data[value_data_size - 3] != 0) ||
Packit ae235b
          (value_data[value_data_size - 4] != 0))
Packit ae235b
        {
Packit ae235b
          value_data[value_data_size] = 0;
Packit ae235b
          value_data[value_data_size + 1] = 0;
Packit ae235b
          value_data[value_data_size + 2] = 0;
Packit ae235b
          value_data[value_data_size + 3] = 0;
Packit ae235b
          new_size += 4;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return new_size;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_next:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 * @skip_errors: (in): %TRUE if iterator should silently ignore errors (such as
Packit ae235b
 *     the actual number of values being less than expected) and
Packit ae235b
 *     proceed forward
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Advances iterator to the next value in the key. If no more values remain then
Packit ae235b
 * FALSE is returned.
Packit ae235b
 * Enumeration errors can be ignored if @skip_errors is %TRUE
Packit ae235b
 *
Packit ae235b
 * Here is an example for iterating with g_win32_registry_value_iter_next():
Packit ae235b
 * |[
Packit ae235b
 *   // iterate values of a key
Packit ae235b
 *   void
Packit ae235b
 *   iterate_values_recursive (GWin32RegistryKey *key)
Packit ae235b
 *   {
Packit ae235b
 *     GWin32RegistryValueIter iter;
Packit ae235b
 *     gchar *name;
Packit ae235b
 *     GWin32RegistryValueType val_type;
Packit ae235b
 *     gchar *val_data;
Packit ae235b
 *
Packit ae235b
 *     if (!g_win32_registry_value_iter_init (&iter, key, NULL))
Packit ae235b
 *       return;
Packit ae235b
 *
Packit ae235b
 *     while (g_win32_registry_value_iter_next (&iter, TRUE, NULL))
Packit ae235b
 *       {
Packit ae235b
 *         if ((!g_win32_registry_value_iter_get_value_type (&iter, &value)) ||
Packit ae235b
 *             ((val_type != G_WIN32_REGISTRY_VALUE_STR) &&
Packit ae235b
 *              (val_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR)))
Packit ae235b
 *           continue;
Packit ae235b
 *
Packit ae235b
 *         if (g_win32_registry_value_iter_get_value (&iter, TRUE, &name, NULL,
Packit ae235b
 *                                                    &val_data, NULL, NULL))
Packit ae235b
 *           g_print ("value '%s' = '%s'\n", name, val_data);
Packit ae235b
 *       }
Packit ae235b
 *
Packit ae235b
 *     g_win32_registry_value_iter_clear (&iter);
Packit ae235b
 *   }
Packit ae235b
 * ]|
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if next value info was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_next (GWin32RegistryValueIter  *iter,
Packit ae235b
                                  gboolean                  skip_errors,
Packit ae235b
                                  GError                  **error)
Packit ae235b
{
Packit ae235b
  LONG status;
Packit ae235b
  DWORD value_name_len_w;
Packit ae235b
  DWORD value_data_size_w;
Packit ae235b
  DWORD value_type_w;
Packit ae235b
  GWin32RegistryValueType value_type_g;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->value_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_value_iter_next: must not be called "
Packit ae235b
                  "again after FALSE has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  while (TRUE)
Packit ae235b
    {
Packit ae235b
      iter->counter += 1;
Packit ae235b
Packit ae235b
      if (iter->counter >= iter->value_count)
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      g_clear_pointer (&iter->value_name_u8, g_free);
Packit ae235b
      g_clear_pointer (&iter->value_data_u8, g_free);
Packit ae235b
      g_clear_pointer (&iter->value_data_expanded_u8, g_free);
Packit ae235b
      /* Including 0-terminator */
Packit ae235b
      value_name_len_w = iter->value_name_size / sizeof (gunichar2);
Packit ae235b
      value_data_size_w = iter->value_data_size;
Packit ae235b
      status = RegEnumValueW (iter->key->priv->handle,
Packit ae235b
                              iter->counter,
Packit ae235b
                              iter->value_name,
Packit ae235b
                              &value_name_len_w,
Packit ae235b
                              NULL,
Packit ae235b
                              &value_type_w,
Packit ae235b
                              (LPBYTE) iter->value_data,
Packit ae235b
                              &value_data_size_w);
Packit ae235b
Packit ae235b
      if (status != ERROR_SUCCESS && !skip_errors)
Packit ae235b
        {
Packit ae235b
          g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
Packit ae235b
                       "Failed to enumerate value #%d for key '%S'",
Packit ae235b
                       iter->counter, g_win32_registry_key_get_path_w (iter->key));
Packit ae235b
          iter->value_count = 0;
Packit ae235b
Packit ae235b
          return FALSE;
Packit ae235b
        }
Packit ae235b
      else if (status != ERROR_SUCCESS && skip_errors)
Packit ae235b
        continue;
Packit ae235b
Packit ae235b
      value_type_g = _g_win32_registry_type_w_to_g (value_type_w);
Packit ae235b
      value_data_size_w = ensure_nul_termination (value_type_g,
Packit ae235b
                                                  iter->value_data,
Packit ae235b
                                                  value_data_size_w);
Packit ae235b
      iter->value_type = value_type_g;
Packit ae235b
      iter->value_expanded_type = value_type_g;
Packit ae235b
      iter->value_actual_data_size = value_data_size_w;
Packit ae235b
      iter->value_name_len = value_name_len_w;
Packit ae235b
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_get_value_type:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 * @value_type: (out): Pointer to a location to store the type of
Packit ae235b
 *     the value.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Stores the type of the value currently being iterated over in @value_type.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if value type was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_get_value_type (GWin32RegistryValueIter  *iter,
Packit ae235b
                                            GWin32RegistryValueType  *value_type,
Packit ae235b
                                            GError                  **error)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (value_type != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->value_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_value_iter_get_type: must not be called "
Packit ae235b
                  "again after NULL has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  *value_type = iter->value_type;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_get_name_w:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 * @value_name: (out callee-allocates) (transfer none): Pointer to a location
Packit ae235b
 *     to store the name of a value (in UTF-16).
Packit ae235b
 * @value_name_len: (out) (optional): Pointer to a location to store the length
Packit ae235b
 *     of @value_name, in gunichar2s, excluding NUL-terminator.
Packit ae235b
 *     %NULL if length is not needed.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Stores the name of the value currently being iterated over in @value_name,
Packit ae235b
 * and its length - in @value_name (if not %NULL).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if value name was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_get_name_w (GWin32RegistryValueIter  *iter,
Packit ae235b
                                        gunichar2               **value_name,
Packit ae235b
                                        gsize                    *value_name_len,
Packit ae235b
                                        GError                  **error)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (value_name != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->value_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_value_iter_get_name_w: must not be called "
Packit ae235b
                  "again after NULL has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  *value_name = iter->value_name;
Packit ae235b
Packit ae235b
  if (value_name_len)
Packit ae235b
    *value_name_len = iter->value_name_len;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_get_name:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 * @value_name: (out callee-allocates) (transfer none): Pointer to a location
Packit ae235b
 *     to store the name of a value (in UTF-8).
Packit ae235b
 * @value_name_len: (out) (optional): Pointer to a location to store the length
Packit ae235b
 *     of @value_name, in gchars, excluding NUL-terminator.
Packit ae235b
 *     %NULL if length is not needed.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Stores the name of the value currently being iterated over in @value_name,
Packit ae235b
 * and its length - in @value_name_len (if not %NULL).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if value name was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_get_name (GWin32RegistryValueIter  *iter,
Packit ae235b
                                      gchar                   **value_name,
Packit ae235b
                                      gsize                    *value_name_len,
Packit ae235b
                                      GError                  **error)
Packit ae235b
{
Packit ae235b
  glong value_name_len_glong;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (value_name != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->value_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_value_iter_get_name: must not be called "
Packit ae235b
                  "again after NULL has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (iter->value_name_u8 == NULL)
Packit ae235b
    {
Packit ae235b
      iter->value_name_u8 = g_utf16_to_utf8 (iter->value_name, iter->value_name_len, NULL,
Packit ae235b
                                             &value_name_len_glong, error);
Packit ae235b
Packit ae235b
      if (iter->value_name_u8 == NULL)
Packit ae235b
        return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  *value_name = iter->value_name_u8;
Packit ae235b
Packit ae235b
  if (value_name_len)
Packit ae235b
    *value_name_len = iter->value_name_u8_len;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
expand_value (gunichar2  *value,
Packit ae235b
              const gunichar2  *value_name,
Packit ae235b
              gpointer   *expanded_value,
Packit ae235b
              gsize      *expanded_charsize,
Packit ae235b
              GError    **error)
Packit ae235b
{
Packit ae235b
  DWORD value_data_expanded_charsize_w;
Packit ae235b
Packit ae235b
  value_data_expanded_charsize_w =
Packit ae235b
      ExpandEnvironmentStringsW (value,
Packit ae235b
                                 (gunichar2 *) *expanded_value,
Packit ae235b
                                 *expanded_charsize);
Packit ae235b
Packit ae235b
  if (value_data_expanded_charsize_w > *expanded_charsize)
Packit ae235b
    {
Packit ae235b
      *expanded_value = g_realloc (*expanded_value,
Packit ae235b
                                   value_data_expanded_charsize_w * sizeof (gunichar2));
Packit ae235b
      *expanded_charsize = value_data_expanded_charsize_w;
Packit ae235b
      value_data_expanded_charsize_w =
Packit ae235b
          ExpandEnvironmentStringsW (value,
Packit ae235b
                                     (gunichar2 *) *expanded_value,
Packit ae235b
                                     *expanded_charsize);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (value_data_expanded_charsize_w == 0)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR,
Packit ae235b
                   g_io_error_from_win32_error (GetLastError ()),
Packit ae235b
                   "Failed to expand data '%S' of value %S",
Packit ae235b
                   value, value_name);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_get_data_w:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 * @auto_expand: (in): %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR to
Packit ae235b
 *     G_WIN32_REGISTRY_VALUE_STR
Packit ae235b
 * @value_data: (out callee-allocates) (optional) (transfer none): Pointer to a
Packit ae235b
 *     location to store the data of the value (in UTF-16, if it's a string)
Packit ae235b
 * @value_data_size: (out) (optional): Pointer to a location to store the size
Packit ae235b
 *     of @value_data, in bytes (including any NUL-terminators, if it's a string).
Packit ae235b
 *     %NULL if length is not needed.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Stores the data of the value currently being iterated over in @value_data,
Packit ae235b
 * and its length - in @value_data_len (if not %NULL).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if value data was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_get_data_w (GWin32RegistryValueIter  *iter,
Packit ae235b
                                        gboolean                  auto_expand,
Packit ae235b
                                        gpointer                 *value_data,
Packit ae235b
                                        gsize                    *value_data_size,
Packit ae235b
                                        GError                  **error)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (value_data != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->value_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_value_iter_get_data_w: must not be called "
Packit ae235b
                  "again after FALSE has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!auto_expand || (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR))
Packit ae235b
    {
Packit ae235b
      *value_data = iter->value_data;
Packit ae235b
Packit ae235b
      if (value_data_size)
Packit ae235b
        *value_data_size = iter->value_actual_data_size;
Packit ae235b
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (iter->value_type == iter->value_expanded_type)
Packit ae235b
    {
Packit ae235b
      if (!expand_value ((gunichar2 *) iter->value_data,
Packit ae235b
                         iter->value_name,
Packit ae235b
                         (gpointer *) &iter->value_data_expanded,
Packit ae235b
                         &iter->value_data_expanded_charsize,
Packit ae235b
                         error))
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      iter->value_expanded_type = G_WIN32_REGISTRY_VALUE_STR;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  *value_data = iter->value_data_expanded;
Packit ae235b
Packit ae235b
  if (value_data_size)
Packit ae235b
    *value_data_size = iter->value_data_expanded_charsize * sizeof (gunichar2);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_value_iter_get_data:
Packit ae235b
 * @iter: (in) (transfer none): a #GWin32RegistryValueIter
Packit ae235b
 * @auto_expand: (in): %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR to
Packit ae235b
 *     G_WIN32_REGISTRY_VALUE_STR
Packit ae235b
 * @value_data: (out callee-allocates) (optional) (transfer none): Pointer to a
Packit ae235b
 *     location to store the data of the value (in UTF-8, if it's a string)
Packit ae235b
 * @value_data_size: (out) (optional): Pointer to a location to store the length
Packit ae235b
 *     of @value_data, in bytes (including any NUL-terminators, if it's a string).
Packit ae235b
 *     %NULL if length is not needed
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Stores the data of the value currently being iterated over in @value_data,
Packit ae235b
 * and its length - in @value_data_len (if not %NULL).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if value data was retrieved, %FALSE otherwise.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_value_iter_get_data (GWin32RegistryValueIter  *iter,
Packit ae235b
                                      gboolean                  auto_expand,
Packit ae235b
                                      gpointer                 *value_data,
Packit ae235b
                                      gsize                    *value_data_size,
Packit ae235b
                                      GError                  **error)
Packit ae235b
{
Packit ae235b
  gsize value_data_len_gsize;
Packit ae235b
  gpointer tmp;
Packit ae235b
  gsize tmp_size;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (iter != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (value_data != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  if G_UNLIKELY (iter->counter >= iter->value_count)
Packit ae235b
    {
Packit ae235b
      g_critical ("g_win32_registry_value_iter_get_data: must not be called "
Packit ae235b
                  "again after FALSE has already been returned.");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR &&
Packit ae235b
      iter->value_type != G_WIN32_REGISTRY_VALUE_LINK &&
Packit ae235b
      iter->value_type != G_WIN32_REGISTRY_VALUE_STR &&
Packit ae235b
      iter->value_type != G_WIN32_REGISTRY_VALUE_MULTI_STR)
Packit ae235b
    {
Packit ae235b
      *value_data = iter->value_data;
Packit ae235b
Packit ae235b
      if (value_data_size != NULL)
Packit ae235b
        *value_data_size = iter->value_actual_data_size;
Packit ae235b
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (!auto_expand || (iter->value_type != G_WIN32_REGISTRY_VALUE_EXPAND_STR))
Packit ae235b
    {
Packit ae235b
      if (iter->value_data_u8 == NULL)
Packit ae235b
        {
Packit ae235b
          iter->value_data_u8 = g_convert ((const gchar *) iter->value_data,
Packit ae235b
                                           iter->value_actual_data_size - sizeof (gunichar2) /* excl. 0 */,
Packit ae235b
                                           "UTF8", "UTF16", NULL,
Packit ae235b
                                           &value_data_len_gsize,
Packit ae235b
                                           error);
Packit ae235b
Packit ae235b
          if (iter->value_data_u8 == NULL)
Packit ae235b
            return FALSE;
Packit ae235b
Packit ae235b
          iter->value_data_u8_size = value_data_len_gsize + 1; /* incl. 0 */
Packit ae235b
        }
Packit ae235b
Packit ae235b
      *value_data = iter->value_data_u8;
Packit ae235b
Packit ae235b
      if (value_data_size != NULL)
Packit ae235b
        *value_data_size = iter->value_data_u8_size;
Packit ae235b
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (iter->value_data_expanded_u8 == NULL)
Packit ae235b
    {
Packit ae235b
      if (!g_win32_registry_value_iter_get_data_w (iter,
Packit ae235b
                                                   TRUE,
Packit ae235b
                                                   &tmp,
Packit ae235b
                                                   &tmp_size,
Packit ae235b
                                                   error))
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      iter->value_data_expanded_u8 = g_convert ((const gchar *) iter->value_data_expanded,
Packit ae235b
                                                iter->value_data_expanded_charsize * sizeof (gunichar2) - sizeof (gunichar2) /* excl. 0 */,
Packit ae235b
                                                "UTF8", "UTF16", NULL,
Packit ae235b
                                                &value_data_len_gsize,
Packit ae235b
                                                error);
Packit ae235b
Packit ae235b
      if (iter->value_data_expanded_u8 == NULL)
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      iter->value_data_u8_size = value_data_len_gsize + 1; /* incl. 0 */
Packit ae235b
    }
Packit ae235b
Packit ae235b
  *value_data = iter->value_data_expanded_u8;
Packit ae235b
Packit ae235b
  if (value_data_size != NULL)
Packit ae235b
    *value_data_size = iter->value_data_expanded_u8_size;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
_g_win32_registry_key_reread_kernel (GWin32RegistryKey        *key,
Packit ae235b
                                     GWin32RegistryKeyPrivate *buf)
Packit ae235b
{
Packit ae235b
  NTSTATUS status;
Packit ae235b
  KEY_BASIC_INFORMATION *basic_info;
Packit ae235b
  ULONG basic_info_size;
Packit ae235b
  ULONG datasize;
Packit ae235b
Packit ae235b
  basic_info_size = 256 * sizeof (gunichar2) + sizeof (KEY_BASIC_INFORMATION);
Packit ae235b
  basic_info = g_malloc (basic_info_size + sizeof (gunichar2));
Packit ae235b
  status = nt_query_key (key->priv->handle,
Packit ae235b
                         KeyBasicInformation,
Packit ae235b
                         basic_info,
Packit ae235b
                         basic_info_size,
Packit ae235b
                         &datasize);
Packit ae235b
Packit ae235b
  if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)
Packit ae235b
    {
Packit ae235b
      g_free (basic_info);
Packit ae235b
      basic_info_size = datasize;
Packit ae235b
       /* +1 for 0-terminator */
Packit ae235b
      basic_info = g_malloc (basic_info_size + sizeof (gunichar2));
Packit ae235b
      status = nt_query_key (key->priv->handle,
Packit ae235b
                             KeyBasicInformation,
Packit ae235b
                             basic_info,
Packit ae235b
                             basic_info_size,
Packit ae235b
                             &datasize);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (status != STATUS_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_free (basic_info);
Packit ae235b
      return;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Ensure 0-termination */
Packit ae235b
  ((char *) basic_info)[datasize] = 0;
Packit ae235b
  ((char *) basic_info)[datasize + 1] = 0;
Packit ae235b
Packit ae235b
  buf->absolute_path_w = g_wcsdup (&basic_info->Name[0],
Packit ae235b
                                   basic_info->NameLength + sizeof (gunichar2));
Packit ae235b
  g_free (basic_info);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
_g_win32_registry_key_reread_user (GWin32RegistryKey        *key,
Packit ae235b
                                   GWin32RegistryKeyPrivate *buf)
Packit ae235b
{
Packit ae235b
  /* Use RegQueryInfoKey(). It's just like NtQueryKey(), but can't query
Packit ae235b
   * key name.
Packit ae235b
   * Since right now we only need the name, this function is a noop.
Packit ae235b
   */
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
_g_win32_registry_key_reread (GWin32RegistryKey        *key,
Packit ae235b
                              GWin32RegistryKeyPrivate *buf)
Packit ae235b
{
Packit ae235b
  if (g_once_init_enter (&nt_query_key))
Packit ae235b
    {
Packit ae235b
      NtQueryKeyFunc func;
Packit ae235b
      HMODULE ntdll = GetModuleHandleW (L"ntdll.dll");
Packit ae235b
Packit ae235b
      if (ntdll != NULL)
Packit ae235b
        func = (NtQueryKeyFunc) GetProcAddress (ntdll, "NtQueryKey");
Packit ae235b
      else
Packit ae235b
        func = NULL;
Packit ae235b
Packit ae235b
      g_once_init_leave (&nt_query_key, func);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Assume that predefined keys never get renamed. Also, their handles probably
Packit ae235b
   * won't be accepted by NtQueryKey(), i suspect.
Packit ae235b
   */
Packit ae235b
  if (nt_query_key != NULL && !key->priv->predefined)
Packit ae235b
    _g_win32_registry_key_reread_kernel (key, buf);
Packit ae235b
  else
Packit ae235b
    _g_win32_registry_key_reread_user (key, buf);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
_g_win32_registry_key_update_path (GWin32RegistryKey *key)
Packit ae235b
{
Packit ae235b
  GWin32RegistryKeyPrivate tmp;
Packit ae235b
  gboolean changed;
Packit ae235b
  gint change_indicator;
Packit ae235b
Packit ae235b
  change_indicator = g_atomic_int_get (&key->priv->change_indicator);
Packit ae235b
Packit ae235b
  if (change_indicator == G_WIN32_KEY_UNCHANGED)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  tmp.absolute_path_w = NULL;
Packit ae235b
  _g_win32_registry_key_reread (key, &tmp);
Packit ae235b
  changed = FALSE;
Packit ae235b
Packit ae235b
  if (wcscmp (key->priv->absolute_path_w, tmp.absolute_path_w) == 0)
Packit ae235b
    g_free (tmp.absolute_path_w);
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_free (key->priv->absolute_path_w);
Packit ae235b
      key->priv->absolute_path_w = tmp.absolute_path_w;
Packit ae235b
      changed = TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return changed;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_get_path:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 *
Packit ae235b
 * Get full path to the key
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer none): a full path to the key (in UTF-8),
Packit ae235b
 *     or %NULL if it can't be converted to UTF-8.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
const gchar *
Packit ae235b
g_win32_registry_key_get_path (GWin32RegistryKey *key)
Packit ae235b
{
Packit ae235b
  gint change_indicator;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL);
Packit ae235b
Packit ae235b
  change_indicator = g_atomic_int_get (&key->priv->change_indicator);
Packit ae235b
Packit ae235b
  if (change_indicator == G_WIN32_KEY_CHANGED &&
Packit ae235b
      !(key->priv->update_flags & G_WIN32_REGISTRY_UPDATED_PATH))
Packit ae235b
    {
Packit ae235b
      _g_win32_registry_key_update_path (key);
Packit ae235b
      key->priv->update_flags |= G_WIN32_REGISTRY_UPDATED_PATH;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (key->priv->absolute_path == NULL)
Packit ae235b
    {
Packit ae235b
      g_free (key->priv->absolute_path);
Packit ae235b
      key->priv->absolute_path =
Packit ae235b
          g_utf16_to_utf8 (key->priv->absolute_path_w, -1,
Packit ae235b
                           NULL, NULL, NULL);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return key->priv->absolute_path;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_get_path_w:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 *
Packit ae235b
 * Get full path to the key
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer none): a full path to the key (in UTF-16)
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
const gunichar2 *
Packit ae235b
g_win32_registry_key_get_path_w (GWin32RegistryKey *key)
Packit ae235b
{
Packit ae235b
  gint change_indicator;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), NULL);
Packit ae235b
Packit ae235b
  change_indicator = g_atomic_int_get (&key->priv->change_indicator);
Packit ae235b
Packit ae235b
  if (change_indicator == G_WIN32_KEY_CHANGED)
Packit ae235b
    _g_win32_registry_key_update_path (key);
Packit ae235b
Packit ae235b
  return key->priv->absolute_path_w;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_get_value:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR
Packit ae235b
 *     to G_WIN32_REGISTRY_VALUE_STR.
Packit ae235b
 * @value_name: (in) (transfer none): name of the value to get (in UTF-8).
Packit ae235b
 *   Empty string means the '(Default)' value.
Packit ae235b
 * @value_type: (out) (optional): type of the value retrieved.
Packit ae235b
 * @value_data: (out callee-allocates) (optional): contents of the value.
Packit ae235b
 * @value_data_size: (out) (optional): size of the buffer pointed
Packit ae235b
 *   by @value_data.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Get data from a value of a key. String data is guaranteed to be
Packit ae235b
 * appropriately terminated and will be in UTF-8.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE on success, %FALSE on failure.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_key_get_value (GWin32RegistryKey        *key,
Packit ae235b
                                gboolean                  auto_expand,
Packit ae235b
                                const gchar              *value_name,
Packit ae235b
                                GWin32RegistryValueType  *value_type,
Packit ae235b
                                gpointer                 *value_data,
Packit ae235b
                                gsize                    *value_data_size,
Packit ae235b
                                GError                  **error)
Packit ae235b
{
Packit ae235b
  GWin32RegistryValueType value_type_g;
Packit ae235b
  gpointer value_data_w;
Packit ae235b
  gsize value_data_w_size;
Packit ae235b
  gunichar2 *value_name_w;
Packit ae235b
  gchar *value_data_u8;
Packit ae235b
  gsize value_data_u8_len;
Packit ae235b
  gboolean result;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
Packit ae235b
  g_return_val_if_fail (value_name != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  /* No sense calling this function with all of these set to NULL */
Packit ae235b
  g_return_val_if_fail (value_type != NULL ||
Packit ae235b
                        value_data != NULL ||
Packit ae235b
                        value_data_size != NULL, FALSE);
Packit ae235b
Packit ae235b
  value_name_w = g_utf8_to_utf16 (value_name, -1, NULL, NULL, error);
Packit ae235b
Packit ae235b
  if (value_name_w == NULL)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  result = g_win32_registry_key_get_value_w (key,
Packit ae235b
                                             auto_expand,
Packit ae235b
                                             value_name_w,
Packit ae235b
                                             &value_type_g,
Packit ae235b
                                             &value_data_w,
Packit ae235b
                                             &value_data_w_size,
Packit ae235b
                                             error);
Packit ae235b
Packit ae235b
  g_free (value_name_w);
Packit ae235b
Packit ae235b
  if (!result)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  if (value_type_g == G_WIN32_REGISTRY_VALUE_EXPAND_STR ||
Packit ae235b
      value_type_g == G_WIN32_REGISTRY_VALUE_LINK ||
Packit ae235b
      value_type_g == G_WIN32_REGISTRY_VALUE_STR ||
Packit ae235b
      value_type_g == G_WIN32_REGISTRY_VALUE_MULTI_STR)
Packit ae235b
    {
Packit ae235b
      value_data_u8 = g_convert ((const gchar *) value_data_w,
Packit ae235b
                                 value_data_w_size - sizeof (gunichar2) /* excl. 0 */,
Packit ae235b
                                 "UTF8",
Packit ae235b
                                 "UTF16",
Packit ae235b
                                 NULL,
Packit ae235b
                                 &value_data_u8_len,
Packit ae235b
                                 error);
Packit ae235b
      g_free (value_data_w);
Packit ae235b
Packit ae235b
      if (value_data_u8 == NULL)
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      if (value_data)
Packit ae235b
        *value_data = value_data_u8;
Packit ae235b
      else
Packit ae235b
        g_free (value_data_u8);
Packit ae235b
Packit ae235b
      if (value_data_size)
Packit ae235b
        *value_data_size = value_data_u8_len + 1;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      if (value_data)
Packit ae235b
        *value_data = value_data_w;
Packit ae235b
      else
Packit ae235b
        g_free (value_data_w);
Packit ae235b
Packit ae235b
      if (value_data_size)
Packit ae235b
        *value_data_size = value_data_w_size;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (value_type)
Packit ae235b
    *value_type = value_type_g;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_get_value_w:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 * @auto_expand: (in) %TRUE to automatically expand G_WIN32_REGISTRY_VALUE_EXPAND_STR
Packit ae235b
 *     to G_WIN32_REGISTRY_VALUE_STR.
Packit ae235b
 * @value_name: (in) (transfer none): name of the value to get (in UTF-16).
Packit ae235b
 *   Empty string means the '(Default)' value.
Packit ae235b
 * @value_type: (out) (optional): type of the value retrieved.
Packit ae235b
 * @value_data: (out callee-allocates) (optional): contents of the value.
Packit ae235b
 * @value_data_size: (out) (optional): size of the buffer pointed
Packit ae235b
 *   by @value_data.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Get data from a value of a key.
Packit ae235b
 *
Packit ae235b
 * Get data from a value of a key. String data is guaranteed to be
Packit ae235b
 * appropriately terminated and will be in UTF-16.
Packit ae235b
 *
Packit ae235b
 * When calling with value_data == NULL (to get data size without getting
Packit ae235b
 * the data itself) remember that returned size corresponds to possibly
Packit ae235b
 * unterminated string data (if value is some kind of string), because
Packit ae235b
 * termination cannot be checked and fixed unless the data is retreived
Packit ae235b
 * too.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE on success, %FALSE on failure.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_key_get_value_w (GWin32RegistryKey        *key,
Packit ae235b
                                  gboolean                  auto_expand,
Packit ae235b
                                  const gunichar2          *value_name,
Packit ae235b
                                  GWin32RegistryValueType  *value_type,
Packit ae235b
                                  gpointer                 *value_data,
Packit ae235b
                                  gsize                    *value_data_size,
Packit ae235b
                                  GError                  **error)
Packit ae235b
{
Packit ae235b
  LONG status;
Packit ae235b
  DWORD value_type_w;
Packit ae235b
  DWORD value_type_w2;
Packit ae235b
  char *req_value_data;
Packit ae235b
  GWin32RegistryValueType value_type_g;
Packit ae235b
  GWin32RegistryValueType value_type_g2;
Packit ae235b
  DWORD req_value_data_size;
Packit ae235b
  DWORD req_value_data_size2;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
Packit ae235b
  g_return_val_if_fail (value_name != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit ae235b
Packit ae235b
  /* No sense calling this functions with all of these set to NULL */
Packit ae235b
  g_return_val_if_fail (value_type != NULL ||
Packit ae235b
                        value_data != NULL ||
Packit ae235b
                        value_data_size != NULL, FALSE);
Packit ae235b
Packit ae235b
  req_value_data_size = 0;
Packit ae235b
  status = RegQueryValueExW (key->priv->handle,
Packit ae235b
                             value_name,
Packit ae235b
                             NULL,
Packit ae235b
                             &value_type_w,
Packit ae235b
                             NULL,
Packit ae235b
                             &req_value_data_size);
Packit ae235b
Packit ae235b
  if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
Packit ae235b
                   "Failed to query value '%S' for key '%S'",
Packit ae235b
                   value_name, g_win32_registry_key_get_path_w (key));
Packit ae235b
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  value_type_g = _g_win32_registry_type_w_to_g (value_type_w);
Packit ae235b
Packit ae235b
  if (value_data == NULL &&
Packit ae235b
      (!auto_expand || value_type_g != G_WIN32_REGISTRY_VALUE_EXPAND_STR))
Packit ae235b
    {
Packit ae235b
      if (value_type)
Packit ae235b
        *value_type = value_type_g;
Packit ae235b
Packit ae235b
      if (value_data_size)
Packit ae235b
        *value_data_size = req_value_data_size;
Packit ae235b
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  req_value_data = g_malloc (req_value_data_size + sizeof (gunichar2) * 2);
Packit ae235b
  req_value_data_size2 = req_value_data_size;
Packit ae235b
  status = RegQueryValueExW (key->priv->handle,
Packit ae235b
                             value_name,
Packit ae235b
                             NULL,
Packit ae235b
                             &value_type_w2,
Packit ae235b
                             (gpointer) req_value_data,
Packit ae235b
                             &req_value_data_size2);
Packit ae235b
Packit ae235b
  if (status != ERROR_SUCCESS)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, g_io_error_from_win32_error (status),
Packit ae235b
                   "Failed to query value '%S' of size %lu for key '%S'",
Packit ae235b
                   value_name,
Packit ae235b
                   req_value_data_size,
Packit ae235b
                   g_win32_registry_key_get_path_w (key));
Packit ae235b
      g_free (req_value_data);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  value_type_g2 = _g_win32_registry_type_w_to_g (value_type_w2);
Packit ae235b
Packit ae235b
  if (value_type_w != value_type_w2)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
Packit ae235b
                   "Type of value '%S' of key '%S' changed from %u to %u"
Packit ae235b
                   " between calls",
Packit ae235b
                   value_name,
Packit ae235b
                   g_win32_registry_key_get_path_w (key),
Packit ae235b
                   value_type_g, value_type_g2);
Packit ae235b
      g_free (req_value_data);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  req_value_data_size = ensure_nul_termination (value_type_g,
Packit ae235b
                                                (guint8 *) req_value_data,
Packit ae235b
                                                req_value_data_size2);
Packit ae235b
Packit ae235b
  if (value_type_g == G_WIN32_REGISTRY_VALUE_EXPAND_STR && auto_expand)
Packit ae235b
    {
Packit ae235b
      gsize value_data_expanded_charsize_w = 0;
Packit ae235b
      gunichar2 *value_data_expanded = NULL;
Packit ae235b
Packit ae235b
      if (!expand_value ((gunichar2 *) req_value_data,
Packit ae235b
                         value_name,
Packit ae235b
                         (gpointer *) &value_data_expanded,
Packit ae235b
                         &value_data_expanded_charsize_w,
Packit ae235b
                         error))
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      g_free (req_value_data);
Packit ae235b
Packit ae235b
      if (value_type)
Packit ae235b
        *value_type = G_WIN32_REGISTRY_VALUE_STR;
Packit ae235b
Packit ae235b
      if (value_data)
Packit ae235b
        *value_data = value_data_expanded;
Packit ae235b
      else
Packit ae235b
        g_free (value_data_expanded);
Packit ae235b
Packit ae235b
      if (value_data_size)
Packit ae235b
        *value_data_size = value_data_expanded_charsize_w * sizeof (gunichar2);
Packit ae235b
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (value_type)
Packit ae235b
    *value_type = value_type_g;
Packit ae235b
Packit ae235b
  if (value_data_size)
Packit ae235b
    *value_data_size = req_value_data_size;
Packit ae235b
Packit ae235b
  if (value_data)
Packit ae235b
    *value_data = req_value_data;
Packit ae235b
  else
Packit ae235b
    g_free (req_value_data);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static VOID NTAPI
Packit ae235b
key_changed (PVOID            closure,
Packit ae235b
             PIO_STATUS_BLOCK status_block,
Packit ae235b
             ULONG            reserved)
Packit ae235b
{
Packit ae235b
  GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (closure);
Packit ae235b
Packit ae235b
  g_free (status_block);
Packit ae235b
  g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_CHANGED);
Packit ae235b
  g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED);
Packit ae235b
  key->priv->update_flags = G_WIN32_REGISTRY_UPDATED_NOTHING;
Packit ae235b
Packit ae235b
  if (key->priv->callback)
Packit ae235b
    key->priv->callback (key, key->priv->user_data);
Packit ae235b
Packit ae235b
  key->priv->callback = NULL;
Packit ae235b
  key->priv->user_data = NULL;
Packit ae235b
  g_object_unref (key);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_watch:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 * @watch_children: (in) %TRUE also watch the children of the @key, %FALSE
Packit ae235b
 *     to watch the key only.
Packit ae235b
 * @watch_flags: (in): specifies the types of changes to watch for.
Packit ae235b
 * @callback: (in) (nullable): a function to invoke when a change occurs.
Packit ae235b
 * @user_data: (in) (nullable): a pointer to pass to @callback on invocation.
Packit ae235b
 * @error: (nullable): a pointer to %NULL #GError, or %NULL
Packit ae235b
 *
Packit ae235b
 * Puts @key under a watch.
Packit ae235b
 *
Packit ae235b
 * When the key changes, an APC will be queued in the current thread. The APC
Packit ae235b
 * will run when the current thread enters alertable state (GLib main loop
Packit ae235b
 * should do that; if you are not using it, see MSDN documentation for W32API
Packit ae235b
 * calls that put thread into alertable state). When it runs, it will
Packit ae235b
 * atomically switch an indicator in the @key. If a callback was specified,
Packit ae235b
 * it is invoked at that point. Subsequent calls to
Packit ae235b
 * g_win32_registry_key_has_changed() will return %TRUE, and the callback (if
Packit ae235b
 * it was specified) will not be invoked anymore.
Packit ae235b
 * Calling g_win32_registry_key_erase_change_indicator() will reset the indicator,
Packit ae235b
 * and g_win32_registry_key_has_changed() will start returning %FALSE.
Packit ae235b
 * To resume the watch, call g_win32_registry_key_watch_for_changes() again.
Packit ae235b
 *
Packit ae235b
 * Calling g_win32_registry_key_watch_for_changes() for a key that is already
Packit ae235b
 * being watched is allowed and affects nothing.
Packit ae235b
 *
Packit ae235b
 * The fact that the key is being watched will be used internally to update
Packit ae235b
 * key path (if it changes).
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE on success, %FALSE on failure.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_key_watch (GWin32RegistryKey                   *key,
Packit ae235b
                            gboolean                             watch_children,
Packit ae235b
                            GWin32RegistryKeyWatcherFlags        watch_flags,
Packit ae235b
                            GWin32RegistryKeyWatchCallbackFunc   callback,
Packit ae235b
                            gpointer                             user_data,
Packit ae235b
                            GError                             **error)
Packit ae235b
{
Packit ae235b
  ULONG filter;
Packit ae235b
  gboolean started_to_watch;
Packit ae235b
  NTSTATUS status;
Packit ae235b
  PIO_STATUS_BLOCK status_block;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
Packit ae235b
Packit ae235b
  filter = ((watch_flags & G_WIN32_REGISTRY_WATCH_NAME)       ? REG_NOTIFY_CHANGE_NAME       : 0) |
Packit ae235b
           ((watch_flags & G_WIN32_REGISTRY_WATCH_ATTRIBUTES) ? REG_NOTIFY_CHANGE_ATTRIBUTES : 0) |
Packit ae235b
           ((watch_flags & G_WIN32_REGISTRY_WATCH_VALUES)     ? REG_NOTIFY_CHANGE_LAST_SET   : 0) |
Packit ae235b
           ((watch_flags & G_WIN32_REGISTRY_WATCH_SECURITY)   ? REG_NOTIFY_CHANGE_SECURITY   : 0);
Packit ae235b
Packit ae235b
  if (filter == 0)
Packit ae235b
    {
Packit ae235b
      g_critical ("No supported flags specified in watch_flags (%x)", (guint) watch_flags);
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (g_once_init_enter (&nt_notify_change_multiple_keys))
Packit ae235b
  {
Packit ae235b
    NtNotifyChangeMultipleKeysFunc func;
Packit ae235b
    HMODULE ntdll = GetModuleHandle ("ntdll.dll");
Packit ae235b
Packit ae235b
    if (ntdll != NULL)
Packit ae235b
      func = (NtNotifyChangeMultipleKeysFunc) GetProcAddress (ntdll, "NtNotifyChangeMultipleKeys");
Packit ae235b
    else
Packit ae235b
      func = NULL;
Packit ae235b
Packit ae235b
    g_once_init_leave (&nt_notify_change_multiple_keys, func);
Packit ae235b
  }
Packit ae235b
Packit ae235b
  if (nt_notify_change_multiple_keys== NULL)
Packit ae235b
    {
Packit ae235b
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
Packit ae235b
                   "Couldn't get NtNotifyChangeMultipleKeys() from ntdll");
Packit ae235b
      return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  started_to_watch =
Packit ae235b
      g_atomic_int_compare_and_exchange (&key->priv->watch_indicator,
Packit ae235b
                                         G_WIN32_KEY_UNWATCHED,
Packit ae235b
                                         G_WIN32_KEY_WATCHED);
Packit ae235b
Packit ae235b
  if (!started_to_watch)
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  key->priv->callback = callback;
Packit ae235b
  key->priv->user_data = user_data;
Packit ae235b
Packit ae235b
  g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNCHANGED);
Packit ae235b
Packit ae235b
  /* Keep it alive until APC is called */
Packit ae235b
  g_object_ref (key);
Packit ae235b
Packit ae235b
  status_block = g_malloc (sizeof (IO_STATUS_BLOCK));
Packit ae235b
Packit ae235b
  status = nt_notify_change_multiple_keys (key->priv->handle,
Packit ae235b
                                           0,
Packit ae235b
                                           NULL,
Packit ae235b
                                           NULL,
Packit ae235b
                                           key_changed,
Packit ae235b
                                           (PVOID) key,
Packit ae235b
                                           status_block,
Packit ae235b
                                           filter,
Packit ae235b
                                           watch_children,
Packit ae235b
                                           NULL,
Packit ae235b
                                           0,
Packit ae235b
                                           TRUE);
Packit ae235b
Packit ae235b
  g_assert (status != STATUS_SUCCESS);
Packit ae235b
Packit ae235b
  if (status == STATUS_PENDING)
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN);
Packit ae235b
  g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED);
Packit ae235b
  g_object_unref (key);
Packit ae235b
  g_free (status_block);
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_erase_change_indicator:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 *
Packit ae235b
 * Erases change indicator of the @key.
Packit ae235b
 *
Packit ae235b
 * Subsequent calls to g_win32_registry_key_has_changed() will return %FALSE
Packit ae235b
 * until the key is put on watch again by calling
Packit ae235b
 * g_win32_registry_key_watch() again.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_win32_registry_key_erase_change_indicator (GWin32RegistryKey *key)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (G_IS_WIN32_REGISTRY_KEY (key));
Packit ae235b
Packit ae235b
  g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_win32_registry_key_has_changed:
Packit ae235b
 * @key: (in) (transfer none): a #GWin32RegistryKey
Packit ae235b
 *
Packit ae235b
 * Check the @key's status indicator.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the @key was put under watch at some point and has changed
Packit ae235b
 * since then, %FALSE if it either wasn't changed or wasn't watched at all.
Packit ae235b
 *
Packit ae235b
 * Since: 2.46
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_win32_registry_key_has_changed (GWin32RegistryKey *key)
Packit ae235b
{
Packit ae235b
  gint changed;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_WIN32_REGISTRY_KEY (key), FALSE);
Packit ae235b
Packit ae235b
  changed = g_atomic_int_get (&key->priv->change_indicator);
Packit ae235b
Packit ae235b
  return (changed == G_WIN32_KEY_CHANGED ? TRUE : FALSE);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_win32_registry_key_get_property (GObject    *object,
Packit ae235b
                                   guint       prop_id,
Packit ae235b
                                   GValue     *value,
Packit ae235b
                                   GParamSpec *pspec)
Packit ae235b
{
Packit ae235b
  GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (object);
Packit ae235b
Packit ae235b
  switch (prop_id)
Packit ae235b
    {
Packit ae235b
      case PROP_PATH:
Packit ae235b
        g_value_set_string (value, g_win32_registry_key_get_path (key));
Packit ae235b
        break;
Packit ae235b
Packit ae235b
      case PROP_PATH_UTF16:
Packit ae235b
        g_value_set_pointer (value, (gpointer) g_win32_registry_key_get_path_w (key));
Packit ae235b
        break;
Packit ae235b
Packit ae235b
      default:
Packit ae235b
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_win32_registry_key_set_property (GObject      *object,
Packit ae235b
                                   guint         prop_id,
Packit ae235b
                                   const GValue *value,
Packit ae235b
                                   GParamSpec   *pspec)
Packit ae235b
{
Packit ae235b
  GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (object);
Packit ae235b
  GWin32RegistryKeyPrivate *priv = key->priv;
Packit ae235b
  const gchar *path;
Packit ae235b
  gunichar2 *path_w;
Packit ae235b
Packit ae235b
  switch (prop_id)
Packit ae235b
    {
Packit ae235b
    case PROP_PATH:
Packit ae235b
      g_assert (priv->absolute_path_w == NULL);
Packit ae235b
      g_assert (priv->absolute_path == NULL);
Packit ae235b
      path = g_value_get_string (value);
Packit ae235b
Packit ae235b
      if (path == NULL)
Packit ae235b
        break;
Packit ae235b
Packit ae235b
      path_w = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
Packit ae235b
Packit ae235b
      if (path_w == NULL)
Packit ae235b
        break;
Packit ae235b
Packit ae235b
      g_free (priv->absolute_path_w);
Packit ae235b
      g_free (priv->absolute_path);
Packit ae235b
      priv->absolute_path_w = path_w;
Packit ae235b
      priv->absolute_path = g_value_dup_string (value);
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case PROP_PATH_UTF16:
Packit ae235b
      g_assert (priv->absolute_path_w == NULL);
Packit ae235b
      g_assert (priv->absolute_path == NULL);
Packit ae235b
      path_w = (gunichar2 *) g_value_get_pointer (value);
Packit ae235b
Packit ae235b
      if (path_w == NULL)
Packit ae235b
        break;
Packit ae235b
Packit ae235b
      priv->absolute_path_w = g_wcsdup (path_w, -1);
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    default:
Packit ae235b
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_win32_registry_key_class_init (GWin32RegistryKeyClass *klass)
Packit ae235b
{
Packit ae235b
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit ae235b
Packit ae235b
  gobject_class->dispose = g_win32_registry_key_dispose;
Packit ae235b
  gobject_class->set_property = g_win32_registry_key_set_property;
Packit ae235b
  gobject_class->get_property = g_win32_registry_key_get_property;
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GWin32RegistryKey:path:
Packit ae235b
   *
Packit ae235b
   * A path to the key in the registry, in UTF-8.
Packit ae235b
   *
Packit ae235b
   * Since: 2.46
Packit ae235b
   */
Packit ae235b
  g_object_class_install_property (gobject_class,
Packit ae235b
                                   PROP_PATH,
Packit ae235b
                                   g_param_spec_string ("path",
Packit ae235b
                                                        "Path",
Packit ae235b
                                                        "Path to the key in the registry",
Packit ae235b
                                                        NULL,
Packit ae235b
                                                        G_PARAM_READWRITE |
Packit ae235b
                                                        G_PARAM_CONSTRUCT_ONLY |
Packit ae235b
                                                        G_PARAM_STATIC_STRINGS));
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GWin32RegistryKey:path-utf16:
Packit ae235b
   *
Packit ae235b
   * A path to the key in the registry, in UTF-16.
Packit ae235b
   *
Packit ae235b
   * Since: 2.46
Packit ae235b
   */
Packit ae235b
  g_object_class_install_property (gobject_class,
Packit ae235b
                                   PROP_PATH_UTF16,
Packit ae235b
                                   g_param_spec_pointer ("path-utf16",
Packit ae235b
                                                        "Path (UTF-16)",
Packit ae235b
                                                        "Path to the key in the registry, in UTF-16",
Packit ae235b
                                                        G_PARAM_READWRITE |
Packit ae235b
                                                        G_PARAM_CONSTRUCT_ONLY |
Packit ae235b
                                                        G_PARAM_STATIC_STRINGS));
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_win32_registry_key_init (GWin32RegistryKey *key)
Packit ae235b
{
Packit ae235b
  key->priv = g_win32_registry_key_get_instance_private (key);
Packit ae235b
  key->priv->change_indicator = G_WIN32_KEY_UNKNOWN;
Packit ae235b
}