1999-11-01 20:46:44 +00:00
|
|
|
/* GLIB - Library of useful routines for C programming
|
|
|
|
* Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
* Copyright (C) 1998-1999 Tor Lillqvist
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
2000-07-26 11:02:02 +00:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
1999-11-01 20:46:44 +00:00
|
|
|
* License as published by the Free Software Foundation; either
|
2017-01-05 12:47:07 +01:00
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
1999-11-01 20:46:44 +00:00
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2000-07-26 11:02:02 +00:00
|
|
|
* Lesser General Public License for more details.
|
1999-11-01 20:46:44 +00:00
|
|
|
*
|
2000-07-26 11:02:02 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2014-01-23 12:58:29 +01:00
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
1999-11-01 20:46:44 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-07-26 11:02:02 +00:00
|
|
|
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
1999-11-01 20:46:44 +00:00
|
|
|
* file for a list of people on the GLib Team. See the ChangeLog
|
|
|
|
* files for a list of changes. These files are distributed with
|
|
|
|
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MT safe for the unix part, FIXME: make the win32 part MT safe as well.
|
|
|
|
*/
|
|
|
|
|
2002-12-04 01:27:44 +00:00
|
|
|
#include "config.h"
|
1999-11-01 20:46:44 +00:00
|
|
|
|
|
|
|
#include "glibconfig.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2005-01-09 22:55:52 +00:00
|
|
|
#include <wchar.h>
|
1999-11-01 20:46:44 +00:00
|
|
|
#include <errno.h>
|
W32: add std stream redirection envvar options
This commit adds two W32-only environmental variable checks:
* G_WIN32_ALLOC_CONSOLE, if set to 1, will force glib to create
a new console if the process has no console by itself.
This option is for GUI apps that are launched from GUI
processes, in which case there's no console anywhere near them.
* G_WIN32_ATTACH_CONSOLE, if set to a comma-separated list of
standard stream names (stdint, stdout, stderr), will reopen
a given std stream and tie it to the console (using existing console
or parent console).
This works either with the other option (to create a console),
or if the app is launched from a console process (often the
case for developers).
The redirection is done with freopen(), dup() and dup2().
If everything goes well, C file descriptors 0, 1 or 2 will
be bound to stdin, stdout and stderr respectively (only for
streams listed in the envrionmental variable), and so will
be stdio streams by the same names.
With these it's possible to see the output of g_log*() functions
when running GTK4 applications, which are linked as GUI applications,
and thus do not get a console by default.
https://bugzilla.gnome.org/show_bug.cgi?id=790857
Fixes issue #1304
2017-11-26 18:27:51 +00:00
|
|
|
#include <fcntl.h>
|
1999-11-01 20:46:44 +00:00
|
|
|
|
|
|
|
#define STRICT /* Strict typing, please */
|
|
|
|
#include <windows.h>
|
2001-03-09 21:31:21 +00:00
|
|
|
#undef STRICT
|
|
|
|
#ifndef G_WITH_CYGWIN
|
1999-11-01 20:46:44 +00:00
|
|
|
#include <direct.h>
|
2001-03-09 21:31:21 +00:00
|
|
|
#endif
|
1999-11-01 20:46:44 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <ctype.h>
|
2007-01-18 19:05:21 +00:00
|
|
|
#if defined(_MSC_VER) || defined(__DMC__)
|
1999-11-01 20:46:44 +00:00
|
|
|
# include <io.h>
|
2007-01-18 19:05:21 +00:00
|
|
|
#endif /* _MSC_VER || __DMC__ */
|
1999-11-01 20:46:44 +00:00
|
|
|
|
2015-10-07 20:00:50 +08:00
|
|
|
#define MODERN_API_FAMILY 2
|
|
|
|
|
|
|
|
#if WINAPI_FAMILY == MODERN_API_FAMILY
|
|
|
|
/* This is for modern UI Builds, where we can't use LoadLibraryW()/GetProcAddress() */
|
|
|
|
/* ntddk.h is found in the WDK, and MinGW */
|
|
|
|
#include <ntddk.h>
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma comment (lib, "ntoskrnl.lib")
|
|
|
|
#endif
|
2018-05-06 15:29:09 +05:30
|
|
|
#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
|
|
|
|
/* mingw-w64 must use winternl.h, but not MinGW */
|
2016-01-05 15:08:18 +08:00
|
|
|
#include <ntdef.h>
|
2015-10-24 11:05:27 +08:00
|
|
|
#else
|
|
|
|
#include <winternl.h>
|
2015-10-07 20:00:50 +08:00
|
|
|
#endif
|
|
|
|
|
1999-11-01 20:46:44 +00:00
|
|
|
#include "glib.h"
|
2011-09-09 13:15:17 -04:00
|
|
|
#include "gthreadprivate.h"
|
W32: add std stream redirection envvar options
This commit adds two W32-only environmental variable checks:
* G_WIN32_ALLOC_CONSOLE, if set to 1, will force glib to create
a new console if the process has no console by itself.
This option is for GUI apps that are launched from GUI
processes, in which case there's no console anywhere near them.
* G_WIN32_ATTACH_CONSOLE, if set to a comma-separated list of
standard stream names (stdint, stdout, stderr), will reopen
a given std stream and tie it to the console (using existing console
or parent console).
This works either with the other option (to create a console),
or if the app is launched from a console process (often the
case for developers).
The redirection is done with freopen(), dup() and dup2().
If everything goes well, C file descriptors 0, 1 or 2 will
be bound to stdin, stdout and stderr respectively (only for
streams listed in the envrionmental variable), and so will
be stdio streams by the same names.
With these it's possible to see the output of g_log*() functions
when running GTK4 applications, which are linked as GUI applications,
and thus do not get a console by default.
https://bugzilla.gnome.org/show_bug.cgi?id=790857
Fixes issue #1304
2017-11-26 18:27:51 +00:00
|
|
|
#include "glib-init.h"
|
1999-11-01 20:46:44 +00:00
|
|
|
|
2001-03-09 21:31:21 +00:00
|
|
|
#ifdef G_WITH_CYGWIN
|
|
|
|
#include <sys/cygwin.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef G_WITH_CYGWIN
|
|
|
|
|
|
|
|
gint
|
1999-11-01 20:46:44 +00:00
|
|
|
g_win32_ftruncate (gint fd,
|
|
|
|
guint size)
|
|
|
|
{
|
2004-09-15 19:12:19 +00:00
|
|
|
return _chsize (fd, size);
|
1999-11-01 20:46:44 +00:00
|
|
|
}
|
|
|
|
|
2001-03-09 21:31:21 +00:00
|
|
|
#endif
|
1999-11-01 20:46:44 +00:00
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
/**
|
|
|
|
* g_win32_getlocale:
|
|
|
|
*
|
2004-10-31 16:31:41 +00:00
|
|
|
* The setlocale() function in the Microsoft C library uses locale
|
|
|
|
* names of the form "English_United States.1252" etc. We want the
|
|
|
|
* UNIXish standard form "en_US", "zh_TW" etc. This function gets the
|
|
|
|
* current thread locale from Windows - without any encoding info -
|
|
|
|
* and returns it as a string of the above form for use in forming
|
|
|
|
* file names etc. The returned string should be deallocated with
|
|
|
|
* g_free().
|
2001-04-16 20:05:25 +00:00
|
|
|
*
|
2001-10-01 18:54:27 +00:00
|
|
|
* Returns: newly-allocated locale name.
|
2001-10-03 20:19:13 +00:00
|
|
|
**/
|
2001-01-17 21:37:32 +00:00
|
|
|
|
2007-01-15 01:13:57 +00:00
|
|
|
#ifndef SUBLANG_SERBIAN_LATIN_BA
|
|
|
|
#define SUBLANG_SERBIAN_LATIN_BA 0x06
|
2004-04-10 03:43:39 +00:00
|
|
|
#endif
|
|
|
|
|
1999-11-01 20:46:44 +00:00
|
|
|
gchar *
|
|
|
|
g_win32_getlocale (void)
|
|
|
|
{
|
2018-08-15 22:25:08 +02:00
|
|
|
gchar *result;
|
1999-11-08 09:49:10 +00:00
|
|
|
LCID lcid;
|
When the sublangid is SUBLANG_DEFAULT, return the locale of the language's
2001-09-24 Bruno Haible <haible@clisp.cons.org>
* glib/gwin32.c (g_win32_getlocale): When the sublangid is
SUBLANG_DEFAULT, return the locale of the language's main country,
not a country-neutral locale. E.g. "en_US" instead of "en". Add
handling of LANG_SORBIAN. Fix typo for SUBLANG_CHINESE_SIMPLIFIED
(China == CN, CH == Switzerland). Ignore empty environment
variable values.
2001-09-28 Tor Lillqvist <tml@iki.fi>
* glib/makefile.{mingw,msc}.in: Add localcharset.o. Just copy the
source file from libcharset and compile in this directory.
* glib/giochannel.c: Mark rest of g_set_error strings for
translation, too.
* glib/giowin32.c: Add some debugging output functions, call them
when debugging.
(create_events, g_io_win32_msg_write): Free message fetched with
g_win32_error_message ().
(g_io_win32_check): Indentation fixes.
(g_io_win32_fd_read,g_io_win32_sock_read): Don't always return
G_IO_STATUS_NORMAL. Do return G_IO_STATUS_EOF if we got 0 bytes,
like on Unix. This helps making the test programs run
successfully.
* glib/gmain.c (g_poll): Return the code ifdeffed out with
TEST_WITHOUT_THIS. Can't remember why it was ifdeffed out. Things
seem to work as previously with the code in place. Especially
spawn-test didn't work with the code ifdeffed out (Bug#61067).
* glib/grand.c (g_rand_new): Don't try to use /dev/urandom unless
on Unix.
* glib/gspawn-win32-helper.c (WinMain): Remove Sleep(10000)
accidentally left in.
gthread:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* gthread-win32.c: Use an extra level of indirection for GMutex.
It is now a pointer either to a pointer to a CRITICAL_SECTION
struct, or to a mutex HANDLE. This is needed in case the user
defines G_ERRORCHECK_MUTEXES. G_MUTEX_SIZE must correctly reflect
the size of *GMutex, but this used to vary depending on whether we
at run-time chose to use CRITICAL_SECTIONs or mutexes.
(g_mutex_free_win32_cs_impl, g_cond_free_win32_impl): Call
DeleteCriticalSection() when done with it.
* gthread-impl.c (g_thread_init_with_errorcheck_mutexes): Call
g_thread_impl_init() before accessing
g_thread_functions_for_glib_use_default, as the
g_thread_impl_init() function might modify it.
po:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* POTFILES.in: Add iochannel.c and giowin32.c.
* sv.po: Remove a bogus fuzziness indicator.
2001-09-27 22:07:00 +00:00
|
|
|
LANGID langid;
|
2020-07-23 13:20:39 +05:30
|
|
|
const gchar *ev;
|
1999-11-01 20:46:44 +00:00
|
|
|
gint primary, sub;
|
2018-08-15 22:25:08 +02:00
|
|
|
WCHAR iso639[10];
|
|
|
|
gchar *iso639_utf8;
|
|
|
|
WCHAR iso3166[10];
|
|
|
|
gchar *iso3166_utf8;
|
2007-01-15 01:13:57 +00:00
|
|
|
const gchar *script = NULL;
|
1999-11-01 20:46:44 +00:00
|
|
|
|
When the sublangid is SUBLANG_DEFAULT, return the locale of the language's
2001-09-24 Bruno Haible <haible@clisp.cons.org>
* glib/gwin32.c (g_win32_getlocale): When the sublangid is
SUBLANG_DEFAULT, return the locale of the language's main country,
not a country-neutral locale. E.g. "en_US" instead of "en". Add
handling of LANG_SORBIAN. Fix typo for SUBLANG_CHINESE_SIMPLIFIED
(China == CN, CH == Switzerland). Ignore empty environment
variable values.
2001-09-28 Tor Lillqvist <tml@iki.fi>
* glib/makefile.{mingw,msc}.in: Add localcharset.o. Just copy the
source file from libcharset and compile in this directory.
* glib/giochannel.c: Mark rest of g_set_error strings for
translation, too.
* glib/giowin32.c: Add some debugging output functions, call them
when debugging.
(create_events, g_io_win32_msg_write): Free message fetched with
g_win32_error_message ().
(g_io_win32_check): Indentation fixes.
(g_io_win32_fd_read,g_io_win32_sock_read): Don't always return
G_IO_STATUS_NORMAL. Do return G_IO_STATUS_EOF if we got 0 bytes,
like on Unix. This helps making the test programs run
successfully.
* glib/gmain.c (g_poll): Return the code ifdeffed out with
TEST_WITHOUT_THIS. Can't remember why it was ifdeffed out. Things
seem to work as previously with the code in place. Especially
spawn-test didn't work with the code ifdeffed out (Bug#61067).
* glib/grand.c (g_rand_new): Don't try to use /dev/urandom unless
on Unix.
* glib/gspawn-win32-helper.c (WinMain): Remove Sleep(10000)
accidentally left in.
gthread:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* gthread-win32.c: Use an extra level of indirection for GMutex.
It is now a pointer either to a pointer to a CRITICAL_SECTION
struct, or to a mutex HANDLE. This is needed in case the user
defines G_ERRORCHECK_MUTEXES. G_MUTEX_SIZE must correctly reflect
the size of *GMutex, but this used to vary depending on whether we
at run-time chose to use CRITICAL_SECTIONs or mutexes.
(g_mutex_free_win32_cs_impl, g_cond_free_win32_impl): Call
DeleteCriticalSection() when done with it.
* gthread-impl.c (g_thread_init_with_errorcheck_mutexes): Call
g_thread_impl_init() before accessing
g_thread_functions_for_glib_use_default, as the
g_thread_impl_init() function might modify it.
po:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* POTFILES.in: Add iochannel.c and giowin32.c.
* sv.po: Remove a bogus fuzziness indicator.
2001-09-27 22:07:00 +00:00
|
|
|
/* Let the user override the system settings through environment
|
2007-01-15 01:13:57 +00:00
|
|
|
* variables, as on POSIX systems. Note that in GTK+ applications
|
|
|
|
* since GTK+ 2.10.7 setting either LC_ALL or LANG also sets the
|
|
|
|
* Win32 locale and C library locale through code in gtkmain.c.
|
|
|
|
*/
|
2020-07-23 13:20:39 +05:30
|
|
|
if (((ev = g_getenv ("LC_ALL")) != NULL && ev[0] != '\0')
|
|
|
|
|| ((ev = g_getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0')
|
|
|
|
|| ((ev = g_getenv ("LANG")) != NULL && ev[0] != '\0'))
|
1999-11-08 09:49:10 +00:00
|
|
|
return g_strdup (ev);
|
|
|
|
|
|
|
|
lcid = GetThreadLocale ();
|
When the sublangid is SUBLANG_DEFAULT, return the locale of the language's
2001-09-24 Bruno Haible <haible@clisp.cons.org>
* glib/gwin32.c (g_win32_getlocale): When the sublangid is
SUBLANG_DEFAULT, return the locale of the language's main country,
not a country-neutral locale. E.g. "en_US" instead of "en". Add
handling of LANG_SORBIAN. Fix typo for SUBLANG_CHINESE_SIMPLIFIED
(China == CN, CH == Switzerland). Ignore empty environment
variable values.
2001-09-28 Tor Lillqvist <tml@iki.fi>
* glib/makefile.{mingw,msc}.in: Add localcharset.o. Just copy the
source file from libcharset and compile in this directory.
* glib/giochannel.c: Mark rest of g_set_error strings for
translation, too.
* glib/giowin32.c: Add some debugging output functions, call them
when debugging.
(create_events, g_io_win32_msg_write): Free message fetched with
g_win32_error_message ().
(g_io_win32_check): Indentation fixes.
(g_io_win32_fd_read,g_io_win32_sock_read): Don't always return
G_IO_STATUS_NORMAL. Do return G_IO_STATUS_EOF if we got 0 bytes,
like on Unix. This helps making the test programs run
successfully.
* glib/gmain.c (g_poll): Return the code ifdeffed out with
TEST_WITHOUT_THIS. Can't remember why it was ifdeffed out. Things
seem to work as previously with the code in place. Especially
spawn-test didn't work with the code ifdeffed out (Bug#61067).
* glib/grand.c (g_rand_new): Don't try to use /dev/urandom unless
on Unix.
* glib/gspawn-win32-helper.c (WinMain): Remove Sleep(10000)
accidentally left in.
gthread:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* gthread-win32.c: Use an extra level of indirection for GMutex.
It is now a pointer either to a pointer to a CRITICAL_SECTION
struct, or to a mutex HANDLE. This is needed in case the user
defines G_ERRORCHECK_MUTEXES. G_MUTEX_SIZE must correctly reflect
the size of *GMutex, but this used to vary depending on whether we
at run-time chose to use CRITICAL_SECTIONs or mutexes.
(g_mutex_free_win32_cs_impl, g_cond_free_win32_impl): Call
DeleteCriticalSection() when done with it.
* gthread-impl.c (g_thread_init_with_errorcheck_mutexes): Call
g_thread_impl_init() before accessing
g_thread_functions_for_glib_use_default, as the
g_thread_impl_init() function might modify it.
po:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* POTFILES.in: Add iochannel.c and giowin32.c.
* sv.po: Remove a bogus fuzziness indicator.
2001-09-27 22:07:00 +00:00
|
|
|
|
2018-08-15 22:25:08 +02:00
|
|
|
if (!GetLocaleInfoW (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) ||
|
|
|
|
!GetLocaleInfoW (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
|
2007-01-15 01:13:57 +00:00
|
|
|
return g_strdup ("C");
|
|
|
|
|
When the sublangid is SUBLANG_DEFAULT, return the locale of the language's
2001-09-24 Bruno Haible <haible@clisp.cons.org>
* glib/gwin32.c (g_win32_getlocale): When the sublangid is
SUBLANG_DEFAULT, return the locale of the language's main country,
not a country-neutral locale. E.g. "en_US" instead of "en". Add
handling of LANG_SORBIAN. Fix typo for SUBLANG_CHINESE_SIMPLIFIED
(China == CN, CH == Switzerland). Ignore empty environment
variable values.
2001-09-28 Tor Lillqvist <tml@iki.fi>
* glib/makefile.{mingw,msc}.in: Add localcharset.o. Just copy the
source file from libcharset and compile in this directory.
* glib/giochannel.c: Mark rest of g_set_error strings for
translation, too.
* glib/giowin32.c: Add some debugging output functions, call them
when debugging.
(create_events, g_io_win32_msg_write): Free message fetched with
g_win32_error_message ().
(g_io_win32_check): Indentation fixes.
(g_io_win32_fd_read,g_io_win32_sock_read): Don't always return
G_IO_STATUS_NORMAL. Do return G_IO_STATUS_EOF if we got 0 bytes,
like on Unix. This helps making the test programs run
successfully.
* glib/gmain.c (g_poll): Return the code ifdeffed out with
TEST_WITHOUT_THIS. Can't remember why it was ifdeffed out. Things
seem to work as previously with the code in place. Especially
spawn-test didn't work with the code ifdeffed out (Bug#61067).
* glib/grand.c (g_rand_new): Don't try to use /dev/urandom unless
on Unix.
* glib/gspawn-win32-helper.c (WinMain): Remove Sleep(10000)
accidentally left in.
gthread:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* gthread-win32.c: Use an extra level of indirection for GMutex.
It is now a pointer either to a pointer to a CRITICAL_SECTION
struct, or to a mutex HANDLE. This is needed in case the user
defines G_ERRORCHECK_MUTEXES. G_MUTEX_SIZE must correctly reflect
the size of *GMutex, but this used to vary depending on whether we
at run-time chose to use CRITICAL_SECTIONs or mutexes.
(g_mutex_free_win32_cs_impl, g_cond_free_win32_impl): Call
DeleteCriticalSection() when done with it.
* gthread-impl.c (g_thread_init_with_errorcheck_mutexes): Call
g_thread_impl_init() before accessing
g_thread_functions_for_glib_use_default, as the
g_thread_impl_init() function might modify it.
po:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* POTFILES.in: Add iochannel.c and giowin32.c.
* sv.po: Remove a bogus fuzziness indicator.
2001-09-27 22:07:00 +00:00
|
|
|
/* Strip off the sorting rules, keep only the language part. */
|
|
|
|
langid = LANGIDFROMLCID (lcid);
|
|
|
|
|
|
|
|
/* Split into language and territory part. */
|
|
|
|
primary = PRIMARYLANGID (langid);
|
|
|
|
sub = SUBLANGID (langid);
|
2007-01-15 01:13:57 +00:00
|
|
|
|
|
|
|
/* Handle special cases */
|
1999-11-01 20:46:44 +00:00
|
|
|
switch (primary)
|
|
|
|
{
|
When the sublangid is SUBLANG_DEFAULT, return the locale of the language's
2001-09-24 Bruno Haible <haible@clisp.cons.org>
* glib/gwin32.c (g_win32_getlocale): When the sublangid is
SUBLANG_DEFAULT, return the locale of the language's main country,
not a country-neutral locale. E.g. "en_US" instead of "en". Add
handling of LANG_SORBIAN. Fix typo for SUBLANG_CHINESE_SIMPLIFIED
(China == CN, CH == Switzerland). Ignore empty environment
variable values.
2001-09-28 Tor Lillqvist <tml@iki.fi>
* glib/makefile.{mingw,msc}.in: Add localcharset.o. Just copy the
source file from libcharset and compile in this directory.
* glib/giochannel.c: Mark rest of g_set_error strings for
translation, too.
* glib/giowin32.c: Add some debugging output functions, call them
when debugging.
(create_events, g_io_win32_msg_write): Free message fetched with
g_win32_error_message ().
(g_io_win32_check): Indentation fixes.
(g_io_win32_fd_read,g_io_win32_sock_read): Don't always return
G_IO_STATUS_NORMAL. Do return G_IO_STATUS_EOF if we got 0 bytes,
like on Unix. This helps making the test programs run
successfully.
* glib/gmain.c (g_poll): Return the code ifdeffed out with
TEST_WITHOUT_THIS. Can't remember why it was ifdeffed out. Things
seem to work as previously with the code in place. Especially
spawn-test didn't work with the code ifdeffed out (Bug#61067).
* glib/grand.c (g_rand_new): Don't try to use /dev/urandom unless
on Unix.
* glib/gspawn-win32-helper.c (WinMain): Remove Sleep(10000)
accidentally left in.
gthread:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* gthread-win32.c: Use an extra level of indirection for GMutex.
It is now a pointer either to a pointer to a CRITICAL_SECTION
struct, or to a mutex HANDLE. This is needed in case the user
defines G_ERRORCHECK_MUTEXES. G_MUTEX_SIZE must correctly reflect
the size of *GMutex, but this used to vary depending on whether we
at run-time chose to use CRITICAL_SECTIONs or mutexes.
(g_mutex_free_win32_cs_impl, g_cond_free_win32_impl): Call
DeleteCriticalSection() when done with it.
* gthread-impl.c (g_thread_init_with_errorcheck_mutexes): Call
g_thread_impl_init() before accessing
g_thread_functions_for_glib_use_default, as the
g_thread_impl_init() function might modify it.
po:
2001-09-28 Tor Lillqvist <tml@iki.fi>
* POTFILES.in: Add iochannel.c and giowin32.c.
* sv.po: Remove a bogus fuzziness indicator.
2001-09-27 22:07:00 +00:00
|
|
|
case LANG_AZERI:
|
1999-11-01 20:46:44 +00:00
|
|
|
switch (sub)
|
|
|
|
{
|
2007-01-15 01:13:57 +00:00
|
|
|
case SUBLANG_AZERI_LATIN:
|
|
|
|
script = "@Latn";
|
|
|
|
break;
|
|
|
|
case SUBLANG_AZERI_CYRILLIC:
|
|
|
|
script = "@Cyrl";
|
|
|
|
break;
|
2004-04-10 03:43:39 +00:00
|
|
|
}
|
|
|
|
break;
|
2007-01-15 01:13:57 +00:00
|
|
|
case LANG_SERBIAN: /* LANG_CROATIAN == LANG_SERBIAN */
|
2004-04-10 03:43:39 +00:00
|
|
|
switch (sub)
|
|
|
|
{
|
2007-01-15 01:13:57 +00:00
|
|
|
case SUBLANG_SERBIAN_LATIN:
|
|
|
|
case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */
|
|
|
|
script = "@Latn";
|
|
|
|
break;
|
1999-11-01 20:46:44 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LANG_UZBEK:
|
|
|
|
switch (sub)
|
|
|
|
{
|
2007-01-15 01:13:57 +00:00
|
|
|
case SUBLANG_UZBEK_LATIN:
|
|
|
|
script = "@Latn";
|
|
|
|
break;
|
|
|
|
case SUBLANG_UZBEK_CYRILLIC:
|
|
|
|
script = "@Cyrl";
|
|
|
|
break;
|
1999-11-01 20:46:44 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2018-08-15 22:25:08 +02:00
|
|
|
|
|
|
|
iso639_utf8 = g_utf16_to_utf8 (iso639, -1, NULL, NULL, NULL);
|
|
|
|
iso3166_utf8 = g_utf16_to_utf8 (iso3166, -1, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
result = g_strconcat (iso639_utf8, "_", iso3166_utf8, script, NULL);
|
|
|
|
|
|
|
|
g_free (iso3166_utf8);
|
|
|
|
g_free (iso639_utf8);
|
|
|
|
|
|
|
|
return result;
|
1999-11-01 20:46:44 +00:00
|
|
|
}
|
1999-11-08 09:49:10 +00:00
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
/**
|
|
|
|
* g_win32_error_message:
|
2001-10-01 18:54:27 +00:00
|
|
|
* @error: error code.
|
2001-01-17 21:37:32 +00:00
|
|
|
*
|
2014-03-25 13:52:45 -04:00
|
|
|
* Translate a Win32 error code (as returned by GetLastError() or
|
|
|
|
* WSAGetLastError()) into the corresponding message. The message is
|
|
|
|
* either language neutral, or in the thread's language, or the user's
|
|
|
|
* language, the system's language, or US English (see docs for
|
|
|
|
* FormatMessage()). The returned string is in UTF-8. It should be
|
|
|
|
* deallocated with g_free().
|
2001-04-16 20:05:25 +00:00
|
|
|
*
|
2001-10-01 18:54:27 +00:00
|
|
|
* Returns: newly-allocated error message
|
2001-10-03 20:19:13 +00:00
|
|
|
**/
|
1999-11-08 09:49:10 +00:00
|
|
|
gchar *
|
|
|
|
g_win32_error_message (gint error)
|
|
|
|
{
|
|
|
|
gchar *retval;
|
2006-08-29 22:45:00 +00:00
|
|
|
wchar_t *msg = NULL;
|
2016-02-17 17:52:31 +01:00
|
|
|
size_t nchars;
|
2006-08-29 22:45:00 +00:00
|
|
|
|
|
|
|
FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
|
|
|FORMAT_MESSAGE_IGNORE_INSERTS
|
|
|
|
|FORMAT_MESSAGE_FROM_SYSTEM,
|
|
|
|
NULL, error, 0,
|
|
|
|
(LPWSTR) &msg, 0, NULL);
|
|
|
|
if (msg != NULL)
|
2004-09-15 19:12:19 +00:00
|
|
|
{
|
2006-08-29 22:45:00 +00:00
|
|
|
nchars = wcslen (msg);
|
2016-02-17 17:52:59 +01:00
|
|
|
|
2016-02-17 17:56:03 +01:00
|
|
|
if (nchars >= 2 && msg[nchars-1] == L'\n' && msg[nchars-2] == L'\r')
|
|
|
|
msg[nchars-2] = L'\0';
|
2016-02-17 17:52:59 +01:00
|
|
|
|
2006-08-29 22:45:00 +00:00
|
|
|
retval = g_utf16_to_utf8 (msg, -1, NULL, NULL, NULL);
|
2016-02-17 17:52:59 +01:00
|
|
|
|
2006-08-29 22:45:00 +00:00
|
|
|
LocalFree (msg);
|
2004-09-15 19:12:19 +00:00
|
|
|
}
|
|
|
|
else
|
2006-08-29 22:45:00 +00:00
|
|
|
retval = g_strdup ("");
|
1999-11-08 09:49:10 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2001-01-16 22:06:23 +00:00
|
|
|
|
2008-02-24 00:38:01 +00:00
|
|
|
/**
|
|
|
|
* g_win32_get_package_installation_directory_of_module:
|
2016-10-28 18:29:02 -07:00
|
|
|
* @hmodule: (nullable): The Win32 handle for a DLL loaded into the current process, or %NULL
|
2008-02-24 00:38:01 +00:00
|
|
|
*
|
|
|
|
* This function tries to determine the installation directory of a
|
|
|
|
* software package based on the location of a DLL of the software
|
|
|
|
* package.
|
|
|
|
*
|
|
|
|
* @hmodule should be the handle of a loaded DLL or %NULL. The
|
|
|
|
* function looks up the directory that DLL was loaded from. If
|
|
|
|
* @hmodule is NULL, the directory the main executable of the current
|
|
|
|
* process is looked up. If that directory's last component is "bin"
|
|
|
|
* or "lib", its parent directory is returned, otherwise the directory
|
|
|
|
* itself.
|
|
|
|
*
|
|
|
|
* It thus makes sense to pass only the handle to a "public" DLL of a
|
|
|
|
* software package to this function, as such DLLs typically are known
|
|
|
|
* to be installed in a "bin" or occasionally "lib" subfolder of the
|
|
|
|
* installation folder. DLLs that are of the dynamically loaded module
|
|
|
|
* or plugin variety are often located in more private locations
|
|
|
|
* deeper down in the tree, from which it is impossible for GLib to
|
|
|
|
* deduce the root of the package installation.
|
|
|
|
*
|
|
|
|
* The typical use case for this function is to have a DllMain() that
|
|
|
|
* saves the handle for the DLL. Then when code in the DLL needs to
|
|
|
|
* construct names of files in the installation tree it calls this
|
|
|
|
* function passing the DLL handle.
|
|
|
|
*
|
|
|
|
* Returns: a string containing the guessed installation directory for
|
|
|
|
* the software package @hmodule is from. The string is in the GLib
|
|
|
|
* file name encoding, i.e. UTF-8. The return value should be freed
|
|
|
|
* with g_free() when not needed any longer. If the function fails
|
|
|
|
* %NULL is returned.
|
2008-02-25 19:32:42 +00:00
|
|
|
*
|
|
|
|
* Since: 2.16
|
2008-02-24 00:38:01 +00:00
|
|
|
*/
|
|
|
|
gchar *
|
|
|
|
g_win32_get_package_installation_directory_of_module (gpointer hmodule)
|
|
|
|
{
|
2014-07-29 18:59:21 +02:00
|
|
|
gchar *filename;
|
2008-02-24 00:38:01 +00:00
|
|
|
gchar *retval;
|
|
|
|
gchar *p;
|
|
|
|
wchar_t wc_fn[MAX_PATH];
|
|
|
|
|
2014-07-29 18:59:21 +02:00
|
|
|
/* NOTE: it relies that GetModuleFileNameW returns only canonical paths */
|
2008-02-24 00:38:01 +00:00
|
|
|
if (!GetModuleFileNameW (hmodule, wc_fn, MAX_PATH))
|
|
|
|
return NULL;
|
|
|
|
|
2014-07-29 18:59:21 +02:00
|
|
|
filename = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL);
|
2008-02-24 00:38:01 +00:00
|
|
|
|
2014-07-29 18:59:21 +02:00
|
|
|
if ((p = strrchr (filename, G_DIR_SEPARATOR)) != NULL)
|
2008-02-24 00:38:01 +00:00
|
|
|
*p = '\0';
|
|
|
|
|
2014-07-29 18:59:21 +02:00
|
|
|
retval = g_strdup (filename);
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
p = strrchr (retval, G_DIR_SEPARATOR);
|
|
|
|
if (p == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
if (g_ascii_strcasecmp (p + 1, "bin") == 0 ||
|
|
|
|
g_ascii_strcasecmp (p + 1, "lib") == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (p != NULL);
|
|
|
|
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
g_free (retval);
|
|
|
|
retval = filename;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
g_free (filename);
|
2008-02-24 00:38:01 +00:00
|
|
|
|
|
|
|
#ifdef G_WITH_CYGWIN
|
|
|
|
/* In Cygwin we need to have POSIX paths */
|
|
|
|
{
|
|
|
|
gchar tmp[MAX_PATH];
|
|
|
|
|
2008-03-31 13:41:03 +00:00
|
|
|
cygwin_conv_to_posix_path (retval, tmp);
|
|
|
|
g_free (retval);
|
|
|
|
retval = g_strdup (tmp);
|
2008-02-24 00:38:01 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
static gchar *
|
2006-12-27 14:50:17 +00:00
|
|
|
get_package_directory_from_module (const gchar *module_name)
|
2001-01-16 22:06:23 +00:00
|
|
|
{
|
2001-01-17 21:37:32 +00:00
|
|
|
static GHashTable *module_dirs = NULL;
|
2001-09-29 23:19:24 +00:00
|
|
|
G_LOCK_DEFINE_STATIC (module_dirs);
|
2001-01-17 21:37:32 +00:00
|
|
|
HMODULE hmodule = NULL;
|
2001-02-10 00:17:06 +00:00
|
|
|
gchar *fn;
|
2001-01-17 21:37:32 +00:00
|
|
|
|
2001-09-29 23:19:24 +00:00
|
|
|
G_LOCK (module_dirs);
|
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
if (module_dirs == NULL)
|
|
|
|
module_dirs = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
|
|
2008-02-24 00:38:01 +00:00
|
|
|
fn = g_hash_table_lookup (module_dirs, module_name ? module_name : "");
|
2001-01-17 21:37:32 +00:00
|
|
|
|
2008-02-24 00:38:01 +00:00
|
|
|
if (fn)
|
2001-09-29 23:19:24 +00:00
|
|
|
{
|
|
|
|
G_UNLOCK (module_dirs);
|
2008-02-24 00:38:01 +00:00
|
|
|
return g_strdup (fn);
|
2001-09-29 23:19:24 +00:00
|
|
|
}
|
2001-01-17 21:37:32 +00:00
|
|
|
|
|
|
|
if (module_name)
|
|
|
|
{
|
2006-08-29 22:45:00 +00:00
|
|
|
wchar_t *wc_module_name = g_utf8_to_utf16 (module_name, -1, NULL, NULL, NULL);
|
|
|
|
hmodule = GetModuleHandleW (wc_module_name);
|
|
|
|
g_free (wc_module_name);
|
|
|
|
|
2009-01-09 10:39:00 +00:00
|
|
|
if (!hmodule)
|
|
|
|
{
|
|
|
|
G_UNLOCK (module_dirs);
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-01-17 21:37:32 +00:00
|
|
|
}
|
|
|
|
|
2008-02-24 00:38:01 +00:00
|
|
|
fn = g_win32_get_package_installation_directory_of_module (hmodule);
|
2001-03-09 21:31:21 +00:00
|
|
|
|
2008-02-24 00:38:01 +00:00
|
|
|
if (fn == NULL)
|
2009-01-09 10:37:31 +00:00
|
|
|
{
|
|
|
|
G_UNLOCK (module_dirs);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-02-24 00:38:01 +00:00
|
|
|
|
2006-10-07 19:27:17 +00:00
|
|
|
g_hash_table_insert (module_dirs, module_name ? g_strdup (module_name) : "", fn);
|
2001-01-17 21:37:32 +00:00
|
|
|
|
2001-09-29 23:19:24 +00:00
|
|
|
G_UNLOCK (module_dirs);
|
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
return g_strdup (fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_win32_get_package_installation_directory:
|
2016-10-28 18:29:02 -07:00
|
|
|
* @package: (nullable): You should pass %NULL for this.
|
|
|
|
* @dll_name: (nullable): The name of a DLL that a package provides in UTF-8, or %NULL.
|
2001-01-17 21:37:32 +00:00
|
|
|
*
|
|
|
|
* Try to determine the installation directory for a software package.
|
|
|
|
*
|
2008-09-13 20:23:17 +00:00
|
|
|
* This function is deprecated. Use
|
2008-02-24 00:38:01 +00:00
|
|
|
* g_win32_get_package_installation_directory_of_module() instead.
|
|
|
|
*
|
2008-09-13 20:23:17 +00:00
|
|
|
* The use of @package is deprecated. You should always pass %NULL. A
|
|
|
|
* warning is printed if non-NULL is passed as @package.
|
2008-02-13 11:59:14 +00:00
|
|
|
*
|
2008-02-24 00:38:01 +00:00
|
|
|
* The original intended use of @package was for a short identifier of
|
2008-02-13 11:59:14 +00:00
|
|
|
* the package, typically the same identifier as used for
|
2014-02-06 08:04:52 -05:00
|
|
|
* `GETTEXT_PACKAGE` in software configured using GNU
|
2007-06-11 07:59:33 +00:00
|
|
|
* autotools. The function first looks in the Windows Registry for the
|
2014-02-09 02:07:26 -05:00
|
|
|
* value `#InstallationDirectory` in the key
|
|
|
|
* `#HKLM\Software\@package`, and if that value
|
2001-10-01 18:54:27 +00:00
|
|
|
* exists and is a string, returns that.
|
2001-01-17 21:37:32 +00:00
|
|
|
*
|
2007-06-11 07:59:33 +00:00
|
|
|
* It is strongly recommended that packagers of GLib-using libraries
|
|
|
|
* for Windows do not store installation paths in the Registry to be
|
|
|
|
* used by this function as that interfers with having several
|
2008-02-13 11:59:14 +00:00
|
|
|
* parallel installations of the library. Enabling multiple
|
|
|
|
* installations of different versions of some GLib-using library, or
|
|
|
|
* GLib itself, is desirable for various reasons.
|
2007-06-11 07:59:33 +00:00
|
|
|
*
|
2020-06-12 14:02:30 +01:00
|
|
|
* For this reason it is recommended to always pass %NULL as
|
2007-06-11 07:59:33 +00:00
|
|
|
* @package to this function, to avoid the temptation to use the
|
2008-09-13 20:23:17 +00:00
|
|
|
* Registry. In version 2.20 of GLib the @package parameter
|
2008-02-13 11:59:14 +00:00
|
|
|
* will be ignored and this function won't look in the Registry at all.
|
2007-06-11 07:59:33 +00:00
|
|
|
*
|
2001-10-01 18:54:27 +00:00
|
|
|
* If @package is %NULL, or the above value isn't found in the
|
|
|
|
* Registry, but @dll_name is non-%NULL, it should name a DLL loaded
|
2001-01-17 21:37:32 +00:00
|
|
|
* into the current process. Typically that would be the name of the
|
|
|
|
* DLL calling this function, looking for its installation
|
|
|
|
* directory. The function then asks Windows what directory that DLL
|
|
|
|
* was loaded from. If that directory's last component is "bin" or
|
|
|
|
* "lib", the parent directory is returned, otherwise the directory
|
|
|
|
* itself. If that DLL isn't loaded, the function proceeds as if
|
2001-10-01 18:54:27 +00:00
|
|
|
* @dll_name was %NULL.
|
2001-01-17 21:37:32 +00:00
|
|
|
*
|
2001-10-04 22:23:03 +00:00
|
|
|
* If both @package and @dll_name are %NULL, the directory from where
|
2005-04-27 09:50:09 +00:00
|
|
|
* the main executable of the process was loaded is used instead in
|
2001-01-17 21:37:32 +00:00
|
|
|
* the same way as above.
|
|
|
|
*
|
2004-11-24 18:07:26 +00:00
|
|
|
* Returns: a string containing the installation directory for
|
2008-02-24 00:38:01 +00:00
|
|
|
* @package. The string is in the GLib file name encoding,
|
|
|
|
* i.e. UTF-8. The return value should be freed with g_free() when not
|
|
|
|
* needed any longer. If the function fails %NULL is returned.
|
2008-09-13 20:23:17 +00:00
|
|
|
*
|
2009-12-28 02:04:01 +01:00
|
|
|
* Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to
|
2008-09-13 20:23:17 +00:00
|
|
|
* g_win32_get_package_installation_directory_of_module() instead.
|
2001-10-01 18:54:27 +00:00
|
|
|
**/
|
|
|
|
|
2017-03-28 08:03:14 +02:00
|
|
|
gchar *
|
|
|
|
g_win32_get_package_installation_directory (const gchar *package,
|
|
|
|
const gchar *dll_name)
|
2001-01-17 21:37:32 +00:00
|
|
|
{
|
|
|
|
gchar *result = NULL;
|
2001-01-16 22:06:23 +00:00
|
|
|
|
2008-09-13 20:23:17 +00:00
|
|
|
if (package != NULL)
|
|
|
|
g_warning ("Passing a non-NULL package to g_win32_get_package_installation_directory() is deprecated and it is ignored.");
|
2001-09-29 23:19:24 +00:00
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
if (dll_name != NULL)
|
|
|
|
result = get_package_directory_from_module (dll_name);
|
2001-01-16 22:06:23 +00:00
|
|
|
|
2001-01-17 21:37:32 +00:00
|
|
|
if (result == NULL)
|
|
|
|
result = get_package_directory_from_module (NULL);
|
2001-01-16 22:06:23 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2001-01-17 21:37:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* g_win32_get_package_installation_subdirectory:
|
2016-10-28 18:29:02 -07:00
|
|
|
* @package: (nullable): You should pass %NULL for this.
|
|
|
|
* @dll_name: (nullable): The name of a DLL that a package provides, in UTF-8, or %NULL.
|
2004-12-05 09:11:42 +00:00
|
|
|
* @subdir: A subdirectory of the package installation directory, also in UTF-8
|
2001-01-17 21:37:32 +00:00
|
|
|
*
|
2008-09-13 20:23:17 +00:00
|
|
|
* This function is deprecated. Use
|
|
|
|
* g_win32_get_package_installation_directory_of_module() and
|
|
|
|
* g_build_filename() instead.
|
2008-02-24 00:38:01 +00:00
|
|
|
*
|
2001-10-04 22:23:03 +00:00
|
|
|
* Returns a newly-allocated string containing the path of the
|
2001-10-01 18:54:27 +00:00
|
|
|
* subdirectory @subdir in the return value from calling
|
2001-01-17 21:37:32 +00:00
|
|
|
* g_win32_get_package_installation_directory() with the @package and
|
2007-06-11 07:59:33 +00:00
|
|
|
* @dll_name parameters. See the documentation for
|
|
|
|
* g_win32_get_package_installation_directory() for more details. In
|
2008-02-13 11:59:14 +00:00
|
|
|
* particular, note that it is deprecated to pass anything except NULL
|
|
|
|
* as @package.
|
2001-10-04 22:23:03 +00:00
|
|
|
*
|
2004-11-24 18:07:26 +00:00
|
|
|
* Returns: a string containing the complete path to @subdir inside
|
2004-12-05 09:11:42 +00:00
|
|
|
* the installation directory of @package. The returned string is in
|
2008-02-24 00:38:01 +00:00
|
|
|
* the GLib file name encoding, i.e. UTF-8. The return value should be
|
|
|
|
* freed with g_free() when no longer needed. If something goes wrong,
|
|
|
|
* %NULL is returned.
|
2008-09-13 20:23:17 +00:00
|
|
|
*
|
2009-12-28 02:04:01 +01:00
|
|
|
* Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to
|
2008-09-13 20:23:17 +00:00
|
|
|
* g_win32_get_package_installation_directory_of_module() instead, and
|
|
|
|
* then construct a subdirectory pathname with g_build_filename().
|
2001-10-03 20:19:13 +00:00
|
|
|
**/
|
2001-01-17 21:37:32 +00:00
|
|
|
|
|
|
|
gchar *
|
2006-12-27 14:50:17 +00:00
|
|
|
g_win32_get_package_installation_subdirectory (const gchar *package,
|
2017-03-28 08:03:14 +02:00
|
|
|
const gchar *dll_name,
|
|
|
|
const gchar *subdir)
|
2001-01-17 21:37:32 +00:00
|
|
|
{
|
|
|
|
gchar *prefix;
|
2004-04-25 22:51:46 +00:00
|
|
|
gchar *dirname;
|
2001-01-17 21:37:32 +00:00
|
|
|
|
2017-03-28 08:03:14 +02:00
|
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
2001-01-17 21:37:32 +00:00
|
|
|
prefix = g_win32_get_package_installation_directory (package, dll_name);
|
2017-03-28 08:03:14 +02:00
|
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
2001-01-17 21:37:32 +00:00
|
|
|
|
2004-04-25 22:51:46 +00:00
|
|
|
dirname = g_build_filename (prefix, subdir, NULL);
|
|
|
|
g_free (prefix);
|
|
|
|
|
|
|
|
return dirname;
|
2001-01-17 21:37:32 +00:00
|
|
|
}
|
2004-08-25 15:32:50 +00:00
|
|
|
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
/**
|
|
|
|
* g_win32_check_windows_version:
|
|
|
|
* @major: major version of Windows
|
|
|
|
* @minor: minor version of Windows
|
|
|
|
* @spver: Windows Service Pack Level, 0 if none
|
|
|
|
* @os_type: Type of Windows OS
|
|
|
|
*
|
|
|
|
* Returns whether the version of the Windows operating system the
|
|
|
|
* code is running on is at least the specified major, minor and
|
|
|
|
* service pack versions. See MSDN documentation for the Operating
|
|
|
|
* System Version. Software that needs even more detailed version and
|
|
|
|
* feature information should use the Win32 API VerifyVersionInfo()
|
|
|
|
* directly.
|
|
|
|
*
|
|
|
|
* Successive calls of this function can be used for enabling or
|
|
|
|
* disabling features at run-time for a range of Windows versions,
|
|
|
|
* as per the VerifyVersionInfo() API documentation.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the Windows Version is the same or greater than
|
|
|
|
* the specified major, minor and service pack versions, and
|
|
|
|
* whether the running Windows is a workstation or server edition
|
|
|
|
* of Windows, if specifically specified.
|
|
|
|
*
|
|
|
|
* Since: 2.44
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
g_win32_check_windows_version (const gint major,
|
|
|
|
const gint minor,
|
|
|
|
const gint spver,
|
|
|
|
const GWin32OSType os_type)
|
|
|
|
{
|
|
|
|
OSVERSIONINFOEXW osverinfo;
|
2015-10-07 20:00:50 +08:00
|
|
|
gboolean is_ver_checked = FALSE;
|
|
|
|
gboolean is_type_checked = FALSE;
|
|
|
|
|
|
|
|
#if WINAPI_FAMILY != MODERN_API_FAMILY
|
|
|
|
/* For non-modern UI Apps, use the LoadLibraryW()/GetProcAddress() thing */
|
2015-10-27 09:28:10 +08:00
|
|
|
typedef NTSTATUS (WINAPI fRtlGetVersion) (PRTL_OSVERSIONINFOEXW);
|
2015-10-07 20:00:50 +08:00
|
|
|
|
|
|
|
fRtlGetVersion *RtlGetVersion;
|
|
|
|
HMODULE hmodule;
|
|
|
|
#endif
|
|
|
|
/* We Only Support Checking for XP or later */
|
|
|
|
g_return_val_if_fail (major >= 5 && (major <=6 || major == 10), FALSE);
|
|
|
|
g_return_val_if_fail ((major >= 5 && minor >= 1) || major >= 6, FALSE);
|
|
|
|
|
|
|
|
/* Check for Service Pack Version >= 0 */
|
|
|
|
g_return_val_if_fail (spver >= 0, FALSE);
|
|
|
|
|
|
|
|
#if WINAPI_FAMILY != MODERN_API_FAMILY
|
|
|
|
hmodule = LoadLibraryW (L"ntdll.dll");
|
|
|
|
g_return_val_if_fail (hmodule != NULL, FALSE);
|
|
|
|
|
|
|
|
RtlGetVersion = (fRtlGetVersion *) GetProcAddress (hmodule, "RtlGetVersion");
|
|
|
|
g_return_val_if_fail (RtlGetVersion != NULL, FALSE);
|
|
|
|
#endif
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
|
|
|
|
memset (&osverinfo, 0, sizeof (OSVERSIONINFOEXW));
|
|
|
|
osverinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
|
2015-10-07 20:00:50 +08:00
|
|
|
RtlGetVersion (&osverinfo);
|
|
|
|
|
|
|
|
/* check the OS and Service Pack Versions */
|
|
|
|
if (osverinfo.dwMajorVersion > major)
|
|
|
|
is_ver_checked = TRUE;
|
|
|
|
else if (osverinfo.dwMajorVersion == major)
|
2016-01-28 15:55:11 +08:00
|
|
|
{
|
|
|
|
if (osverinfo.dwMinorVersion > minor)
|
|
|
|
is_ver_checked = TRUE;
|
|
|
|
else if (osverinfo.dwMinorVersion == minor)
|
|
|
|
if (osverinfo.wServicePackMajor >= spver)
|
2015-10-07 20:00:50 +08:00
|
|
|
is_ver_checked = TRUE;
|
2016-01-28 15:55:11 +08:00
|
|
|
}
|
2015-10-07 20:00:50 +08:00
|
|
|
|
|
|
|
/* Check OS Type */
|
|
|
|
if (is_ver_checked)
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
{
|
2015-10-07 20:00:50 +08:00
|
|
|
switch (os_type)
|
|
|
|
{
|
|
|
|
case G_WIN32_OS_ANY:
|
|
|
|
is_type_checked = TRUE;
|
|
|
|
break;
|
|
|
|
case G_WIN32_OS_WORKSTATION:
|
|
|
|
if (osverinfo.wProductType == VER_NT_WORKSTATION)
|
|
|
|
is_type_checked = TRUE;
|
|
|
|
break;
|
|
|
|
case G_WIN32_OS_SERVER:
|
|
|
|
if (osverinfo.wProductType == VER_NT_SERVER ||
|
|
|
|
osverinfo.wProductType == VER_NT_DOMAIN_CONTROLLER)
|
|
|
|
is_type_checked = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* shouldn't get here normally */
|
|
|
|
g_warning ("Invalid os_type specified");
|
|
|
|
break;
|
|
|
|
}
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
}
|
|
|
|
|
2015-10-07 20:00:50 +08:00
|
|
|
#if WINAPI_FAMILY != MODERN_API_FAMILY
|
|
|
|
FreeLibrary (hmodule);
|
|
|
|
#endif
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
|
2015-10-07 20:00:50 +08:00
|
|
|
return is_ver_checked && is_type_checked;
|
|
|
|
}
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
|
2004-10-31 16:31:41 +00:00
|
|
|
/**
|
|
|
|
* g_win32_get_windows_version:
|
|
|
|
*
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
* This function is deprecated. Use
|
|
|
|
* g_win32_check_windows_version() instead.
|
|
|
|
*
|
2004-10-31 16:31:41 +00:00
|
|
|
* Returns version information for the Windows operating system the
|
|
|
|
* code is running on. See MSDN documentation for the GetVersion()
|
|
|
|
* function. To summarize, the most significant bit is one on Win9x,
|
2006-08-29 22:45:00 +00:00
|
|
|
* and zero on NT-based systems. Since version 2.14, GLib works only
|
|
|
|
* on NT-based systems, so checking whether your are running on Win9x
|
|
|
|
* in your own software is moot. The least significant byte is 4 on
|
|
|
|
* Windows NT 4, and 5 on Windows XP. Software that needs really
|
2011-08-29 14:49:32 -04:00
|
|
|
* detailed version and feature information should use Win32 API like
|
2004-10-31 16:31:41 +00:00
|
|
|
* GetVersionEx() and VerifyVersionInfo().
|
|
|
|
*
|
|
|
|
* Returns: The version information.
|
gwin32: Add g_win32_check_windows_version() API
This adds a public API where one can use to see whether the running version
of Windows where the code is run is at least the specified version, service
pack level, and the type (non-server, server, any) of the running Windows
OS.
This API is done as:
-GetVersion()/GetVersionEx() changed in the way they work since Windows 8.1
[1][2], so a newer mechanism to check the version of the running Windows
operating system is needed. MSDN also states that GetVersion() might be
further changed or removed after Windows 8.1. This provides a wrapper for
VerfyVersionInfo() as well in GLib for most cases, which was recommended
in place of g_win32_get_windows_version() for more detailed Windows
version checking.
-Provides an OS-level functionality check, for those that we don't need to
venture into GetProcAddress(), and also to determine system API behavior
changes due to differences in OS versions.
Also added a note for the g_win32_get_windows_version() API that since the
behavior of GetVersion() which it uses, is changed since Windows 8.1, users
of the API should be aware.
[1]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
[2]:
http://msdn.microsoft.com/zh-tw/library/windows/desktop/ms724451%28v=vs.85%29.aspx
https://bugzilla.gnome.org/show_bug.cgi?id=741895
2015-01-26 11:11:48 +08:00
|
|
|
*
|
|
|
|
* Deprecated: 2.44: Be aware that for Windows 8.1 and Windows Server
|
|
|
|
* 2012 R2 and later, this will return 62 unless the application is
|
|
|
|
* manifested for Windows 8.1/Windows Server 2012 R2, for example.
|
|
|
|
* MSDN stated that GetVersion(), which is used here, is subject to
|
|
|
|
* further change or removal after Windows 8.1.
|
2004-10-31 16:31:41 +00:00
|
|
|
**/
|
2004-10-26 14:04:52 +00:00
|
|
|
guint
|
|
|
|
g_win32_get_windows_version (void)
|
|
|
|
{
|
2011-09-09 13:15:17 -04:00
|
|
|
static gsize windows_version;
|
|
|
|
|
|
|
|
if (g_once_init_enter (&windows_version))
|
|
|
|
g_once_init_leave (&windows_version, GetVersion ());
|
|
|
|
|
2004-10-26 14:04:52 +00:00
|
|
|
return windows_version;
|
2004-08-25 15:32:50 +00:00
|
|
|
}
|
2005-03-14 04:26:57 +00:00
|
|
|
|
2017-07-13 01:42:13 +00:00
|
|
|
/*
|
|
|
|
* Doesn't use gettext (and gconv), preventing recursive calls when
|
|
|
|
* g_win32_locale_filename_from_utf8() is called during
|
|
|
|
* gettext initialization.
|
|
|
|
*/
|
|
|
|
static gchar *
|
2019-09-16 16:06:38 +04:00
|
|
|
special_wchar_to_locale_encoding (wchar_t *wstring)
|
2017-07-13 01:42:13 +00:00
|
|
|
{
|
|
|
|
int sizeof_output;
|
|
|
|
int wctmb_result;
|
|
|
|
char *result;
|
|
|
|
BOOL not_representable = FALSE;
|
|
|
|
|
|
|
|
sizeof_output = WideCharToMultiByte (CP_ACP,
|
|
|
|
WC_NO_BEST_FIT_CHARS,
|
|
|
|
wstring, -1,
|
|
|
|
NULL, 0,
|
|
|
|
NULL,
|
|
|
|
¬_representable);
|
|
|
|
|
|
|
|
if (not_representable ||
|
|
|
|
sizeof_output == 0 ||
|
|
|
|
sizeof_output > MAX_PATH)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
result = g_malloc0 (sizeof_output + 1);
|
|
|
|
|
|
|
|
wctmb_result = WideCharToMultiByte (CP_ACP,
|
|
|
|
WC_NO_BEST_FIT_CHARS,
|
|
|
|
wstring, -1,
|
|
|
|
result, sizeof_output + 1,
|
|
|
|
NULL,
|
|
|
|
¬_representable);
|
|
|
|
|
|
|
|
if (wctmb_result == sizeof_output &&
|
|
|
|
not_representable == FALSE)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
g_free (result);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-04-27 09:50:09 +00:00
|
|
|
/**
|
|
|
|
* g_win32_locale_filename_from_utf8:
|
|
|
|
* @utf8filename: a UTF-8 encoded filename.
|
|
|
|
*
|
2005-05-01 21:57:49 +00:00
|
|
|
* Converts a filename from UTF-8 to the system codepage.
|
2005-04-27 09:50:09 +00:00
|
|
|
*
|
|
|
|
* On NT-based Windows, on NTFS file systems, file names are in
|
|
|
|
* Unicode. It is quite possible that Unicode file names contain
|
|
|
|
* characters not representable in the system codepage. (For instance,
|
|
|
|
* Greek or Cyrillic characters on Western European or US Windows
|
|
|
|
* installations, or various less common CJK characters on CJK Windows
|
|
|
|
* installations.)
|
|
|
|
*
|
|
|
|
* In such a case, and if the filename refers to an existing file, and
|
|
|
|
* the file system stores alternate short (8.3) names for directory
|
|
|
|
* entries, the short form of the filename is returned. Note that the
|
2005-06-09 10:46:21 +00:00
|
|
|
* "short" name might in fact be longer than the Unicode name if the
|
|
|
|
* Unicode name has very short pathname components containing
|
|
|
|
* non-ASCII characters. If no system codepage name for the file is
|
|
|
|
* possible, %NULL is returned.
|
2005-04-27 09:50:09 +00:00
|
|
|
*
|
2005-06-09 10:46:21 +00:00
|
|
|
* The return value is dynamically allocated and should be freed with
|
|
|
|
* g_free() when no longer needed.
|
2005-04-27 09:50:09 +00:00
|
|
|
*
|
2014-02-19 19:35:23 -05:00
|
|
|
* Returns: The converted filename, or %NULL on conversion
|
2005-04-27 09:50:09 +00:00
|
|
|
* failure and lack of short names.
|
|
|
|
*
|
2005-05-01 21:57:49 +00:00
|
|
|
* Since: 2.8
|
2005-04-27 09:50:09 +00:00
|
|
|
*/
|
|
|
|
gchar *
|
|
|
|
g_win32_locale_filename_from_utf8 (const gchar *utf8filename)
|
|
|
|
{
|
2017-07-13 01:42:13 +00:00
|
|
|
gchar *retval;
|
|
|
|
wchar_t *wname;
|
|
|
|
|
|
|
|
wname = g_utf8_to_utf16 (utf8filename, -1, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (wname == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2019-09-16 16:06:38 +04:00
|
|
|
retval = special_wchar_to_locale_encoding (wname);
|
2005-04-27 09:50:09 +00:00
|
|
|
|
2006-08-29 22:45:00 +00:00
|
|
|
if (retval == NULL)
|
2005-04-27 09:50:09 +00:00
|
|
|
{
|
2017-07-13 01:42:13 +00:00
|
|
|
/* Conversion failed, so check if there is a 8.3 version, and use that. */
|
|
|
|
wchar_t wshortname[MAX_PATH + 1];
|
|
|
|
|
|
|
|
if (GetShortPathNameW (wname, wshortname, G_N_ELEMENTS (wshortname)))
|
2019-09-16 16:06:38 +04:00
|
|
|
retval = special_wchar_to_locale_encoding (wshortname);
|
2005-04-27 09:50:09 +00:00
|
|
|
}
|
2017-07-13 01:42:13 +00:00
|
|
|
|
|
|
|
g_free (wname);
|
|
|
|
|
2005-04-27 09:50:09 +00:00
|
|
|
return retval;
|
|
|
|
}
|
2014-01-12 12:13:42 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* g_win32_get_command_line:
|
|
|
|
*
|
|
|
|
* Gets the command line arguments, on Windows, in the GLib filename
|
|
|
|
* encoding (ie: UTF-8).
|
|
|
|
*
|
|
|
|
* Normally, on Windows, the command line arguments are passed to main()
|
|
|
|
* in the system codepage encoding. This prevents passing filenames as
|
|
|
|
* arguments if the filenames contain characters that fall outside of
|
|
|
|
* this codepage. If such filenames are passed, then substitutions
|
|
|
|
* will occur (such as replacing some characters with '?').
|
|
|
|
*
|
|
|
|
* GLib's policy of using UTF-8 as a filename encoding on Windows was
|
|
|
|
* designed to localise the pain of dealing with filenames outside of
|
|
|
|
* the system codepage to one area: dealing with commandline arguments
|
|
|
|
* in main().
|
|
|
|
*
|
|
|
|
* As such, most GLib programs should ignore the value of argv passed to
|
|
|
|
* their main() function and call g_win32_get_command_line() instead.
|
|
|
|
* This will get the "full Unicode" commandline arguments using
|
|
|
|
* GetCommandLineW() and convert it to the GLib filename encoding (which
|
|
|
|
* is UTF-8 on Windows).
|
|
|
|
*
|
|
|
|
* The strings returned by this function are suitable for use with
|
|
|
|
* functions such as g_open() and g_file_new_for_commandline_arg() but
|
|
|
|
* are not suitable for use with g_option_context_parse(), which assumes
|
|
|
|
* that its input will be in the system codepage. The return value is
|
|
|
|
* suitable for use with g_option_context_parse_strv(), however, which
|
|
|
|
* is a better match anyway because it won't leak memory.
|
|
|
|
*
|
|
|
|
* Unlike argv, the returned value is a normal strv and can (and should)
|
|
|
|
* be freed with g_strfreev() when no longer needed.
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): the commandline arguments in the GLib
|
|
|
|
* filename encoding (ie: UTF-8)
|
|
|
|
*
|
|
|
|
* Since: 2.40
|
|
|
|
**/
|
|
|
|
gchar **
|
|
|
|
g_win32_get_command_line (void)
|
|
|
|
{
|
|
|
|
gchar **result;
|
|
|
|
LPWSTR *args;
|
|
|
|
gint i, n;
|
|
|
|
|
|
|
|
args = CommandLineToArgvW (GetCommandLineW(), &n);
|
|
|
|
|
|
|
|
result = g_new (gchar *, n + 1);
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
result[i] = g_utf16_to_utf8 (args[i], -1, NULL, NULL, NULL);
|
|
|
|
result[i] = NULL;
|
|
|
|
|
2014-12-20 18:59:15 -05:00
|
|
|
LocalFree (args);
|
2014-01-12 12:13:42 -05:00
|
|
|
return result;
|
|
|
|
}
|
2017-03-28 08:03:14 +02:00
|
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
|
|
|
/* Binary compatibility versions. Not for newly compiled code. */
|
|
|
|
|
|
|
|
_GLIB_EXTERN gchar *g_win32_get_package_installation_directory_utf8 (const gchar *package,
|
|
|
|
const gchar *dll_name);
|
|
|
|
|
|
|
|
_GLIB_EXTERN gchar *g_win32_get_package_installation_subdirectory_utf8 (const gchar *package,
|
|
|
|
const gchar *dll_name,
|
|
|
|
const gchar *subdir);
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
g_win32_get_package_installation_directory_utf8 (const gchar *package,
|
|
|
|
const gchar *dll_name)
|
|
|
|
{
|
|
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
|
|
|
return g_win32_get_package_installation_directory (package, dll_name);
|
|
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
g_win32_get_package_installation_subdirectory_utf8 (const gchar *package,
|
|
|
|
const gchar *dll_name,
|
|
|
|
const gchar *subdir)
|
|
|
|
{
|
|
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
|
|
|
return g_win32_get_package_installation_subdirectory (package,
|
|
|
|
dll_name,
|
|
|
|
subdir);
|
|
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
W32: add std stream redirection envvar options
This commit adds two W32-only environmental variable checks:
* G_WIN32_ALLOC_CONSOLE, if set to 1, will force glib to create
a new console if the process has no console by itself.
This option is for GUI apps that are launched from GUI
processes, in which case there's no console anywhere near them.
* G_WIN32_ATTACH_CONSOLE, if set to a comma-separated list of
standard stream names (stdint, stdout, stderr), will reopen
a given std stream and tie it to the console (using existing console
or parent console).
This works either with the other option (to create a console),
or if the app is launched from a console process (often the
case for developers).
The redirection is done with freopen(), dup() and dup2().
If everything goes well, C file descriptors 0, 1 or 2 will
be bound to stdin, stdout and stderr respectively (only for
streams listed in the envrionmental variable), and so will
be stdio streams by the same names.
With these it's possible to see the output of g_log*() functions
when running GTK4 applications, which are linked as GUI applications,
and thus do not get a console by default.
https://bugzilla.gnome.org/show_bug.cgi?id=790857
Fixes issue #1304
2017-11-26 18:27:51 +00:00
|
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
|
|
|
/* This function looks up two environment
|
|
|
|
* variables, G_WIN32_ALLOC_CONSOLE and G_WIN32_ATTACH_CONSOLE.
|
|
|
|
* G_WIN32_ALLOC_CONSOLE, if set to 1, makes the process
|
|
|
|
* call AllocConsole(). This is useful for binaries that
|
|
|
|
* are compiled to run without automatically-allocated console
|
|
|
|
* (like most GUI applications).
|
|
|
|
* G_WIN32_ATTACH_CONSOLE, if set to a comma-separated list
|
|
|
|
* of one or more strings "stdout", "stdin" and "stderr",
|
|
|
|
* makes the process reopen the corresponding standard streams
|
|
|
|
* to ensure that they are attached to the files that
|
|
|
|
* GetStdHandle() returns, which, hopefully, would be
|
|
|
|
* either a file handle or a console handle.
|
|
|
|
*
|
|
|
|
* This function is called automatically when glib DLL is
|
|
|
|
* attached to a process, from DllMain().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
g_console_win32_init (void)
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
gboolean redirect;
|
|
|
|
FILE *stream;
|
|
|
|
const gchar *stream_name;
|
|
|
|
DWORD std_handle_type;
|
|
|
|
int flags;
|
|
|
|
const gchar *mode;
|
|
|
|
}
|
|
|
|
streams[] =
|
|
|
|
{
|
|
|
|
{ FALSE, stdin, "stdin", STD_INPUT_HANDLE, _O_RDONLY, "rb" },
|
|
|
|
{ FALSE, stdout, "stdout", STD_OUTPUT_HANDLE, 0, "wb" },
|
|
|
|
{ FALSE, stderr, "stderr", STD_ERROR_HANDLE, 0, "wb" },
|
|
|
|
};
|
|
|
|
|
|
|
|
const gchar *attach_envvar;
|
|
|
|
guint i;
|
|
|
|
gchar **attach_strs;
|
|
|
|
|
|
|
|
/* Note: it's not a very good practice to use DllMain()
|
|
|
|
* to call any functions not in Kernel32.dll.
|
|
|
|
* The following only works if there are no weird
|
|
|
|
* circular DLL dependencies that could cause glib DllMain()
|
|
|
|
* to be called before CRT DllMain().
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (g_strcmp0 (g_getenv ("G_WIN32_ALLOC_CONSOLE"), "1") == 0)
|
|
|
|
AllocConsole (); /* no error handling, fails if console already exists */
|
|
|
|
|
|
|
|
attach_envvar = g_getenv ("G_WIN32_ATTACH_CONSOLE");
|
|
|
|
|
|
|
|
if (attach_envvar == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Re-use parent console, if we don't have our own.
|
|
|
|
* If we do, it will fail, so just ignore the error.
|
|
|
|
*/
|
|
|
|
AttachConsole (ATTACH_PARENT_PROCESS);
|
|
|
|
|
|
|
|
attach_strs = g_strsplit (attach_envvar, ",", -1);
|
|
|
|
|
|
|
|
for (i = 0; attach_strs[i]; i++)
|
|
|
|
{
|
|
|
|
if (g_strcmp0 (attach_strs[i], "stdout") == 0)
|
|
|
|
streams[1].redirect = TRUE;
|
|
|
|
else if (g_strcmp0 (attach_strs[i], "stderr") == 0)
|
|
|
|
streams[2].redirect = TRUE;
|
|
|
|
else if (g_strcmp0 (attach_strs[i], "stdin") == 0)
|
|
|
|
streams[0].redirect = TRUE;
|
|
|
|
else
|
|
|
|
g_warning ("Unrecognized stream name %s", attach_strs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev (attach_strs);
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (streams); i++)
|
|
|
|
{
|
|
|
|
int old_fd;
|
|
|
|
int backup_fd;
|
|
|
|
int new_fd;
|
|
|
|
int preferred_fd = i;
|
|
|
|
HANDLE std_handle;
|
|
|
|
errno_t errsv = 0;
|
|
|
|
|
|
|
|
if (!streams[i].redirect)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ferror (streams[i].stream) != 0)
|
|
|
|
{
|
|
|
|
g_warning ("Stream %s is in error state", streams[i].stream_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std_handle = GetStdHandle (streams[i].std_handle_type);
|
|
|
|
|
|
|
|
if (std_handle == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
DWORD gle = GetLastError ();
|
|
|
|
g_warning ("Standard handle for %s can't be obtained: %lu",
|
|
|
|
streams[i].stream_name, gle);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_fd = fileno (streams[i].stream);
|
|
|
|
|
|
|
|
/* We need the stream object to be associated with
|
|
|
|
* any valid integer fd for the code to work.
|
|
|
|
* If it isn't, reopen it with NUL (/dev/null) to
|
|
|
|
* ensure that it is.
|
|
|
|
*/
|
|
|
|
if (old_fd < 0)
|
|
|
|
{
|
|
|
|
if (freopen ("NUL", streams[i].mode, streams[i].stream) == NULL)
|
|
|
|
{
|
|
|
|
errsv = errno;
|
|
|
|
g_warning ("Failed to redirect %s: %d - %s",
|
|
|
|
streams[i].stream_name,
|
|
|
|
errsv,
|
|
|
|
strerror (errsv));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_fd = fileno (streams[i].stream);
|
|
|
|
|
|
|
|
if (old_fd < 0)
|
|
|
|
{
|
|
|
|
g_warning ("Stream %s does not have a valid fd",
|
|
|
|
streams[i].stream_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new_fd = _open_osfhandle ((intptr_t) std_handle, streams[i].flags);
|
|
|
|
|
|
|
|
if (new_fd < 0)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to create new fd for stream %s",
|
|
|
|
streams[i].stream_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
backup_fd = dup (old_fd);
|
|
|
|
|
|
|
|
if (backup_fd < 0)
|
|
|
|
g_warning ("Failed to backup old fd %d for stream %s",
|
|
|
|
old_fd, streams[i].stream_name);
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
/* Force old_fd to be associated with the same file
|
|
|
|
* as new_fd, i.e with the standard handle we need
|
|
|
|
* (or, rather, with the same kernel object; handle
|
|
|
|
* value will be different, but the kernel object
|
|
|
|
* won't be).
|
|
|
|
*/
|
|
|
|
/* NOTE: MSDN claims that _dup2() returns 0 on success and -1 on error,
|
|
|
|
* POSIX claims that dup2() reurns new FD on success and -1 on error.
|
|
|
|
* The "< 0" check satisfies the error condition for either implementation.
|
|
|
|
*/
|
|
|
|
if (_dup2 (new_fd, old_fd) < 0)
|
|
|
|
{
|
|
|
|
errsv = errno;
|
|
|
|
g_warning ("Failed to substitute fd %d for stream %s: %d : %s",
|
|
|
|
old_fd, streams[i].stream_name, errsv, strerror (errsv));
|
|
|
|
|
|
|
|
_close (new_fd);
|
|
|
|
|
|
|
|
if (backup_fd < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
/* Try to restore old_fd back to its previous
|
|
|
|
* handle, in case the _dup2() call above succeeded partially.
|
|
|
|
*/
|
|
|
|
if (_dup2 (backup_fd, old_fd) < 0)
|
|
|
|
{
|
|
|
|
errsv = errno;
|
|
|
|
g_warning ("Failed to restore fd %d for stream %s: %d : %s",
|
|
|
|
old_fd, streams[i].stream_name, errsv, strerror (errsv));
|
|
|
|
}
|
|
|
|
|
|
|
|
_close (backup_fd);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Success, drop the backup */
|
|
|
|
if (backup_fd >= 0)
|
|
|
|
_close (backup_fd);
|
|
|
|
|
|
|
|
/* Sadly, there's no way to check that preferred_fd
|
|
|
|
* is currently valid, so we can't back it up.
|
|
|
|
* Doing operations on invalid FDs invokes invalid
|
|
|
|
* parameter handler, which is bad for us.
|
|
|
|
*/
|
|
|
|
if (old_fd != preferred_fd)
|
|
|
|
/* This extra code will also try to ensure that
|
|
|
|
* the expected file descriptors 0, 1 and 2 are
|
|
|
|
* associated with the appropriate standard
|
|
|
|
* handles.
|
|
|
|
*/
|
|
|
|
if (_dup2 (new_fd, preferred_fd) < 0)
|
|
|
|
g_warning ("Failed to dup fd %d into fd %d", new_fd, preferred_fd);
|
|
|
|
|
|
|
|
_close (new_fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
/* This is a handle to the Vectored Exception Handler that
|
|
|
|
* we install on library initialization. If installed correctly,
|
|
|
|
* it will be non-NULL. Only used to later de-install the handler
|
|
|
|
* on library de-initialization.
|
|
|
|
*/
|
2021-04-06 09:35:39 +00:00
|
|
|
static void *WinVEH_handle = NULL;
|
|
|
|
|
|
|
|
#define DEBUGGER_BUFFER_SIZE (MAX_PATH + 1)
|
|
|
|
/* This is the debugger that we'll run on crash */
|
2021-04-24 20:50:10 +00:00
|
|
|
static wchar_t debugger[DEBUGGER_BUFFER_SIZE];
|
2021-04-06 09:35:39 +00:00
|
|
|
|
|
|
|
static gsize number_of_exceptions_to_catch = 0;
|
|
|
|
static DWORD *exceptions_to_catch = NULL;
|
|
|
|
|
|
|
|
static HANDLE debugger_wakeup_event = 0;
|
|
|
|
static DWORD debugger_spawn_flags = 0;
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
|
|
|
|
#include "gwin32-private.c"
|
|
|
|
|
2021-04-06 11:03:45 +00:00
|
|
|
static char *
|
|
|
|
copy_chars (char *buffer,
|
|
|
|
gsize *buffer_size,
|
|
|
|
const char *to_copy)
|
|
|
|
{
|
2021-05-15 04:21:37 +00:00
|
|
|
gsize copy_count = MIN (strlen (to_copy), *buffer_size - 1);
|
|
|
|
memset (buffer, 0x20, copy_count);
|
|
|
|
strncpy_s (buffer, *buffer_size, to_copy, _TRUNCATE);
|
|
|
|
*buffer_size -= copy_count;
|
2021-04-06 11:03:45 +00:00
|
|
|
return &buffer[copy_count];
|
|
|
|
}
|
|
|
|
|
2019-03-07 10:38:24 +00:00
|
|
|
/* Handles exceptions (useful for debugging).
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
* Issues a DebugBreak() call if the process is being debugged (not really
|
|
|
|
* useful - if the process is being debugged, this handler won't be invoked
|
|
|
|
* anyway). If it is not, runs a debugger from G_DEBUGGER env var,
|
|
|
|
* substituting first %p in it for PID, and the first %e for the event handle -
|
|
|
|
* that event should be set once the debugger attaches itself (otherwise the
|
|
|
|
* only way out of WaitForSingleObject() is to time out after 1 minute).
|
|
|
|
* For example, G_DEBUGGER can be set to the following command:
|
|
|
|
* ```
|
|
|
|
* gdb.exe -ex "attach %p" -ex "signal-event %e" -ex "bt" -ex "c"
|
|
|
|
* ```
|
|
|
|
* This will make GDB attach to the process, signal the event (GDB must be
|
|
|
|
* recent enough for the signal-event command to be available),
|
|
|
|
* show the backtrace and resume execution, which should make it catch
|
|
|
|
* the exception when Windows re-raises it again.
|
|
|
|
* The command line can't be longer than MAX_PATH (260 characters).
|
|
|
|
*
|
|
|
|
* This function will only stop (and run a debugger) on the following exceptions:
|
|
|
|
* * EXCEPTION_ACCESS_VIOLATION
|
|
|
|
* * EXCEPTION_STACK_OVERFLOW
|
|
|
|
* * EXCEPTION_ILLEGAL_INSTRUCTION
|
|
|
|
* To make it stop at other exceptions one should set the G_VEH_CATCH
|
2020-06-12 14:02:30 +01:00
|
|
|
* environment variable to a list of comma-separated hexadecimal numbers,
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
* where each number is the code of an exception that should be caught.
|
|
|
|
* This is done to prevent GLib from breaking when Windows uses
|
|
|
|
* exceptions to shuttle information (SetThreadName(), OutputDebugString())
|
|
|
|
* or for control flow.
|
|
|
|
*
|
|
|
|
* This function deliberately avoids calling any GLib code.
|
2021-04-06 07:40:23 +00:00
|
|
|
* This is done on purpose. This function can be called when the program
|
|
|
|
* is in a bad state (crashing). It can also be called very early, as soon
|
|
|
|
* as the handler is installed. Therefore, it's imperative that
|
|
|
|
* it does as little as possible. Preferably, all the work that can be
|
|
|
|
* done in advance (when the program is not crashing yet) should be done
|
2021-04-24 20:50:10 +00:00
|
|
|
* in advance.
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
*/
|
|
|
|
static LONG __stdcall
|
|
|
|
g_win32_veh_handler (PEXCEPTION_POINTERS ExceptionInfo)
|
|
|
|
{
|
|
|
|
EXCEPTION_RECORD *er;
|
2021-04-06 09:35:39 +00:00
|
|
|
gsize i;
|
2021-04-24 20:50:10 +00:00
|
|
|
STARTUPINFOW si;
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
PROCESS_INFORMATION pi;
|
2021-04-06 11:03:45 +00:00
|
|
|
#define ITOA_BUFFER_SIZE 100
|
|
|
|
char itoa_buffer[ITOA_BUFFER_SIZE];
|
|
|
|
#define DEBUG_STRING_SIZE 1024
|
|
|
|
gsize dbgs = DEBUG_STRING_SIZE;
|
|
|
|
char debug_string[DEBUG_STRING_SIZE];
|
|
|
|
char *dbgp;
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
|
|
|
|
if (ExceptionInfo == NULL ||
|
2020-02-18 22:57:51 +05:30
|
|
|
ExceptionInfo->ExceptionRecord == NULL ||
|
2021-04-06 11:03:45 +00:00
|
|
|
IsDebuggerPresent () ||
|
|
|
|
debugger[0] == 0)
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
|
|
|
|
er = ExceptionInfo->ExceptionRecord;
|
|
|
|
|
|
|
|
switch (er->ExceptionCode)
|
|
|
|
{
|
|
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
|
|
|
case EXCEPTION_STACK_OVERFLOW:
|
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
|
|
break;
|
|
|
|
default:
|
2021-04-06 09:35:39 +00:00
|
|
|
for (i = 0; i < number_of_exceptions_to_catch; i++)
|
|
|
|
if (exceptions_to_catch[i] == er->ExceptionCode)
|
|
|
|
break;
|
2021-04-06 07:40:23 +00:00
|
|
|
|
2021-04-06 09:35:39 +00:00
|
|
|
if (i == number_of_exceptions_to_catch)
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
|
2021-04-06 09:35:39 +00:00
|
|
|
break;
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memset (&si, 0, sizeof (si));
|
|
|
|
memset (&pi, 0, sizeof (pi));
|
|
|
|
si.cb = sizeof (si);
|
|
|
|
|
|
|
|
/* Run the debugger */
|
2021-04-24 20:50:10 +00:00
|
|
|
if (0 != CreateProcessW (NULL, debugger, NULL, NULL, TRUE, debugger_spawn_flags, NULL, NULL, &si, &pi))
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
{
|
|
|
|
CloseHandle (pi.hProcess);
|
|
|
|
CloseHandle (pi.hThread);
|
|
|
|
/* If successful, wait for 60 seconds on the event
|
|
|
|
* we passed. The debugger should signal that event.
|
|
|
|
* 60 second limit is here to prevent us from hanging
|
|
|
|
* up forever in case the debugger does not support
|
|
|
|
* event signalling.
|
|
|
|
*/
|
2021-04-06 09:35:39 +00:00
|
|
|
WaitForSingleObject (debugger_wakeup_event, 60000);
|
2021-04-06 11:03:45 +00:00
|
|
|
|
|
|
|
dbgp = &debug_string[0];
|
|
|
|
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "Exception code=0x");
|
|
|
|
itoa_buffer[0] = 0;
|
|
|
|
_ui64toa_s (er->ExceptionCode, itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, " flags=0x");
|
|
|
|
itoa_buffer[0] = 0;
|
|
|
|
_ui64toa_s (er->ExceptionFlags, itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, " at 0x");
|
|
|
|
itoa_buffer[0] = 0;
|
|
|
|
_ui64toa_s ((guintptr) er->ExceptionAddress, itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
|
|
|
|
|
|
|
switch (er->ExceptionCode)
|
|
|
|
{
|
|
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, ". Access violation - attempting to ");
|
|
|
|
if (er->ExceptionInformation[0] == 0)
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "read data");
|
|
|
|
else if (er->ExceptionInformation[0] == 1)
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "write data");
|
|
|
|
else if (er->ExceptionInformation[0] == 8)
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "execute data");
|
|
|
|
else
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "do something bad");
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, " at address 0x");
|
|
|
|
itoa_buffer[0] = 0;
|
|
|
|
_ui64toa_s (er->ExceptionInformation[1], itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
|
|
|
break;
|
|
|
|
case EXCEPTION_IN_PAGE_ERROR:
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, ". Page access violation - attempting to ");
|
|
|
|
if (er->ExceptionInformation[0] == 0)
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "read from an inaccessible page");
|
|
|
|
else if (er->ExceptionInformation[0] == 1)
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "write to an inaccessible page");
|
|
|
|
else if (er->ExceptionInformation[0] == 8)
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "execute data in page");
|
|
|
|
else
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "do something bad with a page");
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, " at address 0x");
|
|
|
|
itoa_buffer[0] = 0;
|
|
|
|
_ui64toa_s (er->ExceptionInformation[1], itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, " with status ");
|
|
|
|
itoa_buffer[0] = 0;
|
|
|
|
_ui64toa_s (er->ExceptionInformation[2], itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
dbgp = copy_chars (dbgp, &dbgs, "\n");
|
|
|
|
OutputDebugStringA (debug_string);
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now the debugger is present, and we can try
|
|
|
|
* resuming execution, re-triggering the exception,
|
|
|
|
* which will be caught by debugger this time around.
|
|
|
|
*/
|
|
|
|
if (IsDebuggerPresent ())
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
|
|
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
|
2021-04-06 09:35:39 +00:00
|
|
|
static gsize
|
2021-04-24 20:50:10 +00:00
|
|
|
parse_catch_list (const wchar_t *catch_buffer,
|
|
|
|
DWORD *exceptions,
|
|
|
|
gsize num_exceptions)
|
2021-04-06 09:35:39 +00:00
|
|
|
{
|
2021-04-24 20:50:10 +00:00
|
|
|
const wchar_t *catch_list = catch_buffer;
|
|
|
|
gsize result = 0;
|
|
|
|
gsize i = 0;
|
2021-04-06 09:35:39 +00:00
|
|
|
|
|
|
|
while (catch_list != NULL &&
|
|
|
|
catch_list[0] != 0)
|
|
|
|
{
|
|
|
|
unsigned long catch_code;
|
2021-04-24 20:50:10 +00:00
|
|
|
wchar_t *end;
|
2021-04-06 09:35:39 +00:00
|
|
|
errno = 0;
|
2021-04-24 20:50:10 +00:00
|
|
|
catch_code = wcstoul (catch_list, &end, 16);
|
2021-04-06 09:35:39 +00:00
|
|
|
if (errno != NO_ERROR)
|
|
|
|
break;
|
|
|
|
catch_list = end;
|
2021-04-24 20:50:10 +00:00
|
|
|
if (catch_list != NULL && catch_list[0] == L',')
|
2021-04-06 09:35:39 +00:00
|
|
|
catch_list++;
|
|
|
|
if (exceptions && i < num_exceptions)
|
|
|
|
exceptions[i++] = catch_code;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
void
|
|
|
|
g_crash_handler_win32_init (void)
|
|
|
|
{
|
2021-04-24 20:50:10 +00:00
|
|
|
wchar_t debugger_env[DEBUGGER_BUFFER_SIZE];
|
2021-04-06 09:35:39 +00:00
|
|
|
#define CATCH_BUFFER_SIZE 1024
|
2021-04-24 20:50:10 +00:00
|
|
|
wchar_t catch_buffer[CATCH_BUFFER_SIZE];
|
2021-04-06 09:35:39 +00:00
|
|
|
SECURITY_ATTRIBUTES sa;
|
2021-04-06 07:40:23 +00:00
|
|
|
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
if (WinVEH_handle != NULL)
|
|
|
|
return;
|
|
|
|
|
2020-02-18 23:04:39 +05:30
|
|
|
/* Do not register an exception handler if we're not supposed to catch any
|
|
|
|
* exceptions. Exception handlers are considered dangerous to use, and can
|
|
|
|
* break advanced exception handling such as in CLRs like C# or other managed
|
2021-04-06 09:35:39 +00:00
|
|
|
* code. See: http://www.windows-tech.info/13/785f590867bd6316.php
|
2020-02-18 23:04:39 +05:30
|
|
|
*/
|
2021-04-06 09:35:39 +00:00
|
|
|
debugger_env[0] = 0;
|
2021-04-24 20:50:10 +00:00
|
|
|
if (!GetEnvironmentVariableW (L"G_DEBUGGER", debugger_env, DEBUGGER_BUFFER_SIZE))
|
2020-02-18 23:04:39 +05:30
|
|
|
return;
|
|
|
|
|
2021-04-06 09:35:39 +00:00
|
|
|
/* Create an inheritable event */
|
|
|
|
memset (&sa, 0, sizeof (sa));
|
|
|
|
sa.nLength = sizeof (sa);
|
|
|
|
sa.bInheritHandle = TRUE;
|
|
|
|
debugger_wakeup_event = CreateEvent (&sa, FALSE, FALSE, NULL);
|
|
|
|
|
|
|
|
/* Put process ID and event handle into debugger commandline */
|
2021-04-24 20:50:10 +00:00
|
|
|
if (!_g_win32_subst_pid_and_event_w (debugger, G_N_ELEMENTS (debugger),
|
|
|
|
debugger_env, GetCurrentProcessId (),
|
|
|
|
(guintptr) debugger_wakeup_event))
|
2021-04-06 09:35:39 +00:00
|
|
|
{
|
|
|
|
CloseHandle (debugger_wakeup_event);
|
|
|
|
debugger_wakeup_event = 0;
|
|
|
|
debugger[0] = 0;
|
|
|
|
return;
|
|
|
|
}
|
2021-04-24 20:50:10 +00:00
|
|
|
debugger[MAX_PATH] = L'\0';
|
2021-04-06 09:35:39 +00:00
|
|
|
|
|
|
|
catch_buffer[0] = 0;
|
2021-04-24 20:50:10 +00:00
|
|
|
if (GetEnvironmentVariableW (L"G_VEH_CATCH", catch_buffer, CATCH_BUFFER_SIZE))
|
2021-04-06 09:35:39 +00:00
|
|
|
{
|
|
|
|
number_of_exceptions_to_catch = parse_catch_list (catch_buffer, NULL, 0);
|
|
|
|
if (number_of_exceptions_to_catch > 0)
|
|
|
|
{
|
|
|
|
exceptions_to_catch = g_new0 (DWORD, number_of_exceptions_to_catch);
|
|
|
|
parse_catch_list (catch_buffer, exceptions_to_catch, number_of_exceptions_to_catch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-24 20:50:10 +00:00
|
|
|
if (GetEnvironmentVariableW (L"G_DEBUGGER_OLD_CONSOLE", (wchar_t *) &debugger_spawn_flags, 1))
|
2021-04-06 09:35:39 +00:00
|
|
|
debugger_spawn_flags = 0;
|
|
|
|
else
|
|
|
|
debugger_spawn_flags = CREATE_NEW_CONSOLE;
|
|
|
|
|
W32: Add a simple exception handler
Install a Vectored Exception Handler[0]. Its sole purpose is to catch
some exceptions (access violations, stack overflows, illegal
instructions and debug breaks - by default, but it can be made to catch
any exception for which a code is known) and run a debugger in response.
This allows W32 glib applications to be run without a debugger,
but at the same time allows a debugger to be attached in case
something happens.
The debugger is run with a new console, unless an environment variable
is set to allow it to inherit the console of the crashing process.
The short list of handleable exceptions is there to ensure that
this handler won't run a debugger to "handle" utility exceptions,
such as the one that is used to communicate thread names to a debugger.
The handler is installed to be called last, and shouldn't interfere
with any user-installed handlers.
There's nothing fancy about the way it runs a debugger (it doesn't even
support unicode in paths), and it deliberately avoids using glib code.
The handler will also print a bit of information about the exception
that it caught, and even more information for well-known exceptions,
such as access violation.
The whole scheme is similar to AeDebug[1] and, in fact, the signal-event
gdb command was originally implemented for this very purpose.
[0]: https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling
[1]: https://docs.microsoft.com/en-us/windows/desktop/debug/configuring-automatic-debugging
2019-01-13 11:21:04 +00:00
|
|
|
WinVEH_handle = AddVectoredExceptionHandler (0, &g_win32_veh_handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
g_crash_handler_win32_deinit (void)
|
|
|
|
{
|
|
|
|
if (WinVEH_handle != NULL)
|
|
|
|
RemoveVectoredExceptionHandler (WinVEH_handle);
|
|
|
|
|
|
|
|
WinVEH_handle = NULL;
|
|
|
|
}
|
|
|
|
|
W32: add std stream redirection envvar options
This commit adds two W32-only environmental variable checks:
* G_WIN32_ALLOC_CONSOLE, if set to 1, will force glib to create
a new console if the process has no console by itself.
This option is for GUI apps that are launched from GUI
processes, in which case there's no console anywhere near them.
* G_WIN32_ATTACH_CONSOLE, if set to a comma-separated list of
standard stream names (stdint, stdout, stderr), will reopen
a given std stream and tie it to the console (using existing console
or parent console).
This works either with the other option (to create a console),
or if the app is launched from a console process (often the
case for developers).
The redirection is done with freopen(), dup() and dup2().
If everything goes well, C file descriptors 0, 1 or 2 will
be bound to stdin, stdout and stderr respectively (only for
streams listed in the envrionmental variable), and so will
be stdio streams by the same names.
With these it's possible to see the output of g_log*() functions
when running GTK4 applications, which are linked as GUI applications,
and thus do not get a console by default.
https://bugzilla.gnome.org/show_bug.cgi?id=790857
Fixes issue #1304
2017-11-26 18:27:51 +00:00
|
|
|
#endif
|