gwin32.c 31.4 KB
Newer Older
1 2 3 4 5
/* 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
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9 10 11 12
 *
 * 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
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 18 19
 */

/*
20
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
21 22 23 24 25 26 27 28 29
 * 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.
 */

30
#include "config.h"
31 32 33 34 35 36

#include "glibconfig.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
37
#include <wchar.h>
38
#include <errno.h>
39
#include <fcntl.h>
40 41 42

#define STRICT			/* Strict typing, please */
#include <windows.h>
43 44
#undef STRICT
#ifndef G_WITH_CYGWIN
45
#include <direct.h>
46
#endif
47 48
#include <errno.h>
#include <ctype.h>
49
#if defined(_MSC_VER) || defined(__DMC__)
50
#  include <io.h>
51
#endif /* _MSC_VER || __DMC__ */
52

53 54 55 56 57 58 59 60 61 62
#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
63 64
#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
/* mingw-w64 must use winternl.h, but not MinGW */
65
#include <ntdef.h>
66 67
#else
#include <winternl.h>
68 69
#endif

70
#include "glib.h"
71
#include "gthreadprivate.h"
72
#include "glib-init.h"
73

74 75 76 77 78 79 80
#ifdef G_WITH_CYGWIN
#include <sys/cygwin.h>
#endif

#ifndef G_WITH_CYGWIN

gint
81 82 83
g_win32_ftruncate (gint  fd,
		   guint size)
{
84
  return _chsize (fd, size);
85 86
}

87
#endif
88

89 90 91
/**
 * g_win32_getlocale:
 *
92 93 94 95 96 97 98
 * 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().
Havoc Pennington's avatar
Havoc Pennington committed
99
 *
100
 * Returns: newly-allocated locale name.
101
 **/
102

103 104
#ifndef SUBLANG_SERBIAN_LATIN_BA
#define SUBLANG_SERBIAN_LATIN_BA 0x06
105 106
#endif

107 108 109
gchar *
g_win32_getlocale (void)
{
110
  LCID lcid;
111
  LANGID langid;
112
  gchar *ev;
113
  gint primary, sub;
114 115 116
  char iso639[10];
  char iso3166[10];
  const gchar *script = NULL;
117

118
  /* Let the user override the system settings through environment
119 120 121 122
   * 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.
   */
123 124 125
  if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0')
      || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0')
      || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0'))
126 127 128
    return g_strdup (ev);

  lcid = GetThreadLocale ();
129

130 131 132 133
  if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) ||
      !GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
    return g_strdup ("C");
  
134 135 136 137 138 139
  /* 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);
140 141

  /* Handle special cases */
142 143
  switch (primary)
    {
144
    case LANG_AZERI:
145 146
      switch (sub)
	{
147 148 149 150 151 152
	case SUBLANG_AZERI_LATIN:
	  script = "@Latn";
	  break;
	case SUBLANG_AZERI_CYRILLIC:
	  script = "@Cyrl";
	  break;
153 154
	}
      break;
155
    case LANG_SERBIAN:		/* LANG_CROATIAN == LANG_SERBIAN */
156 157
      switch (sub)
	{
158 159 160 161
	case SUBLANG_SERBIAN_LATIN:
	case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */
	  script = "@Latn";
	  break;
162 163 164 165 166
	}
      break;
    case LANG_UZBEK:
      switch (sub)
	{
167 168 169 170 171 172
	case SUBLANG_UZBEK_LATIN:
	  script = "@Latn";
	  break;
	case SUBLANG_UZBEK_CYRILLIC:
	  script = "@Cyrl";
	  break;
173 174 175
	}
      break;
    }
176
  return g_strconcat (iso639, "_", iso3166, script, NULL);
177
}
178

179 180
/**
 * g_win32_error_message:
181
 * @error: error code.
182
 *
183 184 185 186 187 188
 * 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().
Havoc Pennington's avatar
Havoc Pennington committed
189
 *
190
 * Returns: newly-allocated error message
191
 **/
