diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index bc810bf..acb6eb6 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -820,6 +820,7 @@ get_volume_for_path (const char *path)
   wchar_t *result;
 
   wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
+  wpath = g_win32_expand_path (wpath);
   result = g_new (wchar_t, MAX_PATH);
 
   if (!GetVolumePathNameW (wpath, result, MAX_PATH))
@@ -962,7 +963,9 @@ g_local_file_query_filesystem_info (GFile         *file,
       gchar *localdir = g_path_get_dirname (local->filename);
       wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL);
       ULARGE_INTEGER li;
-      
+
+      wdirname = g_win32_expand_path (wdirname);
+
       g_free (localdir);
       if (GetDiskFreeSpaceExW (wdirname, &li, NULL, NULL))
         g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, (guint64)li.QuadPart);
@@ -981,7 +984,9 @@ g_local_file_query_filesystem_info (GFile         *file,
       gchar *localdir = g_path_get_dirname (local->filename);
       wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL);
       ULARGE_INTEGER li;
-      
+
+      wdirname = g_win32_expand_path (wdirname);
+
       g_free (localdir);
       if (GetDiskFreeSpaceExW (wdirname, NULL, &li, NULL))
         g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,  (guint64)li.QuadPart);
@@ -2076,6 +2081,7 @@ g_local_file_trash (GFile         *file,
   long len;
 
   wfilename = g_utf8_to_utf16 (local->filename, -1, NULL, &len, NULL);
+  wfilename = g_win32_expand_path (wfilename);
   /* SHFILEOPSTRUCT.pFrom is double-zero-terminated */
   wfilename = g_renew (wchar_t, wfilename, len + 2);
   wfilename[len + 1] = 0;
diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c
index 6c1fe20..42be420 100644
--- a/gio/glocalfileinfo.c
+++ b/gio/glocalfileinfo.c
@@ -1325,6 +1325,9 @@ win32_get_file_user_info (const gchar  *filename,
   DWORD sd_size = 0; /* first call calculates the size required */
   
   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+
+  wfilename = g_win32_expand_path (wfilename);
+
   if ((GetFileSecurityW (wfilename, 
                         GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
 			NULL,
@@ -1454,6 +1457,8 @@ _g_local_file_info_get (const char             *basename,
         return NULL;
       }
 
+    wpath = g_win32_expand_path (wpath);
+
     len = wcslen (wpath);
     while (len > 0 && G_IS_DIR_SEPARATOR (wpath[len-1]))
       len--;
diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c
index a441251..5fd43d9 100644
--- a/gio/gwin32appinfo.c
+++ b/gio/gwin32appinfo.c
@@ -283,6 +283,8 @@ g_win32_app_info_launch (GAppInfo           *appinfo,
       char *path = g_file_get_path (l->data);
       wchar_t *wfilename = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
 
+      wfilename = g_win32_expand_path (wfilename);
+
       g_free (path);
       
       memset (&exec_info, 0, sizeof (exec_info));
diff --git a/gio/gwin32mount.c b/gio/gwin32mount.c
index b40412f..bb0417c 100644
--- a/gio/gwin32mount.c
+++ b/gio/gwin32mount.c
@@ -109,6 +109,9 @@ _win32_get_displayname (const char *drive)
   gunichar2 *wdrive = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL);
   gchar *name = NULL;
   SHFILEINFOW sfi;
+
+  wdrive = g_win32_expand_path (drive);
+
   if (SHGetFileInfoW(wdrive, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
     name = g_utf16_to_utf8 (sfi.szDisplayName, -1, NULL, NULL, NULL);
 
@@ -217,6 +220,8 @@ g_win32_mount_get_icon (GMount *mount)
       SHFILEINFOW shfi;
       wchar_t *wfn = g_utf8_to_utf16 (win32_mount->mount_path, -1, NULL, NULL, NULL);
 
+      wfn = g_win32_expand_path (wfn);
+
       if (SHGetFileInfoW (wfn, 0, &shfi, sizeof (shfi), SHGFI_ICONLOCATION))
         {
 	  gchar *name = g_utf16_to_utf8 (shfi.szDisplayName, -1, NULL, NULL, NULL);
diff --git a/gio/win32/gwin32directorymonitor.c b/gio/win32/gwin32directorymonitor.c
index 4b774ee..b10bd5e 100644
--- a/gio/win32/gwin32directorymonitor.c
+++ b/gio/win32/gwin32directorymonitor.c
@@ -191,6 +191,8 @@ g_win32_directory_monitor_constructor (GType                  type,
   self = G_WIN32_DIRECTORY_MONITOR (obj);
   wdirname = g_utf8_to_utf16 (G_LOCAL_DIRECTORY_MONITOR (obj)->dirname, -1, NULL, NULL, NULL);
 
+  wdirname = g_win32_expand_path (wdirname);
+
   self->priv->hDirectory = CreateFileW (wdirname,
 					FILE_LIST_DIRECTORY,
 					FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 
diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c
index 84d5d77..7f2466f 100644
--- a/gio/win32/gwinhttpfile.c
+++ b/gio/win32/gwinhttpfile.c
@@ -371,6 +371,8 @@ g_winhttp_file_resolve_relative_path (GFile      *file,
   if (wnew_path == NULL)
     return NULL;
 
+  wnew_path = g_win32_expand_path (wnew_path);
+
   if (*wnew_path != '/')
     {
       wchar_t *tmp = NULL;
diff --git a/glib/gdir.c b/glib/gdir.c
index 9919bbb..a573240 100644
--- a/glib/gdir.c
+++ b/glib/gdir.c
@@ -98,6 +98,8 @@ g_dir_open (const gchar  *path,
   if (wpath == NULL)
     return NULL;
 
+  wpath = g_win32_expand_path (wpath);
+
   dir = g_new (GDir, 1);
 
   dir->wdirp = _wopendir (wpath);
diff --git a/glib/gfileutils.c b/glib/gfileutils.c
index b7cd2d5..7c6ca78 100644
--- a/glib/gfileutils.c
+++ b/glib/gfileutils.c
@@ -176,6 +176,8 @@ g_mkdir_with_parents (const gchar *pathname,
  * %G_FILE_TEST_IS_EXECUTABLE will just check that the file exists and
  * its name indicates that it is executable, checking for well-known
  * extensions and those listed in the %PATHEXT environment variable.
+ * On Windows you can also OR in the value G_FILE_TEST_NO_EXPAND to
+ * prevent environment variable expansion in the file name.
  *
  * Return value: whether a test was %TRUE
  **/
@@ -194,6 +196,9 @@ g_file_test (const gchar *filename,
   int attributes;
   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
 
+  if (!(test & G_FILE_TEST_NO_EXPAND))
+    wfilename = g_win32_expand_path (wfilename);
+
   if (wfilename == NULL)
     return FALSE;
 
diff --git a/glib/gfileutils.h b/glib/gfileutils.h
index 1d7f4dc..c8509dc 100644
--- a/glib/gfileutils.h
+++ b/glib/gfileutils.h
@@ -71,6 +71,9 @@ typedef enum
   G_FILE_TEST_IS_DIR        = 1 << 2,
   G_FILE_TEST_IS_EXECUTABLE = 1 << 3,
   G_FILE_TEST_EXISTS        = 1 << 4
+#ifdef G_OS_WIN32
+  , G_FILE_TEST_NO_EXPAND   = 1 << 5
+#endif
 } GFileTest;
 
 GQuark     g_file_error_quark      (void);
diff --git a/glib/glib.symbols b/glib/glib.symbols
index ba24a19..fcf8969 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1541,6 +1541,7 @@ g_variant_format_string_scan_type
 g_variant_format_string_scan
 #ifdef G_OS_WIN32
 g_win32_error_message
+g_win32_expand_path
 g_win32_ftruncate
 g_win32_get_package_installation_directory_of_module
 #ifndef _WIN64
diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c
index 44ae907..87e9c96 100644
--- a/glib/gspawn-win32.c
+++ b/glib/gspawn-win32.c
@@ -438,6 +438,7 @@ do_spawn_directly (gint                 *exit_status,
   new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
       
   wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
+  wargv0 = g_win32_expand_path (wargv0);
   if (wargv0 == NULL)
     {
       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
@@ -748,6 +749,7 @@ do_spawn_with_pipes (gint                 *exit_status,
     }
 
   whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL);
+  whelper = g_win32_expand_path (whelper);
   g_free (helper_process);
 
   if (wenvp != NULL)
diff --git a/glib/gstdio.c b/glib/gstdio.c
index fb5a9fb..9ccfe0f 100644
--- a/glib/gstdio.c
+++ b/glib/gstdio.c
@@ -194,7 +194,9 @@ g_open (const gchar *filename,
   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
   int retval;
   int save_errno;
-    
+
+  wfilename =  g_win32_expand_path (wfilename);
+
   if (wfilename == NULL)
     {
       errno = EINVAL;
@@ -251,7 +253,9 @@ g_creat (const gchar *filename,
   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
   int retval;
   int save_errno;
-    
+
+  wfilename =  g_win32_expand_path (wfilename);
+
   if (wfilename == NULL)
     {
       errno = EINVAL;
@@ -296,6 +300,8 @@ g_rename (const gchar *oldfilename,
   int retval;
   int save_errno = 0;
 
+  woldfilename =  g_win32_expand_path (woldfilename);
+
   if (woldfilename == NULL)
     {
       errno = EINVAL;
@@ -311,6 +317,8 @@ g_rename (const gchar *oldfilename,
       return -1;
     }
 
+  wnewfilename =  g_win32_expand_path (wnewfilename);
+
   if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
     retval = 0;
   else
@@ -373,6 +381,8 @@ g_mkdir (const gchar *filename,
       return -1;
     }
 
+  wfilename =  g_win32_expand_path (wfilename);
+
   retval = _wmkdir (wfilename);
   save_errno = errno;
 
@@ -412,6 +422,8 @@ g_chdir (const gchar *path)
       return -1;
     }
 
+  wpath =  g_win32_expand_path (wpath);
+
   retval = _wchdir (wpath);
   save_errno = errno;
 
@@ -481,6 +493,8 @@ g_stat (const gchar *filename,
       return -1;
     }
 
+  wfilename =  g_win32_expand_path (wfilename);
+
   len = wcslen (wfilename);
   while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
     len--;
@@ -563,6 +577,8 @@ g_unlink (const gchar *filename)
       return -1;
     }
 
+  wfilename =  g_win32_expand_path (wfilename);
+
   retval = _wunlink (wfilename);
   save_errno = errno;
 
@@ -615,6 +631,8 @@ g_remove (const gchar *filename)
       return -1;
     }
 
+  wfilename =  g_win32_expand_path (wfilename);
+
   retval = _wremove (wfilename);
   if (retval == -1)
     retval = _wrmdir (wfilename);
@@ -658,6 +676,8 @@ g_rmdir (const gchar *filename)
       return -1;
     }
   
+  wfilename =  g_win32_expand_path (wfilename);
+
   retval = _wrmdir (wfilename);
   save_errno = errno;
 
@@ -710,6 +730,8 @@ g_fopen (const gchar *filename,
       return NULL;
     }
 
+  wfilename =  g_win32_expand_path (wfilename);
+
   wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
 
   if (wmode == NULL)
@@ -766,6 +788,8 @@ g_freopen (const gchar *filename,
       return NULL;
     }
   
+  wfilename =  g_win32_expand_path (wfilename);
+
   wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
 
   if (wmode == NULL)
@@ -819,6 +843,8 @@ g_utime (const gchar    *filename,
       return -1;
     }
   
+  wfilename =  g_win32_expand_path (wfilename);
+
   retval = _wutime (wfilename, (struct _utimbuf*) utb);
   save_errno = errno;
 
diff --git a/glib/gwin32.c b/glib/gwin32.c
index 9ba02ad..4f78874 100644
--- a/glib/gwin32.c
+++ b/glib/gwin32.c
@@ -294,6 +294,8 @@ get_package_directory_from_module (const gchar *module_name)
   if (module_name)
     {
       wchar_t *wc_module_name = g_utf8_to_utf16 (module_name, -1, NULL, NULL, NULL);
+      wc_module_name = g_win32_expand_path (wc_module_name);
+
       hmodule = GetModuleHandleW (wc_module_name);
       g_free (wc_module_name);
 
@@ -594,3 +596,56 @@ g_win32_locale_filename_from_utf8 (const gchar *utf8filename)
     }
   return retval;
 }
+
+/**
+ * g_win32_expand_path:
+ * @utf16filename: a UTF-16 encoded filename.
+ *
+ * Expand any embedded environment variables in a file path.
+ *
+ * @utf16filename must have been previous allocated using g_malloc() or other
+ * internal allocation functions. If the expansion succeeds, this original
+ * variable is freed with g_free(). Most commonly this parameter is the return
+ * value of g_utf8_to_utf16(). Unlike other GLib functions this function uses
+ * native Windows data types for its argument and return value.
+ *
+ * The return value is either a dynamically allocated string that contains the
+ * expanded path and should be freed with g_free() when no longer needed. or
+ * the original @utf16filename if there was any kind of expansion error.
+ *
+ * Since: 2.29.15.
+ */
+wchar_t *
+g_win32_expand_path (wchar_t *utf16filename)
+{
+  wchar_t *expanded_path, used_only_for_size[2];
+  DWORD required_len;
+
+  if (NULL == utf16filename)
+    return utf16filename;
+
+  required_len = ExpandEnvironmentStringsW (utf16filename,
+                                            used_only_for_size,
+                                            1);
+  if (required_len != 0)
+    {
+      expanded_path = (wchar_t *)g_malloc ((required_len + 2) * sizeof (wchar_t));
+      if (expanded_path)
+        {
+          required_len = ExpandEnvironmentStringsW (utf16filename,
+                                                    expanded_path,
+                                                    required_len + 1);
+          if (0 == required_len)
+            {
+              g_free (expanded_path);
+            }
+          else
+            {
+              g_free (utf16filename);
+              utf16filename = expanded_path;
+            }
+        }
+    }
+
+  return utf16filename;
+}
diff --git a/glib/gwin32.h b/glib/gwin32.h
index f368c1d..99a1c16 100644
--- a/glib/gwin32.h
+++ b/glib/gwin32.h
@@ -83,6 +83,14 @@ gchar* 		g_win32_getlocale  (void);
  */
 gchar*          g_win32_error_message (gint error);
 
+/* Expand a file path replacing environment variables. The file name must have
+ * been allocated and if replacement succeeds, will be g_free()'ed. Since this
+ * function requires the input string to be wchar_t *, it will most likely be
+ * the return value from g_utf8_to_utf16(). Returns either a newly allocated
+ * string if expansion succeeds, or the original string if not.
+ */
+wchar_t*        g_win32_expand_path (wchar_t *original_filename);
+
 #ifndef G_DISABLE_DEPRECATED
 
 #ifndef __GTK_DOC_IGNORE__
diff --git a/gmodule/gmodule-win32.c b/gmodule/gmodule-win32.c
index 439fb5d..ab2a971 100644
--- a/gmodule/gmodule-win32.c
+++ b/gmodule/gmodule-win32.c
@@ -80,9 +80,11 @@ _g_module_open (const gchar *file_name,
 #endif
   wfilename = g_utf8_to_utf16 (file_name, -1, NULL, NULL, NULL);
 
+  wfilename = g_win32_expand_path (wfilename);
+
   handle = LoadLibraryW (wfilename);
   g_free (wfilename);
-      
+
   if (!handle)
     set_error ("`%s': ", file_name);
 
