[glib: 3/7] gdbus, win32: autolaunch bus with gdbus.exe instead of rundll32



commit 8c7670f0e1b4b4850a82aa76a67b4c2fb78344fb
Author: Vasily Galkin <galkin-vv ya ru>
Date:   Thu Feb 28 23:12:47 2019 +0300

    gdbus, win32: autolaunch bus with gdbus.exe instead of rundll32
    
    This is a bit of breaking change:
    After this commit the apps relying of win32 dbus autolaunching,
    need to install gdbus.exe alongside with libgio-2.0-0.dll.
    
    A new command for gdbus tool is used for running server:
    gdbus.exe _win32_run_session_bus
    
    To implement it gdbus.exe uses the same exported function
    g_win32_run_session_bus that earlier was used by rundll.
    So (private) ABI was not changed.
    
    It runs the bus syncronously, exiting after inactivity timeout -
    all exactly like it was runed earlier with the help of rundll32.
    
    While private exported function may have _some_
    version compatibility issues between gdbus.exe and libgio-2.0-0.dll
    compiling dbus server registration logic directly into gdbus.exe
    can lead to _more hidden and more complex_ compatibility issues
    since the names and behaviour of syncronization objects
    used to publish server address would be required compatible between
    gdbus.exe and libgio-2.0-0.dll.
    
    So using "private" exported function to call
    looks like more safe behaviour.
    
    gdbus.exe binary was selected for this task since
    it has corresponding name and at least for msys2 is shippied
    in same package with libgio-2.0-0.dll
    
    turn_off_the_starting_cursor function is also kept as is,
    however it is not obvious if it is still needed
    (by now I failed reproducing original issue).
    
    Explicit g_warnings added to help with possible
    problematic cases for absent or incompatible gdbus.exe
    
    Mainloop is created after successful daemon creation
    Before this change the function leaked mainloop on daemon creation fail

 gio/gdbus-tool.c   |  9 ++++++
 gio/gdbusprivate.c | 89 ++++++++++++++++++++++++------------------------------
 gio/gdbusprivate.h |  1 +
 3 files changed, 49 insertions(+), 50 deletions(-)
---
diff --git a/gio/gdbus-tool.c b/gio/gdbus-tool.c
index 8d06f191b..c8e01ad99 100644
--- a/gio/gdbus-tool.c
+++ b/gio/gdbus-tool.c
@@ -31,6 +31,7 @@
 
 #ifdef G_OS_WIN32
 #include "glib/glib-private.h"
+#include "gdbusprivate.h"
 #endif
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -2421,6 +2422,14 @@ main (gint argc, gchar *argv[])
         ret = 0;
       goto out;
     }
+#ifdef G_OS_WIN32
+  else if (g_strcmp0 (command, _GDBUS_ARG_WIN32_RUN_SESSION_BUS) == 0)
+    {
+      g_win32_run_session_bus (NULL, NULL, NULL, 0);
+      ret = 0;
+      goto out;
+    }
+#endif
   else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
     {
       const gchar *completion_line;
diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c
index 385b5a4d6..4d7ca6f89 100644
--- a/gio/gdbusprivate.c
+++ b/gio/gdbusprivate.c
@@ -2292,8 +2292,6 @@ g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdsh
   if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
     open_console_window ();
 
-  loop = g_main_loop_new (NULL, FALSE);
-
   address = "nonce-tcp:";
   daemon = _g_dbus_daemon_new (address, NULL, &error);
   if (daemon == NULL)
@@ -2303,6 +2301,8 @@ g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdsh
       return;
     }
 
+  loop = g_main_loop_new (NULL, FALSE);
+
   /* There is a subtle detail with "idle-timeout" signal of dbus daemon:
    * It is fired on idle after last client disconnection,
    * but (at least with glib 2.59.1) it is NEVER fired
@@ -2322,6 +2322,8 @@ g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdsh
   g_object_unref (daemon);
 }
 
+static gboolean autolaunch_binary_absent = FALSE;
+
 gchar *
 _g_dbus_win32_get_session_address_dbus_launch (GError **error)
 {
@@ -2337,28 +2339,8 @@ _g_dbus_win32_get_session_address_dbus_launch (GError **error)
 
   release_mutex (init_mutex);
 
-  if (address == NULL)
+  if (address == NULL && !autolaunch_binary_absent)
     {
-      /* rundll32 doesn't support neither spaces, nor quotes in cmdline:
-       * https://support.microsoft.com/en-us/help/164787/info-windows-rundll-and-rundll32-interface
-       * Since the dll path may have spaces, it is used as working directory,
-       * and the plain dll name is passed as argument to rundll32 like
-       * "C:\Windows\System32\rundll32.exe" .\libgio-2.0-0.dll,g_win32_run_session_bus
-       *
-       * Using relative path to dll rises a question if correct dll is loaded.
-       * According to docs if relative path like .\libgio-2.0-0.dll is passed
-       * the System32 directory may be searched before current directory:
-       * 
https://docs.microsoft.com/en-us/windows/desktop/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications
-       * Internally rundll32 uses "undefined behavior" parameter combination
-       * LoadLibraryExW(".\libgio-2.0-0.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
-       * Actual testing shows that if relative name starts from ".\"
-       * the current directory is searched before System32 (win7, win10 1607).
-       * So wrong dll would be loaded only if the BOTH of the following holds:
-       * - rundll32 will change so it would prefer system32 even for .\ paths
-       * - some app would place libgio-2.0-0.dll in system32 directory
-       *
-       * In point of that using .\libgio-2.0-0.dll looks fine.
-       */
       wchar_t gio_path[MAX_PATH + 2] = { 0 };
       int gio_path_len = GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH + 1);
 
