diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index 8b3c858ba..024e93b43 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -37,8 +37,6 @@ #include "gtask.h" #include "glib-private.h" #include "gdbusprivate.h" -#include "giomodule-priv.h" -#include "gdbusdaemon.h" #include "gstdio.h" #ifdef G_OS_UNIX @@ -50,8 +48,6 @@ #ifdef G_OS_WIN32 #include -#include -#include #endif #include "glibintl.h" @@ -1195,367 +1191,12 @@ get_session_address_dbus_launch (GError **error) /* end of G_OS_UNIX case */ #elif defined(G_OS_WIN32) -#define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo" -#define DBUS_DAEMON_MUTEX "DBusDaemonMutex" -#define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex" -#define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex" - -static void -release_mutex (HANDLE mutex) -{ - ReleaseMutex (mutex); - CloseHandle (mutex); -} - -static HANDLE -acquire_mutex (const char *mutexname) -{ - HANDLE mutex; - DWORD res; - - mutex = CreateMutexA (NULL, FALSE, mutexname); - if (!mutex) - return 0; - - res = WaitForSingleObject (mutex, INFINITE); - switch (res) - { - case WAIT_ABANDONED: - release_mutex (mutex); - return 0; - case WAIT_FAILED: - case WAIT_TIMEOUT: - return 0; - } - - return mutex; -} - -static gboolean -is_mutex_owned (const char *mutexname) -{ - HANDLE mutex; - gboolean res = FALSE; - - mutex = CreateMutexA (NULL, FALSE, mutexname); - if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT) - res = TRUE; - else - ReleaseMutex (mutex); - CloseHandle (mutex); - - return res; -} - -static char * -read_shm (const char *shm_name) -{ - HANDLE shared_mem; - char *shared_data; - char *res; - int i; - - res = NULL; - - for (i = 0; i < 20; i++) - { - shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name); - if (shared_mem != 0) - break; - Sleep (100); - } - - if (shared_mem != 0) - { - shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0); - /* It looks that a race is possible here: - * if the dbus process already created mapping but didn't fill it - * the code below may read incorrect address. - * Also this is a bit complicated by the fact that - * any change in the "synchronization contract" between processes - * should be accompanied with renaming all of used win32 named objects: - * otherwise libgio-2.0-0.dll of different versions shipped with - * different apps may break each other due to protocol difference. - */ - if (shared_data != NULL) - { - res = g_strdup (shared_data); - UnmapViewOfFile (shared_data); - } - CloseHandle (shared_mem); - } - - return res; -} - -static HANDLE -set_shm (const char *shm_name, const char *value) -{ - HANDLE shared_mem; - char *shared_data; - - shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, strlen (value) + 1, shm_name); - if (shared_mem == 0) - return 0; - - shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 ); - if (shared_data == NULL) - return 0; - - strcpy (shared_data, value); - - UnmapViewOfFile (shared_data); - - return shared_mem; -} - -/* These keep state between publish_session_bus and unpublish_session_bus */ -static HANDLE published_daemon_mutex; -static HANDLE published_shared_mem; - -static gboolean -publish_session_bus (const char *address) -{ - HANDLE init_mutex; - - init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); - - published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX); - if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0) - { - release_mutex (init_mutex); - CloseHandle (published_daemon_mutex); - published_daemon_mutex = NULL; - return FALSE; - } - - published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address); - if (!published_shared_mem) - { - release_mutex (init_mutex); - CloseHandle (published_daemon_mutex); - published_daemon_mutex = NULL; - return FALSE; - } - - release_mutex (init_mutex); - return TRUE; -} - -static void -unpublish_session_bus (void) -{ - HANDLE init_mutex; - - init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); - - CloseHandle (published_shared_mem); - published_shared_mem = NULL; - - release_mutex (published_daemon_mutex); - published_daemon_mutex = NULL; - - release_mutex (init_mutex); -} - -static void -wait_console_window (void) -{ - FILE *console = fopen ("CONOUT$", "w"); - - SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window."); - fprintf (console, _("(Type any character to close this window)\n")); - fflush (console); - _getch (); -} - -static void -open_console_window (void) -{ - if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE || - (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ()) - { - if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE) - freopen ("CONOUT$", "w", stdout); - - if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) - freopen ("CONOUT$", "w", stderr); - - SetConsoleTitleW (L"gdbus-daemon debug output."); - - atexit (wait_console_window); - } -} - -static void -idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data) -{ - GMainLoop *loop = user_data; - g_main_loop_quit (loop); -} - -/* Satisfies STARTF_FORCEONFEEDBACK */ -static void -turn_off_the_starting_cursor (void) -{ - MSG msg; - BOOL bRet; - - PostQuitMessage (0); - - while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0) - { - if (bRet == -1) - continue; - - TranslateMessage (&msg); - DispatchMessage (&msg); - } -} - -__declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow); - -__declspec(dllexport) void CALLBACK -g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow) -{ - GDBusDaemon *daemon; - GMainLoop *loop; - const char *address; - GError *error = NULL; - - turn_off_the_starting_cursor (); - - 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) - { - g_printerr ("Can't init bus: %s\n", error->message); - g_error_free (error); - return; - } - - /* 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 - * if no clients connect to daemon at all. - * This may lead to infinite run of this daemon process. - */ - g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop); - - if (publish_session_bus (_g_dbus_daemon_get_address (daemon))) - { - g_main_loop_run (loop); - - unpublish_session_bus (); - } - - g_main_loop_unref (loop); - g_object_unref (daemon); -} - static gchar * get_session_address_dbus_launch (GError **error) { - HANDLE autolaunch_mutex, init_mutex; - char *address = NULL; - - autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX); - - init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); - - if (is_mutex_owned (DBUS_DAEMON_MUTEX)) - address = read_shm (DBUS_DAEMON_ADDRESS_INFO); - - release_mutex (init_mutex); - - if (address == NULL) - { - /* 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); - - /* The <= MAX_PATH check prevents truncated path usage */ - if (gio_path_len > 0 && gio_path_len <= MAX_PATH) - { - 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 }; - /* 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) - { - wchar_t prev_char = gio_path[gio_name_index - 1]; - 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) - { - GetSystemDirectoryW (rundll_path, MAX_PATH); - wcscat (rundll_path, L"\\rundll32.exe"); - } - - 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); - } - } - - release_mutex (autolaunch_mutex); - - if (address == NULL) - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - _("Session dbus not running, and autolaunch failed")); - - return address; + return _g_dbus_win32_get_session_address_dbus_launch (error); } + #else /* neither G_OS_UNIX nor G_OS_WIN32 */ static gchar * get_session_address_dbus_launch (GError **error) diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 1e8e1d64b..385b5a4d6 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -33,6 +33,8 @@ #include "gdbusproxy.h" #include "gdbuserror.h" #include "gdbusintrospection.h" +#include "gdbusdaemon.h" +#include "giomodule-priv.h" #include "gtask.h" #include "ginputstream.h" #include "gmemoryinputstream.h" @@ -51,6 +53,8 @@ #ifdef G_OS_WIN32 #include +#include +#include #endif #include "glibintl.h" @@ -2054,6 +2058,368 @@ out: CloseHandle (h); return ret; } + + +#define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo" +#define DBUS_DAEMON_MUTEX "DBusDaemonMutex" +#define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex" +#define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex" + +static void +release_mutex (HANDLE mutex) +{ + ReleaseMutex (mutex); + CloseHandle (mutex); +} + +static HANDLE +acquire_mutex (const char *mutexname) +{ + HANDLE mutex; + DWORD res; + + mutex = CreateMutexA (NULL, FALSE, mutexname); + if (!mutex) + return 0; + + res = WaitForSingleObject (mutex, INFINITE); + switch (res) + { + case WAIT_ABANDONED: + release_mutex (mutex); + return 0; + case WAIT_FAILED: + case WAIT_TIMEOUT: + return 0; + } + + return mutex; +} + +static gboolean +is_mutex_owned (const char *mutexname) +{ + HANDLE mutex; + gboolean res = FALSE; + + mutex = CreateMutexA (NULL, FALSE, mutexname); + if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT) + res = TRUE; + else + ReleaseMutex (mutex); + CloseHandle (mutex); + + return res; +} + +static char * +read_shm (const char *shm_name) +{ + HANDLE shared_mem; + char *shared_data; + char *res; + int i; + + res = NULL; + + for (i = 0; i < 20; i++) + { + shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name); + if (shared_mem != 0) + break; + Sleep (100); + } + + if (shared_mem != 0) + { + shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0); + /* It looks that a race is possible here: + * if the dbus process already created mapping but didn't fill it + * the code below may read incorrect address. + * Also this is a bit complicated by the fact that + * any change in the "synchronization contract" between processes + * should be accompanied with renaming all of used win32 named objects: + * otherwise libgio-2.0-0.dll of different versions shipped with + * different apps may break each other due to protocol difference. + */ + if (shared_data != NULL) + { + res = g_strdup (shared_data); + UnmapViewOfFile (shared_data); + } + CloseHandle (shared_mem); + } + + return res; +} + +static HANDLE +set_shm (const char *shm_name, const char *value) +{ + HANDLE shared_mem; + char *shared_data; + + shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, strlen (value) + 1, shm_name); + if (shared_mem == 0) + return 0; + + shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 ); + if (shared_data == NULL) + return 0; + + strcpy (shared_data, value); + + UnmapViewOfFile (shared_data); + + return shared_mem; +} + +/* These keep state between publish_session_bus and unpublish_session_bus */ +static HANDLE published_daemon_mutex; +static HANDLE published_shared_mem; + +static gboolean +publish_session_bus (const char *address) +{ + HANDLE init_mutex; + + init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); + + published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX); + if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0) + { + release_mutex (init_mutex); + CloseHandle (published_daemon_mutex); + published_daemon_mutex = NULL; + return FALSE; + } + + published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address); + if (!published_shared_mem) + { + release_mutex (init_mutex); + CloseHandle (published_daemon_mutex); + published_daemon_mutex = NULL; + return FALSE; + } + + release_mutex (init_mutex); + return TRUE; +} + +static void +unpublish_session_bus (void) +{ + HANDLE init_mutex; + + init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); + + CloseHandle (published_shared_mem); + published_shared_mem = NULL; + + release_mutex (published_daemon_mutex); + published_daemon_mutex = NULL; + + release_mutex (init_mutex); +} + +static void +wait_console_window (void) +{ + FILE *console = fopen ("CONOUT$", "w"); + + SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window."); + fprintf (console, _("(Type any character to close this window)\n")); + fflush (console); + _getch (); +} + +static void +open_console_window (void) +{ + if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE || + (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ()) + { + if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE) + freopen ("CONOUT$", "w", stdout); + + if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) + freopen ("CONOUT$", "w", stderr); + + SetConsoleTitleW (L"gdbus-daemon debug output."); + + atexit (wait_console_window); + } +} + +static void +idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data) +{ + GMainLoop *loop = user_data; + g_main_loop_quit (loop); +} + +/* Satisfies STARTF_FORCEONFEEDBACK */ +static void +turn_off_the_starting_cursor (void) +{ + MSG msg; + BOOL bRet; + + PostQuitMessage (0); + + while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0) + { + if (bRet == -1) + continue; + + TranslateMessage (&msg); + DispatchMessage (&msg); + } +} + +__declspec(dllexport) void __stdcall +g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdshow) +{ + GDBusDaemon *daemon; + GMainLoop *loop; + const char *address; + GError *error = NULL; + + turn_off_the_starting_cursor (); + + 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) + { + g_printerr ("Can't init bus: %s\n", error->message); + g_error_free (error); + return; + } + + /* 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 + * if no clients connect to daemon at all. + * This may lead to infinite run of this daemon process. + */ + g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop); + + if (publish_session_bus (_g_dbus_daemon_get_address (daemon))) + { + g_main_loop_run (loop); + + unpublish_session_bus (); + } + + g_main_loop_unref (loop); + g_object_unref (daemon); +} + +gchar * +_g_dbus_win32_get_session_address_dbus_launch (GError **error) +{ + HANDLE autolaunch_mutex, init_mutex; + char *address = NULL; + + autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX); + + init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); + + if (is_mutex_owned (DBUS_DAEMON_MUTEX)) + address = read_shm (DBUS_DAEMON_ADDRESS_INFO); + + release_mutex (init_mutex); + + if (address == NULL) + { + /* 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); + + /* The <= MAX_PATH check prevents truncated path usage */ + if (gio_path_len > 0 && gio_path_len <= MAX_PATH) + { + 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 }; + /* 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) + { + wchar_t prev_char = gio_path[gio_name_index - 1]; + 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) + { + GetSystemDirectoryW (rundll_path, MAX_PATH); + wcscat (rundll_path, L"\\rundll32.exe"); + } + + 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); + } + } + + release_mutex (autolaunch_mutex); + + if (address == NULL) + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Session dbus not running, and autolaunch failed")); + + return address; +} + #endif /* ---------------------------------------------------------------------------------------------------- */ diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h index a319166ee..7f5845f47 100644 --- a/gio/gdbusprivate.h +++ b/gio/gdbusprivate.h @@ -109,6 +109,16 @@ gchar *_g_dbus_hexdump (const gchar *data, gsize len, guint indent); #ifdef G_OS_WIN32 gchar *_g_dbus_win32_get_user_sid (void); + +/* 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. + * Initially this function was introduces for usage with rundll, + * so the signature is kept rundll-compatible, though parameters aren't used. + */ +__declspec(dllexport) void __stdcall +g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdshow); +gchar *_g_dbus_win32_get_session_address_dbus_launch (GError **error); #endif gchar *_g_dbus_get_machine_id (GError **error);