192 193 194 195
gchar *
g_win32_error_message (gint error)
{
  gchar *retval;
196
  wchar_t *msg = NULL;
197
  size_t nchars;
198 199 200 201 202 203 204

  FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER
		  |FORMAT_MESSAGE_IGNORE_INSERTS
		  |FORMAT_MESSAGE_FROM_SYSTEM,
		  NULL, error, 0,
		  (LPWSTR) &msg, 0, NULL);
  if (msg != NULL)
205
    {
206
      nchars = wcslen (msg);
207

208 209
      if (nchars >= 2 && msg[nchars-1] == L'\n' && msg[nchars-2] == L'\r')
        msg[nchars-2] = L'\0';
210

211
      retval = g_utf16_to_utf8 (msg, -1, NULL, NULL, NULL);
212

213
      LocalFree (msg);
214 215
    }
  else
216
    retval = g_strdup ("");
217 218 219

  return retval;
}
220

221 222
/**
 * g_win32_get_package_installation_directory_of_module:
223
 * @hmodule: (nullable): The Win32 handle for a DLL loaded into the current process, or %NULL
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
 *
 * 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.
Matthias Clasen's avatar
Matthias Clasen committed
254 255
 *
 * Since: 2.16
256 257 258 259
 */
gchar *
g_win32_get_package_installation_directory_of_module (gpointer hmodule)
{
260
  gchar *filename;
261 262 263 264
  gchar *retval;
  gchar *p;
  wchar_t wc_fn[MAX_PATH];

265
  /* NOTE: it relies that GetModuleFileNameW returns only canonical paths */
266 267 268
  if (!GetModuleFileNameW (hmodule, wc_fn, MAX_PATH))
    return NULL;

269
  filename = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL);
270

271
  if ((p = strrchr (filename, G_DIR_SEPARATOR)) != NULL)
272 273
    *p = '\0';

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  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);
297 298 299 300 301 302

#ifdef G_WITH_CYGWIN
  /* In Cygwin we need to have POSIX paths */
  {
    gchar tmp[MAX_PATH];

303 304 305
    cygwin_conv_to_posix_path (retval, tmp);
    g_free (retval);
    retval = g_strdup (tmp);
306 307 308 309 310 311
  }
#endif

  return retval;
}

312
static gchar *
313
get_package_directory_from_module (const gchar *module_name)
314
{
315
  static GHashTable *module_dirs = NULL;
316
  G_LOCK_DEFINE_STATIC (module_dirs);
317
  HMODULE hmodule = NULL;
318
  gchar *fn;
319

320 321
  G_LOCK (module_dirs);

322 323 324
  if (module_dirs == NULL)
    module_dirs = g_hash_table_new (g_str_hash, g_str_equal);
  
325
  fn = g_hash_table_lookup (module_dirs, module_name ? module_name : "");
326
      
327
  if (fn)
328 329
    {
      G_UNLOCK (module_dirs);
330
      return g_strdup (fn);
331
    }
332 333 334

  if (module_name)
    {
335 336 337 338
      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);

Tor Lillqvist's avatar
Tor Lillqvist committed
339 340 341 342 343
      if (!hmodule)
	{
	  G_UNLOCK (module_dirs);
	  return NULL;
	}
344 345
    }

346
  fn = g_win32_get_package_installation_directory_of_module (hmodule);
347

348
  if (fn == NULL)
349 350 351 352
    {
      G_UNLOCK (module_dirs);
      return NULL;
    }
353
  
354
  g_hash_table_insert (module_dirs, module_name ? g_strdup (module_name) : "", fn);
355

356 357
  G_UNLOCK (module_dirs);

358 359 360 361 362
  return g_strdup (fn);
}

