Imported Upstream version 2.67.2
[platform/upstream/glib.git] / glib / gutils.c
index 988d0a5..d3e4e19 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/stat.h>
 #ifdef G_OS_UNIX
 #include <pwd.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 #endif
 #include <sys/types.h>
@@ -301,8 +302,8 @@ g_find_program_in_path (const gchar *program)
  * the program is found, the return value contains the full name
  * including the type suffix.
  *
- * Returns: (type filename): a newly-allocated string with the absolute path,
- *     or %NULL
+ * Returns: (type filename) (transfer full) (nullable): a newly-allocated
+ *   string with the absolute path, or %NULL
  **/
 #ifdef G_OS_WIN32
 static gchar *
@@ -680,7 +681,7 @@ g_get_user_database_entry (void)
             e.user_name = g_strdup (pw->pw_name);
 
 #ifndef __BIONIC__
-            if (pw->pw_gecos && *pw->pw_gecos != '\0')
+            if (pw->pw_gecos && *pw->pw_gecos != '\0' && pw->pw_name)
               {
                 gchar **gecos_fields;
                 gchar **name_parts;
@@ -735,7 +736,7 @@ g_get_user_database_entry (void)
  * encoding, or something else, and there is no guarantee that it is even
  * consistent on a machine. On Windows, it is always UTF-8.
  *
- * Returns: (type filename): the user name of the current user.
+ * Returns: (type filename) (transfer none): the user name of the current user.
  */
 const gchar *
 g_get_user_name (void)
@@ -756,7 +757,7 @@ g_get_user_name (void)
  * real user name cannot be determined, the string "Unknown" is 
  * returned.
  *
- * Returns: (type filename): the user's real name.
+ * Returns: (type filename) (transfer none): the user's real name.
  */
 const gchar *
 g_get_real_name (void)
@@ -865,7 +866,7 @@ g_build_home_dir (void)
  * should either directly check the `HOME` environment variable yourself
  * or unset it before calling any functions in GLib.
  *
- * Returns: (type filename): the current user's home directory
+ * Returns: (type filename) (transfer none): the current user's home directory
  */
 const gchar *
 g_get_home_dir (void)
@@ -901,7 +902,7 @@ g_get_home_dir (void)
  * it is always UTF-8. The return value is never %NULL or the empty
  * string.
  *
- * Returns: (type filename): the directory to use for temporary files.
+ * Returns: (type filename) (transfer none): the directory to use for temporary files.
  */
 const gchar *
 g_get_tmp_dir (void)
@@ -966,7 +967,7 @@ g_get_tmp_dir (void)
  *
  * The encoding of the returned string is UTF-8.
  *
- * Returns: the host name of the machine.
+ * Returns: (transfer none): the host name of the machine.
  *
  * Since: 2.8
  */
@@ -981,7 +982,6 @@ g_get_host_name (void)
       gchar *utmp;
 
 #ifndef G_OS_WIN32
-      glong max;
       gsize size;
       /* The number 256 * 256 is taken from the value of _POSIX_HOST_NAME_MAX,
        * which is 255. Since we use _POSIX_HOST_NAME_MAX + 1 (= 256) in the
@@ -992,16 +992,24 @@ g_get_host_name (void)
       const gsize size_large = (gsize) 256 * 256;
       gchar *tmp;
 
-      max = sysconf (_SC_HOST_NAME_MAX);
-      if (max > 0 && max <= G_MAXSIZE - 1)
-        size = (gsize) max + 1;
-      else
+#ifdef _SC_HOST_NAME_MAX
+      {
+        glong max;
+
+        max = sysconf (_SC_HOST_NAME_MAX);
+        if (max > 0 && (gsize) max <= G_MAXSIZE - 1)
+          size = (gsize) max + 1;
+        else
 #ifdef HOST_NAME_MAX
-        size = HOST_NAME_MAX + 1;
+          size = HOST_NAME_MAX + 1;
 #else
-        size = _POSIX_HOST_NAME_MAX + 1;
-#endif
-
+          size = _POSIX_HOST_NAME_MAX + 1;
+#endif /* HOST_NAME_MAX */
+      }
+#else
+      /* Fallback to some reasonable value */
+      size = 256;
+#endif /* _SC_HOST_NAME_MAX */
       tmp = g_malloc (size);
       failed = (gethostname (tmp, size) == -1);
       if (failed && size < size_large)
@@ -1046,9 +1054,9 @@ static gchar *g_prgname = NULL;
  * #GtkApplication::startup handler. The program name is found by
  * taking the last component of @argv[0].
  *