@@ -2368,8 +2350,7 @@ _g_dbus_win32_get_session_address_dbus_launch (GError **error)
          PROCESS_INFORMATION pi = { 0 };
          STARTUPINFOW si = { 0 };
          BOOL res = FALSE;
-         wchar_t rundll_path[MAX_PATH + 100] = { 0 };
-         wchar_t args[MAX_PATH*2 + 100] = { 0 };
+         wchar_t exe_path[MAX_PATH + 100] = { 0 };
          /* calculate index of first char of dll file name inside full path */
          int gio_name_index = gio_path_len;
          for (; gio_name_index > 0; --gio_name_index)
@@ -2378,34 +2359,42 @@ _g_dbus_win32_get_session_address_dbus_launch (GError **error)
            if (prev_char == L'\\' || prev_char == L'/')
              break;
          }
-         GetWindowsDirectoryW (rundll_path, MAX_PATH);
-         wcscat (rundll_path, L"\\rundll32.exe");
-         if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
+         gio_path[gio_name_index] = L'\0';
+         wcscpy (exe_path, gio_path);
+         wcscat (exe_path, L"\\gdbus.exe");
+
+         if (GetFileAttributesW (exe_path) == INVALID_FILE_ATTRIBUTES)
            {
-             GetSystemDirectoryW (rundll_path, MAX_PATH);
-             wcscat (rundll_path, L"\\rundll32.exe");
+             /* warning won't be raised another time
+              * since autolaunch_binary_absent would be already set.
+              */
+             autolaunch_binary_absent = TRUE;
+             g_warning ("win32 session dbus binary not found: %S", exe_path );
+           }
+         else
+           {
+             wchar_t args[MAX_PATH*2 + 100] = { 0 };
+             wcscpy (args, L"\"");
+             wcscat (args, exe_path);
+             wcscat (args, L"\" ");
+#define _L_PREFIX_FOR_EXPANDED(arg) L##arg
+#define _L_PREFIX(arg) _L_PREFIX_FOR_EXPANDED (arg)
+             wcscat (args, _L_PREFIX (_GDBUS_ARG_WIN32_RUN_SESSION_BUS));
+#undef _L_PREFIX
+#undef _L_PREFIX_FOR_EXPANDED
+
+             res = CreateProcessW (exe_path, args,
+                                   0, 0, FALSE,
+                                   NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
+                                   0, gio_path,
+                                   &si, &pi);
            }
-
-         wcscpy (args, L"\"");
-         wcscat (args, rundll_path);
-         wcscat (args, L"\" .\\");
-         wcscat (args, gio_path + gio_name_index);
-#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
-         wcscat (args, L",g_win32_run_session_bus");
-#elif defined (_MSC_VER)
-         wcscat (args, L",_g_win32_run_session_bus@16");
-#else
-         wcscat (args, L",g_win32_run_session_bus@16");
-#endif
-
-         gio_path[gio_name_index] = L'\0';
-         res = CreateProcessW (rundll_path, args,
-                               0, 0, FALSE,
-                               NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
-                               0, gio_path,
-                               &si, &pi);
          if (res)
-           address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
+           {
+             address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
+             if (address == NULL)
+               g_warning ("%S dbus binary failed to launch bus, maybe incompatible version", exe_path );
+           }
        }
     }
 
diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h
index 7f5845f47..8f8a93ba7 100644
--- a/gio/gdbusprivate.h
+++ b/gio/gdbusprivate.h
@@ -110,6 +110,7 @@ gchar *_g_dbus_hexdump (const gchar *data, gsize len, guint indent);
 #ifdef G_OS_WIN32
 gchar *_g_dbus_win32_get_user_sid (void);
 
+#define _GDBUS_ARG_WIN32_RUN_SESSION_BUS "_win32_run_session_bus"
 /* The g_win32_run_session_bus is exported from libgio dll on win32,
  * but still is NOT part of API/ABI since it is declared in private header
  * and used only by tool built from same sources.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]