X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgwin32.c;h=3c60df4c9d92412c24475b2ca9a07c1eaf3abca5;hb=7e3d32b7053b47ca7feecf185abac96b619770c2;hp=13fd2b8afdccb0b0618d6200833029afec907772;hpb=23de741c2935062ad889c3b3057b3836e2f00f86;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gwin32.c b/glib/gwin32.c index 13fd2b8..3c60df4 100644 --- a/glib/gwin32.c +++ b/glib/gwin32.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* @@ -29,15 +27,14 @@ * MT safe for the unix part, FIXME: make the win32 part MT safe as well. */ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" #include "glibconfig.h" #include #include #include +#include #include #define STRICT /* Strict typing, please */ @@ -48,11 +45,12 @@ #endif #include #include -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__DMC__) # include -#endif /* _MSC_VER */ +#endif /* _MSC_VER || __DMC__ */ #include "glib.h" +#include "gthreadprivate.h" #ifdef G_WITH_CYGWIN #include @@ -64,33 +62,7 @@ gint g_win32_ftruncate (gint fd, guint size) { - HANDLE hfile; - guint curpos; - - g_return_val_if_fail (fd >= 0, -1); - - hfile = (HANDLE) _get_osfhandle (fd); - curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT); - if (curpos == 0xFFFFFFFF - || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF - || !SetEndOfFile (hfile)) - { - gint error = GetLastError (); - - switch (error) - { - case ERROR_INVALID_HANDLE: - errno = EBADF; - break; - default: - errno = EIO; - break; - } - - return -1; - } - - return 0; + return _chsize (fd, size); } #endif @@ -98,16 +70,21 @@ g_win32_ftruncate (gint fd, /** * g_win32_getlocale: * - * The setlocale 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(). + * 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(). * * Returns: newly-allocated locale name. **/ +#ifndef SUBLANG_SERBIAN_LATIN_BA +#define SUBLANG_SERBIAN_LATIN_BA 0x06 +#endif + gchar * g_win32_getlocale (void) { @@ -115,505 +92,226 @@ g_win32_getlocale (void) LANGID langid; gchar *ev; gint primary, sub; - gchar *l = NULL, *sl = NULL; - gchar bfr[20]; + char iso639[10]; + char iso3166[10]; + const gchar *script = NULL; /* Let the user override the system settings through environment - variables, as on POSIX systems. */ + * 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. + */ if (((ev = getenv ("LC_ALL")) != NULL && ev[0] != '\0') || ((ev = getenv ("LC_MESSAGES")) != NULL && ev[0] != '\0') || ((ev = getenv ("LANG")) != NULL && ev[0] != '\0')) return g_strdup (ev); - /* Use native Win32 API locale ID. */ lcid = GetThreadLocale (); + if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) || + !GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166))) + return g_strdup ("C"); + /* 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); + + /* Handle special cases */ switch (primary) { - case LANG_AFRIKAANS: l = "af"; sl = "ZA"; break; - case LANG_ALBANIAN: l = "sq"; sl = "AL"; break; - case LANG_ARABIC: - l = "ar"; - switch (sub) - { - case SUBLANG_ARABIC_SAUDI_ARABIA: sl = "SA"; break; - case SUBLANG_ARABIC_IRAQ: sl = "IQ"; break; - case SUBLANG_ARABIC_EGYPT: sl = "EG"; break; - case SUBLANG_ARABIC_LIBYA: sl = "LY"; break; - case SUBLANG_ARABIC_ALGERIA: sl = "DZ"; break; - case SUBLANG_ARABIC_MOROCCO: sl = "MA"; break; - case SUBLANG_ARABIC_TUNISIA: sl = "TN"; break; - case SUBLANG_ARABIC_OMAN: sl = "OM"; break; - case SUBLANG_ARABIC_YEMEN: sl = "YE"; break; - case SUBLANG_ARABIC_SYRIA: sl = "SY"; break; - case SUBLANG_ARABIC_JORDAN: sl = "JO"; break; - case SUBLANG_ARABIC_LEBANON: sl = "LB"; break; - case SUBLANG_ARABIC_KUWAIT: sl = "KW"; break; - case SUBLANG_ARABIC_UAE: sl = "AE"; break; - case SUBLANG_ARABIC_BAHRAIN: sl = "BH"; break; - case SUBLANG_ARABIC_QATAR: sl = "QA"; break; - } - break; -#ifdef LANG_ARMENIAN - case LANG_ARMENIAN: l = "hy"; sl = "AM"; break; -#endif -#ifdef LANG_ASSAMESE - case LANG_ASSAMESE: l = "as"; sl = "IN"; break; -#endif -#ifdef LANG_AZERI case LANG_AZERI: - l = "az"; -#if defined (SUBLANG_AZERI_LATIN) && defined (SUBLANG_AZERI_CYRILLIC) - switch (sub) - { - /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */ - case SUBLANG_AZERI_LATIN: sl = "@latin"; break; - case SUBLANG_AZERI_CYRILLIC: sl = "@cyrillic"; break; - } -#endif - break; -#endif - case LANG_BASQUE: - l = "eu"; /* sl could be "ES" or "FR". */ - break; - case LANG_BELARUSIAN: l = "be"; sl = "BY"; break; -#ifdef LANG_BENGALI - case LANG_BENGALI: l = "bn"; sl = "IN"; break; -#endif - case LANG_BULGARIAN: l = "bg"; sl = "BG"; break; - case LANG_CATALAN: l = "ca"; sl = "ES"; break; - case LANG_CHINESE: - l = "zh"; - switch (sub) - { - case SUBLANG_CHINESE_TRADITIONAL: sl = "TW"; break; - case SUBLANG_CHINESE_SIMPLIFIED: sl = "CN"; break; - case SUBLANG_CHINESE_HONGKONG: sl = "HK"; break; - case SUBLANG_CHINESE_SINGAPORE: sl = "SG"; break; -#ifdef SUBLANG_CHINESE_MACAU - case SUBLANG_CHINESE_MACAU: sl = "MO"; break; -#endif - } - break; - case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN - * What used to be called Serbo-Croatian - * should really now be two separate - * languages because of political reasons. - * (Says tml, who knows nothing about Serbian - * or Croatian.) - * (I can feel those flames coming already.) - */ - switch (sub) - { - /* FIXME: How to distinguish Croatian and Latin Serbian locales? */ - case SUBLANG_SERBIAN_LATIN: l = "sr"; break; - case SUBLANG_SERBIAN_CYRILLIC: l = "sr"; sl = "@cyrillic"; break; - default: l = "hr"; sl = "HR"; - } - break; - case LANG_CZECH: l = "cs"; sl = "CZ"; break; - case LANG_DANISH: l = "da"; sl = "DK"; break; -#ifdef LANG_DIVEHI - case LANG_DIVEHI: l = "div"; sl = "MV"; break; -#endif - case LANG_DUTCH: - l = "nl"; - switch (sub) - { - case SUBLANG_DUTCH: sl = "NL"; break; - case SUBLANG_DUTCH_BELGIAN: sl = "BE"; break; - } - break; - case LANG_ENGLISH: - l = "en"; - switch (sub) - { - case SUBLANG_ENGLISH_US: sl = "US"; break; - case SUBLANG_ENGLISH_UK: sl = "GB"; break; - case SUBLANG_ENGLISH_AUS: sl = "AU"; break; - case SUBLANG_ENGLISH_CAN: sl = "CA"; break; - case SUBLANG_ENGLISH_NZ: sl = "NZ"; break; - case SUBLANG_ENGLISH_EIRE: sl = "IE"; break; - case SUBLANG_ENGLISH_SOUTH_AFRICA: sl = "ZA"; break; - case SUBLANG_ENGLISH_JAMAICA: sl = "JM"; break; - case SUBLANG_ENGLISH_CARIBBEAN: sl = "GD"; break; /* Grenada? */ - case SUBLANG_ENGLISH_BELIZE: sl = "BZ"; break; - case SUBLANG_ENGLISH_TRINIDAD: sl = "TT"; break; -#ifdef SUBLANG_ENGLISH_ZIMBABWE - case SUBLANG_ENGLISH_ZIMBABWE: sl = "ZW"; break; -#endif -#ifdef SUBLANG_ENGLISH_PHILIPPINES - case SUBLANG_ENGLISH_PHILIPPINES: sl = "PH"; break; -#endif - } - break; - case LANG_ESTONIAN: l = "et"; sl = "EE"; break; - case LANG_FAEROESE: l = "fo"; sl = "FO"; break; - case LANG_FARSI: l = "fa"; sl = "IR"; break; - case LANG_FINNISH: l = "fi"; sl = "FI"; break; - case LANG_FRENCH: - l = "fr"; - switch (sub) - { - case SUBLANG_FRENCH: sl = "FR"; break; - case SUBLANG_FRENCH_BELGIAN: sl = "BE"; break; - case SUBLANG_FRENCH_CANADIAN: sl = "CA"; break; - case SUBLANG_FRENCH_SWISS: sl = "CH"; break; - case SUBLANG_FRENCH_LUXEMBOURG: sl = "LU"; break; -#ifdef SUBLANG_FRENCH_MONACO - case SUBLANG_FRENCH_MONACO: sl = "MC"; break; -#endif - } - break; - /* FIXME: LANG_GALICIAN: What's the code for Galician? */ -#ifdef LANG_GEORGIAN - case LANG_GEORGIAN: l = "ka"; sl = "GE"; break; -#endif - case LANG_GERMAN: - l = "de"; switch (sub) { - case SUBLANG_GERMAN: sl = "DE"; break; - case SUBLANG_GERMAN_SWISS: sl = "CH"; break; - case SUBLANG_GERMAN_AUSTRIAN: sl = "AT"; break; - case SUBLANG_GERMAN_LUXEMBOURG: sl = "LU"; break; - case SUBLANG_GERMAN_LIECHTENSTEIN: sl = "LI"; break; - } - break; - case LANG_GREEK: l = "el"; sl = "GR"; break; -#ifdef LANG_GUJARATI - case LANG_GUJARATI: l = "gu"; sl = "IN"; break; -#endif - case LANG_HEBREW: l = "he"; sl = "IL"; break; -#ifdef LANG_HINDI - case LANG_HINDI: l = "hi"; sl = "IN"; break; -#endif - case LANG_HUNGARIAN: l = "hu"; sl = "HU"; break; - case LANG_ICELANDIC: l = "is"; sl = "IS"; break; - case LANG_INDONESIAN: l = "id"; sl = "ID"; break; - case LANG_ITALIAN: - l = "it"; - switch (sub) - { - case SUBLANG_ITALIAN: sl = "IT"; break; - case SUBLANG_ITALIAN_SWISS: sl = "CH"; break; - } - break; - case LANG_JAPANESE: l = "ja"; sl = "JP"; break; -#ifdef LANG_KANNADA - case LANG_KANNADA: l = "kn"; sl = "IN"; break; -#endif -#ifdef LANG_KASHMIRI - case LANG_KASHMIRI: - l = "ks"; - switch (sub) - { - case SUBLANG_DEFAULT: sl = "PK"; break; -#ifdef SUBLANG_KASHMIRI_INDIA - case SUBLANG_KASHMIRI_INDIA: sl = "IN"; break; -#endif - } - break; -#endif -#ifdef LANG_KAZAK - case LANG_KAZAK: l = "kk"; sl = "KZ"; break; -#endif -#ifdef LANG_KONKANI - case LANG_KONKANI: - /* FIXME: Adjust this when such locales appear on Unix. */ - l = "kok"; sl = "IN"; - break; -#endif - case LANG_KOREAN: l = "ko"; sl = "KR"; break; -#ifdef LANG_KYRGYZ - case LANG_KYRGYZ: l = "ky"; sl = "KG"; /* ??? */ break; -#endif - case LANG_LATVIAN: l = "lv"; sl = "LV"; break; - case LANG_LITHUANIAN: l = "lt"; sl = "LT"; break; -#ifdef LANG_MACEDONIAN - case LANG_MACEDONIAN: l = "mk"; sl = "MK"; break; -#endif -#ifdef LANG_MALAY - case LANG_MALAY: - l = "ms"; - switch (sub) - { -#ifdef SUBLANG_MALAY_MALAYSIA - case SUBLANG_MALAY_MALAYSIA: sl = "MY"; break; -#endif -#ifdef SUBLANG_MALAY_BRUNEI_DARUSSALAM - case SUBLANG_MALAY_BRUNEI_DARUSSALAM: sl = "BN"; break; -#endif - } - break; -#endif -#ifdef LANG_MALAYALAM - case LANG_MALAYALAM: l = "ml"; sl = "IN"; break; -#endif -#ifdef LANG_MANIPURI - case LANG_MANIPURI: - /* FIXME: Adjust this when such locales appear on Unix. */ - l = "mni"; sl = "IN"; - break; -#endif -#ifdef LANG_MARATHI - case LANG_MARATHI: l = "mr"; sl = "IN"; break; -#endif -#ifdef LANG_MONGOLIAN - case LANG_MONGOLIAN: l = "mn"; sl = "MN"; break; -#endif -#ifdef LANG_NEPALI - case LANG_NEPALI: - l = "ne"; - switch (sub) - { - case SUBLANG_DEFAULT: sl = "NP"; break; -#ifdef SUBLANG_NEPALI_INDIA - case SUBLANG_NEPALI_INDIA: sl = "IN"; break; -#endif - } - break; -#endif - case LANG_NORWEGIAN: - l = "no"; - switch (sub) - { - case SUBLANG_NORWEGIAN_BOKMAL: sl = "NO"; break; - case SUBLANG_NORWEGIAN_NYNORSK: l = "nn"; sl = "NO"; break; - } - break; -#ifdef LANG_ORIYA - case LANG_ORIYA: l = "or"; sl = "IN"; break; -#endif - case LANG_POLISH: l = "pl"; sl = "PL"; break; - case LANG_PORTUGUESE: - l = "pt"; - switch (sub) - { - case SUBLANG_PORTUGUESE: sl = "PT"; break; - case SUBLANG_PORTUGUESE_BRAZILIAN: sl = "BR"; break; - } - break; -#ifdef LANG_PUNJABI - case LANG_PUNJABI: l = "pa"; sl = "IN"; break; -#endif - case LANG_ROMANIAN: l = "ro"; sl = "RO"; break; - case LANG_RUSSIAN: - l = "ru"; /* sl could be "RU" or "UA". */ - break; -#ifdef LANG_SANSKRIT - case LANG_SANSKRIT: l = "sa"; sl = "IN"; break; -#endif -#ifdef LANG_SINDHI - case LANG_SINDHI: l = "sd"; break; -#endif - case LANG_SLOVAK: l = "sk"; sl = "SK"; break; - case LANG_SLOVENIAN: l = "sl"; sl = "SI"; break; -#ifdef LANG_SORBIAN - case LANG_SORBIAN: - /* FIXME: Adjust this when such locales appear on Unix. */ - l = "wen"; sl = "DE"; - break; -#endif - case LANG_SPANISH: - l = "es"; - switch (sub) - { - case SUBLANG_SPANISH: sl = "ES"; break; - case SUBLANG_SPANISH_MEXICAN: sl = "MX"; break; - case SUBLANG_SPANISH_MODERN: - sl = "ES@modern"; break; /* not seen on Unix */ - case SUBLANG_SPANISH_GUATEMALA: sl = "GT"; break; - case SUBLANG_SPANISH_COSTA_RICA: sl = "CR"; break; - case SUBLANG_SPANISH_PANAMA: sl = "PA"; break; - case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: sl = "DO"; break; - case SUBLANG_SPANISH_VENEZUELA: sl = "VE"; break; - case SUBLANG_SPANISH_COLOMBIA: sl = "CO"; break; - case SUBLANG_SPANISH_PERU: sl = "PE"; break; - case SUBLANG_SPANISH_ARGENTINA: sl = "AR"; break; - case SUBLANG_SPANISH_ECUADOR: sl = "EC"; break; - case SUBLANG_SPANISH_CHILE: sl = "CL"; break; - case SUBLANG_SPANISH_URUGUAY: sl = "UY"; break; - case SUBLANG_SPANISH_PARAGUAY: sl = "PY"; break; - case SUBLANG_SPANISH_BOLIVIA: sl = "BO"; break; - case SUBLANG_SPANISH_EL_SALVADOR: sl = "SV"; break; - case SUBLANG_SPANISH_HONDURAS: sl = "HN"; break; - case SUBLANG_SPANISH_NICARAGUA: sl = "NI"; break; - case SUBLANG_SPANISH_PUERTO_RICO: sl = "PR"; break; - } - break; -#ifdef LANG_SWAHILI - case LANG_SWAHILI: l = "sw"; break; -#endif - case LANG_SWEDISH: - l = "sv"; - switch (sub) - { - case SUBLANG_DEFAULT: sl = "SE"; break; - case SUBLANG_SWEDISH_FINLAND: sl = "FI"; break; + case SUBLANG_AZERI_LATIN: + script = "@Latn"; + break; + case SUBLANG_AZERI_CYRILLIC: + script = "@Cyrl"; + break; } break; -#ifdef LANG_SYRIAC - case LANG_SYRIAC: l = "syr"; break; -#endif -#ifdef LANG_TAMIL - case LANG_TAMIL: - l = "ta"; /* sl could be "IN" or "LK". */ - break; -#endif -#ifdef LANG_TATAR - case LANG_TATAR: l = "tt"; break; -#endif -#ifdef LANG_TELUGU - case LANG_TELUGU: l = "te"; sl = "IN"; break; -#endif - case LANG_THAI: l = "th"; sl = "TH"; break; - case LANG_TURKISH: l = "tr"; sl = "TR"; break; - case LANG_UKRAINIAN: l = "uk"; sl = "UA"; break; -#ifdef LANG_URDU - case LANG_URDU: - l = "ur"; + case LANG_SERBIAN: /* LANG_CROATIAN == LANG_SERBIAN */ switch (sub) { -#ifdef SUBLANG_URDU_PAKISTAN - case SUBLANG_URDU_PAKISTAN: sl = "PK"; break; -#endif -#ifdef SUBLANG_URDU_INDIA - case SUBLANG_URDU_INDIA: sl = "IN"; break; -#endif + case SUBLANG_SERBIAN_LATIN: + case 0x06: /* Serbian (Latin) - Bosnia and Herzegovina */ + script = "@Latn"; + break; } break; -#endif -#ifdef LANG_UZBEK case LANG_UZBEK: - l = "uz"; switch (sub) { - /* FIXME: Adjust this when Uzbek locales appear on Unix. */ -#ifdef SUBLANG_UZBEK_LATIN - case SUBLANG_UZBEK_LATIN: sl = "UZ@latin"; break; -#endif -#ifdef SUBLANG_UZBEK_CYRILLIC - case SUBLANG_UZBEK_CYRILLIC: sl = "UZ@cyrillic"; break; -#endif + case SUBLANG_UZBEK_LATIN: + script = "@Latn"; + break; + case SUBLANG_UZBEK_CYRILLIC: + script = "@Cyrl"; + break; } break; -#endif - case LANG_VIETNAMESE: l = "vi"; sl = "VN"; break; - default: l = "xx"; break; - } - strcpy (bfr, l); - if (sl != NULL) - { - if (sl[0] != '@') - strcat (bfr, "_"); - strcat (bfr, sl); } - - return g_strdup (bfr); + return g_strconcat (iso639, "_", iso3166, script, NULL); } /** * g_win32_error_message: * @error: error code. * - * Translate a Win32 error code (as returned by GetLastError()) 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 should be deallocated with g_free(). + * 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(). * * Returns: newly-allocated error message **/ gchar * g_win32_error_message (gint error) { - gchar *msg; gchar *retval; - int nbytes; + wchar_t *msg = NULL; + int nchars; + + FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_IGNORE_INSERTS + |FORMAT_MESSAGE_FROM_SYSTEM, + NULL, error, 0, + (LPWSTR) &msg, 0, NULL); + if (msg != NULL) + { + nchars = wcslen (msg); + + if (nchars > 2 && msg[nchars-1] == '\n' && msg[nchars-2] == '\r') + msg[nchars-2] = '\0'; + + retval = g_utf16_to_utf8 (msg, -1, NULL, NULL, NULL); + + LocalFree (msg); + } + else + retval = g_strdup (""); - FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER - |FORMAT_MESSAGE_IGNORE_INSERTS - |FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, - (LPTSTR) &msg, 0, NULL); - nbytes = strlen (msg); + return retval; +} - if (nbytes > 2 && msg[nbytes-1] == '\n' && msg[nbytes-2] == '\r') - msg[nbytes-2] = '\0'; - - retval = g_strdup (msg); +/** + * g_win32_get_package_installation_directory_of_module: + * @hmodule: (allow-none): The Win32 handle for a DLL loaded into the current process, or %NULL + * + * 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. + * + * Since: 2.16 + */ +gchar * +g_win32_get_package_installation_directory_of_module (gpointer hmodule) +{ + gchar *retval; + gchar *p; + wchar_t wc_fn[MAX_PATH]; - if (msg != NULL) - LocalFree (msg); + if (!GetModuleFileNameW (hmodule, wc_fn, MAX_PATH)) + return NULL; + + retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL); + + if ((p = strrchr (retval, G_DIR_SEPARATOR)) != NULL) + *p = '\0'; + + p = strrchr (retval, G_DIR_SEPARATOR); + if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0 || + g_ascii_strcasecmp (p + 1, "lib") == 0)) + *p = '\0'; + +#ifdef G_WITH_CYGWIN + /* In Cygwin we need to have POSIX paths */ + { + gchar tmp[MAX_PATH]; + + cygwin_conv_to_posix_path (retval, tmp); + g_free (retval); + retval = g_strdup (tmp); + } +#endif return retval; } static gchar * -get_package_directory_from_module (gchar *module_name) +get_package_directory_from_module (const gchar *module_name) { static GHashTable *module_dirs = NULL; G_LOCK_DEFINE_STATIC (module_dirs); HMODULE hmodule = NULL; gchar *fn; - gchar *p; - gchar *result; G_LOCK (module_dirs); if (module_dirs == NULL) module_dirs = g_hash_table_new (g_str_hash, g_str_equal); - result = g_hash_table_lookup (module_dirs, module_name ? module_name : ""); + fn = g_hash_table_lookup (module_dirs, module_name ? module_name : ""); - if (result) + if (fn) { G_UNLOCK (module_dirs); - return g_strdup (result); + return g_strdup (fn); } if (module_name) { - hmodule = GetModuleHandle (module_name); + 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); + if (!hmodule) - return NULL; + { + G_UNLOCK (module_dirs); + return NULL; + } } - fn = g_malloc (MAX_PATH); - if (!GetModuleFileName (hmodule, fn, MAX_PATH)) + fn = g_win32_get_package_installation_directory_of_module (hmodule); + + if (fn == NULL) { G_UNLOCK (module_dirs); - g_free (fn); return NULL; } - - if ((p = strrchr (fn, G_DIR_SEPARATOR)) != NULL) - *p = '\0'; - - p = strrchr (fn, G_DIR_SEPARATOR); - if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0 || - g_ascii_strcasecmp (p + 1, "lib") == 0)) - *p = '\0'; - -#ifdef G_WITH_CYGWIN - /* In Cygwin we need to have POSIX paths */ - { - gchar tmp[MAX_PATH]; - - cygwin_conv_to_posix_path(fn, tmp); - g_free(fn); - fn = g_strdup(tmp); - } -#endif - - g_hash_table_insert (module_dirs, module_name ? module_name : "", fn); + + g_hash_table_insert (module_dirs, module_name ? g_strdup (module_name) : "", fn); G_UNLOCK (module_dirs); @@ -622,20 +320,37 @@ get_package_directory_from_module (gchar *module_name) /** * g_win32_get_package_installation_directory: - * @package: An identifier for a software package, or %NULL - * @dll_name: The name of a DLL that a package provides, or %NULL. + * @package: (allow-none): You should pass %NULL for this. + * @dll_name: (allow-none): The name of a DLL that a package provides in UTF-8, or %NULL. * * Try to determine the installation directory for a software package. - * Typically used by GNU software packages. - * - * @package should be a short identifier for the package. Typically it - * is the same identifier as used for - * GETTEXT_PACKAGE in software configured according - * to GNU standards. The function first looks in the Windows Registry - * for the value #InstallationDirectory in the key - * #HKLM\Software\@package, and if that value + * + * This function is deprecated. Use + * g_win32_get_package_installation_directory_of_module() instead. + * + * The use of @package is deprecated. You should always pass %NULL. A + * warning is printed if non-NULL is passed as @package. + * + * The original intended use of @package was for a short identifier of + * the package, typically the same identifier as used for + * `GETTEXT_PACKAGE` in software configured using GNU + * autotools. The function first looks in the Windows Registry for the + * value `#InstallationDirectory` in the key + * `#HKLM\Software\@package`, and if that value * exists and is a string, returns that. * + * 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 + * parallel installations of the library. Enabling multiple + * installations of different versions of some GLib-using library, or + * GLib itself, is desirable for various reasons. + * + * For this reason it is recommeded to always pass %NULL as + * @package to this function, to avoid the temptation to use the + * Registry. In version 2.20 of GLib the @package parameter + * will be ignored and this function won't look in the Registry at all. + * * 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 * into the current process. Typically that would be the name of the @@ -647,73 +362,26 @@ get_package_directory_from_module (gchar *module_name) * @dll_name was %NULL. * * If both @package and @dll_name are %NULL, the directory from where - * the main executable of the process was loaded is uses instead in + * the main executable of the process was loaded is used instead in * the same way as above. * - * Returns: a string containing the installation directory for @package. - * The return value should be freed with g_free() when not needed any longer. + * Returns: a string containing the installation directory for + * @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. + * + * Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to + * g_win32_get_package_installation_directory_of_module() instead. **/ -gchar * -g_win32_get_package_installation_directory (gchar *package, - gchar *dll_name) + gchar * +g_win32_get_package_installation_directory_utf8 (const gchar *package, + const gchar *dll_name) { - static GHashTable *package_dirs = NULL; - G_LOCK_DEFINE_STATIC (package_dirs); gchar *result = NULL; - gchar *key; - HKEY reg_key = NULL; - DWORD type; - DWORD nbytes; if (package != NULL) - { - G_LOCK (package_dirs); - - if (package_dirs == NULL) - package_dirs = g_hash_table_new (g_str_hash, g_str_equal); - - result = g_hash_table_lookup (package_dirs, package); - - if (result && result[0]) - { - G_UNLOCK (package_dirs); - return g_strdup (result); - } - - key = g_strconcat ("Software\\", package, NULL); - - nbytes = 0; - if ((RegOpenKeyEx (HKEY_CURRENT_USER, key, 0, - KEY_QUERY_VALUE, ®_key) == ERROR_SUCCESS - && RegQueryValueEx (reg_key, "InstallationDirectory", 0, - &type, NULL, &nbytes) == ERROR_SUCCESS) - || - ((RegOpenKeyEx (HKEY_LOCAL_MACHINE, key, 0, - KEY_QUERY_VALUE, ®_key) == ERROR_SUCCESS - && RegQueryValueEx (reg_key, "InstallationDirectory", 0, - &type, NULL, &nbytes) == ERROR_SUCCESS) - && type == REG_SZ)) - { - result = g_malloc (nbytes + 1); - RegQueryValueEx (reg_key, "InstallationDirectory", 0, - &type, result, &nbytes); - result[nbytes] = '\0'; - } - - if (reg_key != NULL) - RegCloseKey (reg_key); - - g_free (key); - - if (result) - { - g_hash_table_insert (package_dirs, package, result); - G_UNLOCK (package_dirs); - return g_strdup (result); - } - G_UNLOCK (package_dirs); - } + g_warning ("Passing a non-NULL package to g_win32_get_package_installation_directory() is deprecated and it is ignored."); if (dll_name != NULL) result = get_package_directory_from_module (dll_name); @@ -724,30 +392,243 @@ g_win32_get_package_installation_directory (gchar *package, return result; } +#if !defined (_WIN64) + +/* DLL ABI binary compatibility version that uses system codepage file names */ + +gchar * +g_win32_get_package_installation_directory (const gchar *package, + const gchar *dll_name) +{ + gchar *utf8_package = NULL, *utf8_dll_name = NULL; + gchar *utf8_retval, *retval; + + if (package != NULL) + utf8_package = g_locale_to_utf8 (package, -1, NULL, NULL, NULL); + + if (dll_name != NULL) + utf8_dll_name = g_locale_to_utf8 (dll_name, -1, NULL, NULL, NULL); + + utf8_retval = + g_win32_get_package_installation_directory_utf8 (utf8_package, + utf8_dll_name); + + retval = g_locale_from_utf8 (utf8_retval, -1, NULL, NULL, NULL); + + g_free (utf8_package); + g_free (utf8_dll_name); + g_free (utf8_retval); + + return retval; +} + +#endif + /** * g_win32_get_package_installation_subdirectory: - * @package: An identifier for a software package, or %NULL. - * @dll_name: The name of a DLL that a package provides, or %NULL. - * @subdir: A subdirectory of the package installation directory. + * @package: (allow-none): You should pass %NULL for this. + * @dll_name: (allow-none): The name of a DLL that a package provides, in UTF-8, or %NULL. + * @subdir: A subdirectory of the package installation directory, also in UTF-8 + * + * This function is deprecated. Use + * g_win32_get_package_installation_directory_of_module() and + * g_build_filename() instead. * * Returns a newly-allocated string containing the path of the * subdirectory @subdir in the return value from calling * g_win32_get_package_installation_directory() with the @package and - * @dll_name parameters. + * @dll_name parameters. See the documentation for + * g_win32_get_package_installation_directory() for more details. In + * particular, note that it is deprecated to pass anything except NULL + * as @package. * - * Returns: a string containing the complete path to @subdir inside the - * installation directory of @package. The return value should be freed with - * g_free() when no longer needed. + * Returns: a string containing the complete path to @subdir inside + * the installation directory of @package. The returned string is in + * 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. + * + * Deprecated: 2.18: Pass the HMODULE of a DLL or EXE to + * g_win32_get_package_installation_directory_of_module() instead, and + * then construct a subdirectory pathname with g_build_filename(). **/ gchar * -g_win32_get_package_installation_subdirectory (gchar *package, - gchar *dll_name, - gchar *subdir) +g_win32_get_package_installation_subdirectory_utf8 (const gchar *package, + const gchar *dll_name, + const gchar *subdir) { gchar *prefix; + gchar *dirname; + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + prefix = g_win32_get_package_installation_directory_utf8 (package, dll_name); +G_GNUC_END_IGNORE_DEPRECATIONS + + dirname = g_build_filename (prefix, subdir, NULL); + g_free (prefix); + + return dirname; +} +#if !defined (_WIN64) + +/* DLL ABI binary compatibility version that uses system codepage file names */ + +gchar * +g_win32_get_package_installation_subdirectory (const gchar *package, + const gchar *dll_name, + const gchar *subdir) +{ + gchar *prefix; + gchar *dirname; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS prefix = g_win32_get_package_installation_directory (package, dll_name); + G_GNUC_END_IGNORE_DEPRECATIONS + + dirname = g_build_filename (prefix, subdir, NULL); + g_free (prefix); + + return dirname; +} + +#endif + +/** + * g_win32_get_windows_version: + * + * 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, + * 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 + * detailed version and feature information should use Win32 API like + * GetVersionEx() and VerifyVersionInfo(). + * + * Returns: The version information. + * + * Since: 2.6 + **/ +guint +g_win32_get_windows_version (void) +{ + static gsize windows_version; + + if (g_once_init_enter (&windows_version)) + g_once_init_leave (&windows_version, GetVersion ()); - return g_build_filename (prefix, subdir, NULL); + return windows_version; +} + +/** + * g_win32_locale_filename_from_utf8: + * @utf8filename: a UTF-8 encoded filename. + * + * Converts a filename from UTF-8 to the system codepage. + * + * 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 + * "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. + * + * The return value is dynamically allocated and should be freed with + * g_free() when no longer needed. + * + * Returns: The converted filename, or %NULL on conversion + * failure and lack of short names. + * + * Since: 2.8 + */ +gchar * +g_win32_locale_filename_from_utf8 (const gchar *utf8filename) +{ + gchar *retval = g_locale_from_utf8 (utf8filename, -1, NULL, NULL, NULL); + + if (retval == NULL) + { + /* Conversion failed, so convert to wide chars, check if there + * is a 8.3 version, and use that. + */ + wchar_t *wname = g_utf8_to_utf16 (utf8filename, -1, NULL, NULL, NULL); + if (wname != NULL) + { + wchar_t wshortname[MAX_PATH + 1]; + if (GetShortPathNameW (wname, wshortname, G_N_ELEMENTS (wshortname))) + { + gchar *tem = g_utf16_to_utf8 (wshortname, -1, NULL, NULL, NULL); + retval = g_locale_from_utf8 (tem, -1, NULL, NULL, NULL); + g_free (tem); + } + g_free (wname); + } + } + return retval; +} + +/** + * 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; + + return result; }