- * Returns: (nullable): the name of the program, or %NULL if it has not been
- *     set yet. The returned string belongs
- *     to GLib and must not be modified or freed.
+ * Returns: (nullable) (transfer none): the name of the program,
+ *   or %NULL if it has not been set yet. The returned string belongs
+ *   to GLib and must not be modified or freed.
  */
 const gchar*
 g_get_prgname (void)
@@ -1100,7 +1108,8 @@ static gchar *g_application_name = NULL;
  * g_get_prgname() (which may be %NULL if g_set_prgname() has also not
  * been called).
  * 
- * Returns: human-readable application name. may return %NULL
+ * Returns: (transfer none) (nullable): human-readable application
+ *   name. May return %NULL
  *
  * Since: 2.2
  **/
@@ -1153,6 +1162,429 @@ g_set_application_name (const gchar *application_name)
     g_warning ("g_set_application_name() called multiple times");
 }
 
+#ifdef G_OS_WIN32
+/* For the past versions we can just
+ * hardcode all the names.
+ */
+static const struct winver
+{
+  gint major;
+  gint minor;
+  gint sp;
+  const char *version;
+  const char *spversion;
+} versions[] =
+{
+  {6, 2, 0, "8", ""},
+  {6, 1, 1, "7", " SP1"},
+  {6, 1, 0, "7", ""},
+  {6, 0, 2, "Vista", " SP2"},
+  {6, 0, 1, "Vista", " SP1"},
+  {6, 0, 0, "Vista", ""},
+  {5, 1, 3, "XP", " SP3"},
+  {5, 1, 2, "XP", " SP2"},
+  {5, 1, 1, "XP", " SP1"},
+  {5, 1, 0, "XP", ""},
+  {0, 0, 0, NULL, NULL},
+};
+
+static gchar *
+get_registry_str (HKEY root_key, const wchar_t *path, const wchar_t *value_name)
+{
+  HKEY key_handle;
+  DWORD req_value_data_size;
+  DWORD req_value_data_size2;
+  LONG status;
+  DWORD value_type_w;
+  DWORD value_type_w2;
+  char *req_value_data;
+  gchar *result;
+
+  status = RegOpenKeyExW (root_key, path, 0, KEY_READ, &key_handle);
+  if (status != ERROR_SUCCESS)
+    return NULL;
+
+  req_value_data_size = 0;
+  status = RegQueryValueExW (key_handle,
+                             value_name,
+                             NULL,
+                             &value_type_w,
+                             NULL,
+                             &req_value_data_size);
+
+  if (status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
+    {
+      RegCloseKey (key_handle);
+
+      return NULL;
+    }
+
+  req_value_data = g_malloc (req_value_data_size);
+  req_value_data_size2 = req_value_data_size;
+
+  status = RegQueryValueExW (key_handle,
+                             value_name,
+                             NULL,
+                             &value_type_w2,
+                             (gpointer) req_value_data,
+                             &req_value_data_size2);
+
+  result = NULL;
+
+  if (status == ERROR_SUCCESS && value_type_w2 == REG_SZ)
+    result = g_utf16_to_utf8 ((gunichar2 *) req_value_data,
+                              req_value_data_size / sizeof (gunichar2),
+                              NULL,
+                              NULL,
+                              NULL);
+
+  g_free (req_value_data);
+  RegCloseKey (key_handle);
+
+  return result;
+}
+
+/* Windows 8.1 can be either plain or with Update 1,
+ * depending on its build number (9200 or 9600).
+ */
+static gchar *
+get_windows_8_1_update (void)
+{
+  gchar *current_build;
+  gchar *result = NULL;
+
+  current_build = get_registry_str (HKEY_LOCAL_MACHINE,
+                                    L"SOFTWARE"
+                                    L"\\Microsoft"
+                                    L"\\Windows NT"
+                                    L"\\CurrentVersion",
+                                    L"CurrentBuild");
+
+  if (current_build != NULL)
+    {
+      wchar_t *end;
+      long build = wcstol ((const wchar_t *) current_build, &end, 10);
+
+      if (build <= INT_MAX &&
+          build >= INT_MIN &&
+          errno == 0 &&
+          *end == L'\0')
+        {
+          if (build >= 9600)
+            result = g_strdup ("Update 1");
+        }
+    }
+
+  g_clear_pointer (&current_build, g_free);
+
+  return result;
+}
+
+static gchar *
+get_windows_version (gboolean with_windows)
+{
+  GString *version = g_string_new (NULL);
+
+  if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY))
+    {
+      gchar *win10_release;
+
+      g_string_append (version, "10");
+
+      if (!g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_WORKSTATION))
+        g_string_append (version, " Server");
+
+      /* Windows 10 is identified by its release number, such as
+       * 1511, 1607, 1703, 1709, 1803, 1809 or 1903.
+       * The first version of Windows 10 has no release number.
+       */
+      win10_release = get_registry_str (HKEY_LOCAL_MACHINE,
+                                        L"SOFTWARE"
+                                        L"\\Microsoft"
+                                        L"\\Windows NT"
+                                        L"\\CurrentVersion",
+                                        L"ReleaseId");
+
+      if (win10_release != NULL)
+        g_string_append_printf (version, " %s", win10_release);
+
+      g_free (win10_release);
+    }
+  else if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_ANY))
+    {
+      gchar *win81_update;
+
+      g_string_append (version, "8.1");
+
+      if (!g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_WORKSTATION))
+        g_string_append (version, " Server");
+
+      win81_update = get_windows_8_1_update ();
+
+      if (win81_update != NULL)
+        g_string_append_printf (version, " %s", win81_update);
+
+      g_free (win81_update);
+    }
+  else
+    {
+      gint i;
+
+      for (i = 0; versions[i].major > 0; i++)
+        {
+          if (!g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_ANY))
+            continue;
+
+          g_string_append (version, versions[i].version);
+
+          if (!g_win32_check_windows_version (versions[i].major, versions[i].minor, versions[i].sp, G_WIN32_OS_WORKSTATION))
+            g_string_append (version, " Server");
+
+          g_string_append (version, versions[i].spversion);
+        }
+    }
+
+  if (version->len == 0)
+    {
+      g_string_free (version, TRUE);
+
+      return NULL;
+    }
+
+  if (with_windows)
+    g_string_prepend (version, "Windows ");
+
+  return g_string_free (version, FALSE);
+}
+#endif
+
+#ifdef G_OS_UNIX
+static gchar *
+get_os_info_from_os_release (const gchar *key_name,
+                             const gchar *buffer)
+{
+  GStrv lines;
+  gchar *prefix;
+  size_t i;
+  gchar *result = NULL;
+
+  lines = g_strsplit (buffer, "\n", -1);
+  prefix = g_strdup_printf ("%s=", key_name);
+  for (i = 0; lines[i] != NULL; i++)
+    {
+      const gchar *line = lines[i];
+      const gchar *value;
+
+      if (g_str_has_prefix (line, prefix))
+        {
+          value = line + strlen (prefix);
+          result = g_shell_unquote (value, NULL);
+          if (result == NULL)
+            result = g_strdup (value);
+          break;
+        }
+    }
+  g_strfreev (lines);
+  g_free (prefix);
+
+#ifdef __linux__
+  /* Default values in spec */
+  if (result == NULL)
+    {
+      if (g_str_equal (key_name, G_OS_INFO_KEY_NAME))
+        return g_strdup ("Linux");
+      if (g_str_equal (key_name, G_OS_INFO_KEY_ID))
+        return g_strdup ("linux");
+      if (g_str_equal (key_name, G_OS_INFO_KEY_PRETTY_NAME))
+        return g_strdup ("Linux");
+    }
+#endif
+
+  return g_steal_pointer (&result);
+}
+
+static gchar *
+get_os_info_from_uname (const gchar *key_name)
+{
+  struct utsname info;
+
+  if (uname (&info) == -1)
+    return NULL;
+
+  if (strcmp (key_name, G_OS_INFO_KEY_NAME) == 0)
+    return g_strdup (info.sysname);
+  else if (strcmp (key_name, G_OS_INFO_KEY_VERSION) == 0)
+    return g_strdup (info.release);
+  else if (strcmp (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
+    return g_strdup_printf ("%s %s", info.sysname, info.release);
+  else if (strcmp (key_name, G_OS_INFO_KEY_ID) == 0)
+    {
+      gchar *result = g_ascii_strdown (info.sysname, -1);
+
+      g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+      return g_steal_pointer (&result);
+    }
+  else if (strcmp (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
+    {
+      /* We attempt to convert the version string to the format returned by
+       * config.guess, which is the script used to generate target triplets
+       * in GNU autotools. There are a lot of rules in the script. We only
+       * implement a few rules which are easy to understand here.
+       *
+       * config.guess can be found at https://savannah.gnu.org/projects/config.
+       */
+      gchar *result;
+
+      if (strcmp (info.sysname, "NetBSD") == 0)
+        {
+          /* sed -e 's,[-_].*,,' */
+          gssize len = G_MAXSSIZE;
+          const gchar *c;
+
+          if ((c = strchr (info.release, '-')) != NULL)
+            len = MIN (len, c - info.release);
+          if ((c = strchr (info.release, '_')) != NULL)
+            len = MIN (len, c - info.release);
+          if (len == G_MAXSSIZE)
+            len = -1;
+
+          result = g_ascii_strdown (info.release, len);
+        }
+      else if (strcmp (info.sysname, "GNU") == 0)
+        {
+          /* sed -e 's,/.*$,,' */
+          gssize len = -1;
+          const gchar *c = strchr (info.release, '/');
+
+          if (c != NULL)
+            len = c - info.release;
+
+          result = g_ascii_strdown (info.release, len);
+        }
+      else if (g_str_has_prefix (info.sysname, "GNU/") ||
+               strcmp (info.sysname, "FreeBSD") == 0 ||
+               strcmp (info.sysname, "DragonFly") == 0)
+        {
+          /* sed -e 's,[-(].*,,' */
+          gssize len = G_MAXSSIZE;
+          const gchar *c;
+
+          if ((c = strchr (info.release, '-')) != NULL)
+            len = MIN (len, c - info.release);
+          if ((c = strchr (info.release, '(')) != NULL)
+            len = MIN (len, c - info.release);
+          if (len == G_MAXSSIZE)
+            len = -1;
+
+          result = g_ascii_strdown (info.release, len);
+        }
+      else
+        result = g_ascii_strdown (info.release, -1);
+
+      g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+      return g_steal_pointer (&result);
+    }
+  else
+    return NULL;
+}
+#endif
+
+/**
+ * g_get_os_info:
+ * @key_name: a key for the OS info being requested, for example %G_OS_INFO_KEY_NAME.
+ *
+ * Get information about the operating system.
+ *
+ * On Linux this comes from the `/etc/os-release` file. On other systems, it may
+ * come from a variety of sources. You can either use the standard key names
+ * like %G_OS_INFO_KEY_NAME or pass any UTF-8 string key name. For example,
+ * `/etc/os-release` provides a number of other less commonly used values that may
+ * be useful. No key is guaranteed to be provided, so the caller should always
+ * check if the result is %NULL.
+ *
+ * Returns: (nullable): The associated value for the requested key or %NULL if
+ *   this information is not provided.
+ *
+ * Since: 2.64
+ **/
+gchar *
+g_get_os_info (const gchar *key_name)
+{
+#if defined (__APPLE__)
+  if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
+    return g_strdup ("macOS");
+  else
+    return NULL;
+#elif defined (G_OS_UNIX)
+  const gchar * const os_release_files[] = { "/etc/os-release", "/usr/lib/os-release" };
+  gsize i;
+  gchar *buffer = NULL;
+  gchar *result = NULL;
+
+  g_return_val_if_fail (key_name != NULL, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (os_release_files); i++)
+    {
+      GError *error = NULL;
+      gboolean file_missing;
+
+      if (g_file_get_contents (os_release_files[i], &buffer, NULL, &error))
+        break;
+
+      file_missing = g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
+      g_clear_error (&error);
+
+      if (!file_missing)
+        return NULL;
+    }
+
+  if (buffer != NULL)
+    result = get_os_info_from_os_release (key_name, buffer);
+  else
+    result = get_os_info_from_uname (key_name);
+
+  g_free (buffer);
+  return g_steal_pointer (&result);
+#elif defined (G_OS_WIN32)
+  if (g_strcmp0 (key_name, G_OS_INFO_KEY_NAME) == 0)
+    return g_strdup ("Windows");
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_ID) == 0)
+    return g_strdup ("windows");
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_PRETTY_NAME) == 0)
+    /* Windows XP SP2 or Windows 10 1903 or Windows 7 Server SP1 */
+    return get_windows_version (TRUE);
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_VERSION) == 0)
+    /* XP SP2 or 10 1903 or 7 Server SP1 */
+    return get_windows_version (FALSE);
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_VERSION_ID) == 0)
+    {
+      /* xp_sp2 or 10_1903 or 7_server_sp1 */
+      gchar *result;
+      gchar *version = get_windows_version (FALSE);
+
+      if (version == NULL)
+        return NULL;
+
+      result = g_ascii_strdown (version, -1);
+      g_free (version);
+
+      return g_strcanon (result, "abcdefghijklmnopqrstuvwxyz0123456789_-.", '_');
+    }
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_HOME_URL) == 0)
+    return g_strdup ("https://microsoft.com/windows/");
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_DOCUMENTATION_URL) == 0)
+    return g_strdup ("https://docs.microsoft.com/");
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_SUPPORT_URL) == 0)
+    return g_strdup ("https://support.microsoft.com/");
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_BUG_REPORT_URL) == 0)
+    return g_strdup ("https://support.microsoft.com/contactus/");
+  else if (g_strcmp0 (key_name, G_OS_INFO_KEY_PRIVACY_POLICY_URL) == 0)
+    return g_strdup ("https://privacy.microsoft.com/");
+  else
+    return NULL;
+#endif
+}
+
 /* Set @global_str to a copy of @new_value if it’s currently unset or has a
  * different value. If its current value matches @new_value, do nothing. If
  * replaced, we have to leak the old value as client code could still have
@@ -1300,8 +1732,9 @@ g_build_user_data_dir (void)
  * Note that in this case on Windows it will be the same
  * as what g_get_user_config_dir() returns.
  *
- * Returns: (type filename): a string owned by GLib that must not be modified
- *               or freed.
+ * Returns: (type filename) (transfer none): a string owned by GLib that must
+ *   not be modified or freed.
+ *
  * Since: 2.6
  **/
 const gchar *