/**
 * g_win32_get_package_installation_directory:
363 364
 * @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.
365 366 367
 *
 * Try to determine the installation directory for a software package.
 *
368
 * This function is deprecated. Use
369 370
 * g_win32_get_package_installation_directory_of_module() instead.
 *
371 372
 * The use of @package is deprecated. You should always pass %NULL. A
 * warning is printed if non-NULL is passed as @package.
373
 *
374
 * The original intended use of @package was for a short identifier of
375
 * the package, typically the same identifier as used for
376
 * `GETTEXT_PACKAGE` in software configured using GNU
377
 * autotools. The function first looks in the Windows Registry for the
378 379
 * value `#InstallationDirectory` in the key
 * `#HKLM\Software\@package`, and if that value
380
 * exists and is a string, returns that.
381
 *
382 383 384
 * 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
385 386 387
 * parallel installations of the library. Enabling multiple
 * installations of different versions of some GLib-using library, or
 * GLib itself, is desirable for various reasons.
388
 *
389
 * For this reason it is recommeded to always pass %NULL as
390
 * @package to this function, to avoid the temptation to use the
391
 * Registry. In version 2.20 of GLib the @package parameter
392
 * will be ignored and this function won't look in the Registry at all.
393
 *
394 395
 * 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
396 397 398 399 400 401
 * 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
402
 * @dll_name was %NULL.
403
 *
Matthias Clasen's avatar
Matthias Clasen committed
404
 * If both @package and @dll_name are %NULL, the directory from where
405
 * the main executable of the process was loaded is used instead in
406 407
 * the same way as above.
 *
408
 * Returns: a string containing the installation directory for
409 410 411
 * @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.
412
 *
413
 * Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to
414
 * g_win32_get_package_installation_directory_of_module() instead.
415 416
 **/

417 418 419
gchar *
g_win32_get_package_installation_directory (const gchar *package,
                                            const gchar *dll_name)
420 421
{
  gchar *result = NULL;
422

423 424
  if (package != NULL)
      g_warning ("Passing a non-NULL package to g_win32_get_package_installation_directory() is deprecated and it is ignored.");
425

426 427
  if (dll_name != NULL)
    result = get_package_directory_from_module (dll_name);
428

429 430
  if (result == NULL)
    result = get_package_directory_from_module (NULL);
431 432 433

  return result;
}
434 435 436

/**
 * g_win32_get_package_installation_subdirectory:
437 438
 * @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.
439
 * @subdir: A subdirectory of the package installation directory, also in UTF-8
440
 *
441 442 443
 * This function is deprecated. Use
 * g_win32_get_package_installation_directory_of_module() and
 * g_build_filename() instead.
444
 *
Matthias Clasen's avatar
Matthias Clasen committed
445
 * Returns a newly-allocated string containing the path of the
446
 * subdirectory @subdir in the return value from calling
447
 * g_win32_get_package_installation_directory() with the @package and
448 449
 * @dll_name parameters. See the documentation for
 * g_win32_get_package_installation_directory() for more details. In
450 451
 * particular, note that it is deprecated to pass anything except NULL
 * as @package.
Matthias Clasen's avatar
Matthias Clasen committed
452
 *
453
 * Returns: a string containing the complete path to @subdir inside
454
 * the installation directory of @package. The returned string is in
455 456 457
 * 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.
458
 *
459
 * Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to
460 461
 * g_win32_get_package_installation_directory_of_module() instead, and
 * then construct a subdirectory pathname with g_build_filename().
462
 **/
463 464

gchar *
465
g_win32_get_package_installation_subdirectory (const gchar *package,
466 467
                                               const gchar *dll_name,
                                               const gchar *subdir)
468 469
{
  gchar *prefix;
470
  gchar *dirname;
471

472
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
473
  prefix = g_win32_get_package_installation_directory (package, dll_name);
474
G_GNUC_END_IGNORE_DEPRECATIONS
475

476 477 478 479
  dirname = g_build_filename (prefix, subdir, NULL);
  g_free (prefix);

  return dirname;
480
}
481

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
/**
 * 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;
514 515 516 517 518
  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 */