@@ -1360,8 +1793,8 @@ g_build_user_config_dir (void)
  * Note that in this case on Windows it will be  the same
  * as what g_get_user_data_dir() returns.
  *
- * Returns: (type filename): a string owned by GLib that must not be modified
- *               or freed.
+ * Returns: (type filename) (transfer none): a string owned by GLib that
+ *   must not be modified or freed.
  * Since: 2.6
  **/
 const gchar *
@@ -1419,8 +1852,8 @@ g_build_user_cache_dir (void)
  * `C:\Documents and Settings\username\Local Settings\Temporary Internet Files`.
  * See the [documentation for `CSIDL_INTERNET_CACHE`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494%28v=vs.85%29.aspx#csidl_internet_cache).
  *
- * Returns: (type filename): a string owned by GLib that must not be modified
- *               or freed.
+ * Returns: (type filename) (transfer none): a string owned by GLib that
+ *   must not be modified or freed.
  * Since: 2.6
  **/
 const gchar *
@@ -1531,7 +1964,7 @@ load_user_special_dirs (void)
 
   wchar_t *wcp;
 
-  p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (GetModuleHandle ("shell32.dll"),
+  p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (GetModuleHandleW (L"shell32.dll"),
                                                                    "SHGetKnownFolderPath");
 
   g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
@@ -1862,26 +2295,14 @@ get_module_for_address (gconstpointer address)
 {
   /* Holds the g_utils_global lock */
 
-  static gboolean beenhere = FALSE;
-  typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
-  static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
   HMODULE hmodule = NULL;
 
   if (!address)
     return NULL;
 
-  if (!beenhere)
-    {
-      p_GetModuleHandleExA =
-       (t_GetModuleHandleExA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
-                                              "GetModuleHandleExA");
-      beenhere = TRUE;
-    }
-
-  if (p_GetModuleHandleExA == NULL ||
-      !(*p_GetModuleHandleExA) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
-                               GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-                               address, &hmodule))
+  if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+                          GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                          address, &hmodule))
     {
       MEMORY_BASIC_INFORMATION mbi;
       VirtualQuery (address, &mbi, sizeof (mbi));
@@ -2258,8 +2679,8 @@ g_nullify_pointer (gpointer *nullify_location)
  * See g_format_size_full() for more options about how the size might be
  * formatted.
  *
- * Returns: a newly-allocated formatted string containing a human readable
- *     file size
+ * Returns: (transfer full): a newly-allocated formatted string containing
+ *   a human readable file size
  *
  * Since: 2.30
  */
@@ -2297,8 +2718,8 @@ g_format_size (guint64 size)
  * This function is similar to g_format_size() but allows for flags
  * that modify the output. See #GFormatSizeFlags.
  *
- * Returns: a newly-allocated formatted string containing a human
- *     readable file size
+ * Returns: (transfer full): a newly-allocated formatted string
+ *   containing a human readable file size
  *
  * Since: 2.30
  */
@@ -2514,8 +2935,8 @@ g_format_size_full (guint64          size,
  *
  * This string should be freed with g_free() when not needed any longer.
  *
- * Returns: a newly-allocated formatted string containing a human
- *     readable file size
+ * Returns: (transfer full): a newly-allocated formatted string
+ *   containing a human readable file size
  *
  * Since: 2.16
  *
@@ -2672,7 +3093,7 @@ g_abort (void)
 {
   /* One call to break the debugger */
   DebugBreak ();
-  /* One call in case CRT does get saner about abort() behaviour */
+  /* One call in case CRT changes its abort() behaviour */
   abort ();
   /* And one call to bind them all and terminate the program for sure */
   ExitProcess (127);