519
  typedef NTSTATUS (WINAPI fRtlGetVersion) (PRTL_OSVERSIONINFOEXW);
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

  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
538 539 540

  memset (&osverinfo, 0, sizeof (OSVERSIONINFOEXW));
  osverinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
541 542 543 544 545 546
  RtlGetVersion (&osverinfo);

  /* check the OS and Service Pack Versions */
  if (osverinfo.dwMajorVersion > major)
    is_ver_checked = TRUE;
  else if (osverinfo.dwMajorVersion == major)
547 548 549 550 551
    {
      if (osverinfo.dwMinorVersion > minor)
        is_ver_checked = TRUE;
      else if (osverinfo.dwMinorVersion == minor)
        if (osverinfo.wServicePackMajor >= spver)
552
          is_ver_checked = TRUE;
553
    }
554 555 556

  /* Check OS Type */
  if (is_ver_checked)
557
    {
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
      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;
        }
577 578
    }

579 580 581
#if WINAPI_FAMILY != MODERN_API_FAMILY
  FreeLibrary (hmodule);
#endif
582

583 584
  return is_ver_checked && is_type_checked;
}
585

586 587 588
/**
 * g_win32_get_windows_version:
 *
589 590 591
 * This function is deprecated. Use
 * g_win32_check_windows_version() instead.
 *
592 593 594
 * 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,
595 596 597 598
 * 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
Matthias Clasen's avatar
Matthias Clasen committed
599
 * detailed version and feature information should use Win32 API like
600 601 602
 * GetVersionEx() and VerifyVersionInfo().
 *
 * Returns: The version information.
603 604 605 606 607 608
 *
 * 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.
609
 **/
610 611 612
guint
g_win32_get_windows_version (void)
{
613 614 615 616 617
  static gsize windows_version;

  if (g_once_init_enter (&windows_version))
    g_once_init_leave (&windows_version, GetVersion ());

618
  return windows_version;
619
}
620

621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
/*
 * Doesn't use gettext (and gconv), preventing recursive calls when
 * g_win32_locale_filename_from_utf8() is called during
 * gettext initialization.
 */
static gchar *
special_wchar_to_locale_enoding (wchar_t *wstring)
{
  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,
                                       &not_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,
                                      &not_representable);

  if (wctmb_result == sizeof_output &&
      not_representable == FALSE)
    return result;

  g_free (result);

  return NULL;
}

664 665 666 667
/**
 * g_win32_locale_filename_from_utf8:
 * @utf8filename: a UTF-8 encoded filename.
 *
Matthias Clasen's avatar
Matthias Clasen committed
668
 * Converts a filename from UTF-8 to the system codepage.
669 670 671 672 673 674 675 676 677 678 679
 *
 * 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
680 681 682 683
 * "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.
684
 *
685 686
 * The return value is dynamically allocated and should be freed with
 * g_free() when no longer needed.
687
 *
688
 * Returns: The converted filename, or %NULL on conversion
689 690
 * failure and lack of short names.
 *
Matthias Clasen's avatar
Matthias Clasen committed
691
 * Since: 2.8
692 693 694 695
 */
gchar *
g_win32_locale_filename_from_utf8 (const gchar *utf8filename)
{
696 697 698 699 700 701 702 703 704
  gchar *retval;
  wchar_t *wname;

  wname = g_utf8_to_utf16 (utf8filename, -1, NULL, NULL, NULL);

  if (wname == NULL)
    return NULL;

  retval = special_wchar_to_locale_enoding (wname);
705

706
  if (retval == NULL)
707
    {
708 709 710 711 712
      /* 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)))
        retval = special_wchar_to_locale_enoding (wshortname);
713
    }
714 715 716

  g_free (wname);

717 718
  return retval;
}
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771

/**
 * 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;

772
  LocalFree (args);
773 774
  return result;
}
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808

#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
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021

#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);
    }
}

#endif