Mercurial > pidgin.yaz
changeset 29621:66dd4729d25d
Fix the win32 launcher to support unicode input. This allows the config
dirs and the various path setups to hande non-ASCII characters.
A good reminder of how ugly the whole TCHAR mess is.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Sun, 01 Nov 2009 08:04:37 +0000 |
parents | e7b9cf2f2386 |
children | 380d38f07f58 |
files | pidgin/win32/winpidgin.c |
diffstat | 1 files changed, 305 insertions(+), 247 deletions(-) [+] |
line wrap: on
line diff
--- a/pidgin/win32/winpidgin.c Sun Nov 01 04:56:45 2009 +0000 +++ b/pidgin/win32/winpidgin.c Sun Nov 01 08:04:37 2009 +0000 @@ -26,10 +26,13 @@ */ /* This is for ATTACH_PARENT_PROCESS */ +#define UNICODE +#define _UNICODE #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x501 #endif #include <windows.h> +#include <tchar.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> @@ -55,7 +58,7 @@ typedef int (CALLBACK* LPFNPIDGINMAIN)(HINSTANCE, int, char**); -typedef void (CALLBACK* LPFNSETDLLDIRECTORY)(LPCTSTR); +typedef void (CALLBACK* LPFNSETDLLDIRECTORY)(LPCWSTR); typedef BOOL (CALLBACK* LPFNATTACHCONSOLE)(DWORD); static BOOL portable_mode = FALSE; @@ -66,19 +69,19 @@ static LPFNPIDGINMAIN pidgin_main = NULL; static LPFNSETDLLDIRECTORY MySetDllDirectory = NULL; -static const char *get_win32_error_message(DWORD err) { - static char err_msg[512]; +static const TCHAR *get_win32_error_message(DWORD err) { + static TCHAR err_msg[512]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &err_msg, sizeof(err_msg), NULL); + (LPTSTR) &err_msg, sizeof(err_msg) / sizeof(TCHAR), NULL); return err_msg; } -static BOOL read_reg_string(HKEY key, char* sub_key, char* val_name, LPBYTE data, LPDWORD data_len) { +static BOOL read_reg_string(HKEY key, TCHAR *sub_key, TCHAR *val_name, LPBYTE data, LPDWORD data_len) { HKEY hkey; BOOL ret = FALSE; LONG retv; @@ -89,11 +92,11 @@ NULL, NULL, data, data_len))) ret = TRUE; else { - const char *err_msg = get_win32_error_message(retv); + const TCHAR *err_msg = get_win32_error_message(retv); - printf("Could not read reg key '%s' subkey '%s' value: '%s'.\nMessage: (%ld) %s\n", - (key == HKEY_LOCAL_MACHINE) ? "HKLM" - : ((key == HKEY_CURRENT_USER) ? "HKCU" : "???"), + _tprintf(_T("Could not read reg key '%s' subkey '%s' value: '%s'.\nMessage: (%ld) %s\n"), + (key == HKEY_LOCAL_MACHINE) ? _T("HKLM") + : ((key == HKEY_CURRENT_USER) ? _T("HKCU") : _T("???")), sub_key, val_name, retv, err_msg); } RegCloseKey(hkey); @@ -102,36 +105,36 @@ TCHAR szBuf[80]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, retv, 0, - (LPTSTR) &szBuf, sizeof(szBuf), NULL); - printf("Could not open reg subkey: %s\nError: (%ld) %s\n", + (LPTSTR) &szBuf, sizeof(szBuf) / sizeof(TCHAR), NULL); + _tprintf(_T("Could not open reg subkey: %s\nError: (%ld) %s\n"), sub_key, retv, szBuf); } return ret; } -static void common_dll_prep(const char *path) { +static void common_dll_prep(const TCHAR *path) { HMODULE hmod; HKEY hkey; struct _stat stat_buf; - char test_path[MAX_PATH + 1]; + TCHAR test_path[MAX_PATH + 1]; - _snprintf(test_path, sizeof(test_path), "%s\\libgtk-win32-2.0-0.dll", - path); - test_path[sizeof(test_path) - 1] = '\0'; + _sntprintf(test_path, sizeof(test_path) / sizeof(TCHAR), + _T("%s\\libgtk-win32-2.0-0.dll"), path); + test_path[sizeof(test_path) / sizeof(TCHAR) - 1] = _T('\0'); - if (_stat(test_path, &stat_buf) != 0) { + if (_tstat(test_path, &stat_buf) != 0) { printf("Unable to determine GTK+ path. \n" "Assuming GTK+ is in the PATH.\n"); return; } - printf("GTK+ path found: %s\n", path); + _tprintf(_T("GTK+ path found: %s\n"), path); - if ((hmod = GetModuleHandle("kernel32.dll"))) { + if ((hmod = GetModuleHandle(_T("kernel32.dll")))) { MySetDllDirectory = (LPFNSETDLLDIRECTORY) GetProcAddress( - hmod, "SetDllDirectoryA"); + hmod, "SetDllDirectoryW"); if (!MySetDllDirectory) printf("SetDllDirectory not supported\n"); } else @@ -157,20 +160,21 @@ */ osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osinfo); - if ((osinfo.dwMajorVersion == 5 && - osinfo.dwMinorVersion == 0 && - strcmp(osinfo.szCSDVersion, "Service Pack 3") >= 0) || - (osinfo.dwMajorVersion == 5 && - osinfo.dwMinorVersion == 1 && - strcmp(osinfo.szCSDVersion, "") >= 0) + if ((osinfo.dwMajorVersion == 5 + && osinfo.dwMinorVersion == 0 + && _tcscmp(osinfo.szCSDVersion, _T("Service Pack 3")) >= 0) + || + (osinfo.dwMajorVersion == 5 + && osinfo.dwMinorVersion == 1 + && _tcscmp(osinfo.szCSDVersion, _T("")) >= 0) ) { DWORD regval = 1; DWORD reglen = sizeof(DWORD); printf("Using Win2k (SP3+) / WinXP (No SP)... Checking SafeDllSearch\n"); read_reg_string(HKEY_LOCAL_MACHINE, - "System\\CurrentControlSet\\Control\\Session Manager", - "SafeDllSearchMode", + _T("System\\CurrentControlSet\\Control\\Session Manager"), + _T("SafeDllSearchMode"), (LPBYTE) ®val, ®len); @@ -178,16 +182,16 @@ printf("Trying to set SafeDllSearchMode to 0\n"); regval = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - "System\\CurrentControlSet\\Control\\Session Manager", + _T("System\\CurrentControlSet\\Control\\Session Manager"), 0, KEY_SET_VALUE, &hkey ) == ERROR_SUCCESS) { if (RegSetValueEx(hkey, - "SafeDllSearchMode", 0, + _T("SafeDllSearchMode"), 0, REG_DWORD, (LPBYTE) ®val, sizeof(DWORD) ) != ERROR_SUCCESS) printf("Error writing SafeDllSearchMode. Error: %u\n", - (UINT) GetLastError()); + (UINT) GetLastError()); RegCloseKey(hkey); } else printf("Error opening Session Manager key for writing. Error: %u\n", @@ -198,29 +202,23 @@ } } -static void portable_mode_dll_prep(const char *pidgin_dir) { +static void portable_mode_dll_prep(const TCHAR *pidgin_dir) { /* need to be able to fit MAX_PATH + "PIDGIN_ASPELL_DIR=\\Aspell\\bin" in path2 */ - char path[MAX_PATH + 1]; - char path2[MAX_PATH + 33]; - const char *prev = NULL; + TCHAR path[MAX_PATH + 1]; + TCHAR path2[MAX_PATH + 33]; + const TCHAR *prev = NULL; /* We assume that GTK+ is installed under \\path\to\Pidgin\..\GTK * First we find \\path\to */ - if (*pidgin_dir) { + if (*pidgin_dir) /* pidgin_dir points to \\path\to\Pidgin */ - const char *tmp = pidgin_dir; - - while ((tmp = strchr(tmp, '\\'))) { - prev = tmp; - tmp++; - } - } + prev = _tcsrchr(pidgin_dir, _T('\\')); if (prev) { int cnt = (prev - pidgin_dir); - strncpy(path, pidgin_dir, cnt); - path[cnt] = '\0'; + _tcsncpy(path, pidgin_dir, cnt); + path[cnt] = _T('\0'); } else { printf("Unable to determine current executable path. \n" "This will prevent the settings dir from being set.\n" @@ -229,141 +227,141 @@ } /* Set $HOME so that the GTK+ settings get stored in the right place */ - _snprintf(path2, sizeof(path2), "HOME=%s", path); - _putenv(path2); + _sntprintf(path2, sizeof(path2) / sizeof(TCHAR), _T("HOME=%s"), path); + _tputenv(path2); /* Set up the settings dir base to be \\path\to * The actual settings dir will be \\path\to\.purple */ - _snprintf(path2, sizeof(path2), "PURPLEHOME=%s", path); - printf("Setting settings dir: %s\n", path2); - _putenv(path2); + _sntprintf(path2, sizeof(path2) / sizeof(TCHAR), _T("PURPLEHOME=%s"), path); + _tprintf(_T("Setting settings dir: %s\n"), path2); + _tputenv(path2); - _snprintf(path2, sizeof(path2), "PIDGIN_ASPELL_DIR=%s\\Aspell\\bin", path); - printf("%s\n", path2); - _putenv(path2); + _sntprintf(path2, sizeof(path2) / sizeof(TCHAR), _T("PIDGIN_ASPELL_DIR=%s\\Aspell\\bin"), path); + _tprintf(_T("%s\n"), path2); + _tputenv(path2); /* set the GTK+ path to be \\path\to\GTK\bin */ - strcat(path, "\\GTK\\bin"); + _tcscat(path, _T("\\GTK\\bin")); common_dll_prep(path); } -static void dll_prep(const char *pidgin_dir) { - char gtk_path[MAX_PATH + 1]; - gtk_path[0] = '\0'; +static void dll_prep(const TCHAR *pidgin_dir) { + TCHAR gtk_path[MAX_PATH + 1]; + gtk_path[0] = _T('\0'); if (*pidgin_dir) { - _snprintf(gtk_path, sizeof(gtk_path), "%s\\Gtk\\bin", pidgin_dir); - gtk_path[sizeof(gtk_path)] = '\0'; + _sntprintf(gtk_path, sizeof(gtk_path) / sizeof(TCHAR), _T("%s\\Gtk\\bin"), pidgin_dir); + gtk_path[sizeof(gtk_path) / sizeof(TCHAR)] = _T('\0'); } common_dll_prep(gtk_path); } -static char* winpidgin_lcid_to_posix(LCID lcid) { - char *posix = NULL; +static TCHAR* winpidgin_lcid_to_posix(LCID lcid) { + TCHAR *posix = NULL; int lang_id = PRIMARYLANGID(lcid); int sub_id = SUBLANGID(lcid); switch (lang_id) { - case LANG_AFRIKAANS: posix = "af"; break; - case LANG_ARABIC: posix = "ar"; break; - case LANG_AZERI: posix = "az"; break; - case LANG_BENGALI: posix = "bn"; break; - case LANG_BULGARIAN: posix = "bg"; break; - case LANG_CATALAN: posix = "ca"; break; - case LANG_CZECH: posix = "cs"; break; - case LANG_DANISH: posix = "da"; break; - case LANG_ESTONIAN: posix = "et"; break; - case LANG_PERSIAN: posix = "fa"; break; - case LANG_GERMAN: posix = "de"; break; - case LANG_GREEK: posix = "el"; break; + case LANG_AFRIKAANS: posix = _T("af"); break; + case LANG_ARABIC: posix = _T("ar"); break; + case LANG_AZERI: posix = _T("az"); break; + case LANG_BENGALI: posix = _T("bn"); break; + case LANG_BULGARIAN: posix = _T("bg"); break; + case LANG_CATALAN: posix = _T("ca"); break; + case LANG_CZECH: posix = _T("cs"); break; + case LANG_DANISH: posix = _T("da"); break; + case LANG_ESTONIAN: posix = _T("et"); break; + case LANG_PERSIAN: posix = _T("fa"); break; + case LANG_GERMAN: posix = _T("de"); break; + case LANG_GREEK: posix = _T("el"); break; case LANG_ENGLISH: switch (sub_id) { case SUBLANG_ENGLISH_UK: - posix = "en_GB"; break; + posix = _T("en_GB"); break; case SUBLANG_ENGLISH_AUS: - posix = "en_AU"; break; + posix = _T("en_AU"); break; case SUBLANG_ENGLISH_CAN: - posix = "en_CA"; break; + posix = _T("en_CA"); break; default: - posix = "en"; break; + posix = _T("en"); break; } break; - case LANG_SPANISH: posix = "es"; break; - case LANG_BASQUE: posix = "eu"; break; - case LANG_FINNISH: posix = "fi"; break; - case LANG_FRENCH: posix = "fr"; break; - case LANG_GALICIAN: posix = "gl"; break; - case LANG_GUJARATI: posix = "gu"; break; - case LANG_HEBREW: posix = "he"; break; - case LANG_HINDI: posix = "hi"; break; - case LANG_HUNGARIAN: posix = "hu"; break; + case LANG_SPANISH: posix = _T("es"); break; + case LANG_BASQUE: posix = _T("eu"); break; + case LANG_FINNISH: posix = _T("fi"); break; + case LANG_FRENCH: posix = _T("fr"); break; + case LANG_GALICIAN: posix = _T("gl"); break; + case LANG_GUJARATI: posix = _T("gu"); break; + case LANG_HEBREW: posix = _T("he"); break; + case LANG_HINDI: posix = _T("hi"); break; + case LANG_HUNGARIAN: posix = _T("hu"); break; case LANG_ICELANDIC: break; - case LANG_INDONESIAN: posix = "id"; break; - case LANG_ITALIAN: posix = "it"; break; - case LANG_JAPANESE: posix = "ja"; break; - case LANG_GEORGIAN: posix = "ka"; break; - case LANG_KANNADA: posix = "kn"; break; - case LANG_KOREAN: posix = "ko"; break; - case LANG_LITHUANIAN: posix = "lt"; break; - case LANG_MACEDONIAN: posix = "mk"; break; - case LANG_DUTCH: posix = "nl"; break; - case LANG_NEPALI: posix = "ne"; break; + case LANG_INDONESIAN: posix = _T("id"); break; + case LANG_ITALIAN: posix = _T("it"); break; + case LANG_JAPANESE: posix = _T("ja"); break; + case LANG_GEORGIAN: posix = _T("ka"); break; + case LANG_KANNADA: posix = _T("kn"); break; + case LANG_KOREAN: posix = _T("ko"); break; + case LANG_LITHUANIAN: posix = _T("lt"); break; + case LANG_MACEDONIAN: posix = _T("mk"); break; + case LANG_DUTCH: posix = _T("nl"); break; + case LANG_NEPALI: posix = _T("ne"); break; case LANG_NORWEGIAN: switch (sub_id) { case SUBLANG_NORWEGIAN_BOKMAL: - posix = "nb"; break; + posix = _T("nb"); break; case SUBLANG_NORWEGIAN_NYNORSK: - posix = "nn"; break; + posix = _T("nn"); break; } break; - case LANG_PUNJABI: posix = "pa"; break; - case LANG_POLISH: posix = "pl"; break; - case LANG_PASHTO: posix = "ps"; break; + case LANG_PUNJABI: posix = _T("pa"); break; + case LANG_POLISH: posix = _T("pl"); break; + case LANG_PASHTO: posix = _T("ps"); break; case LANG_PORTUGUESE: switch (sub_id) { case SUBLANG_PORTUGUESE_BRAZILIAN: - posix = "pt_BR"; break; + posix = _T("pt_BR"); break; default: - posix = "pt"; break; + posix = _T("pt"); break; } break; - case LANG_ROMANIAN: posix = "ro"; break; - case LANG_RUSSIAN: posix = "ru"; break; - case LANG_SLOVAK: posix = "sk"; break; - case LANG_SLOVENIAN: posix = "sl"; break; - case LANG_ALBANIAN: posix = "sq"; break; + case LANG_ROMANIAN: posix = _T("ro"); break; + case LANG_RUSSIAN: posix = _T("ru"); break; + case LANG_SLOVAK: posix = _T("sk"); break; + case LANG_SLOVENIAN: posix = _T("sl"); break; + case LANG_ALBANIAN: posix = _T("sq"); break; /* LANG_CROATIAN == LANG_SERBIAN == LANG_BOSNIAN */ case LANG_SERBIAN: switch (sub_id) { case SUBLANG_SERBIAN_LATIN: - posix = "sr@Latn"; break; + posix = _T("sr@Latn"); break; case SUBLANG_SERBIAN_CYRILLIC: - posix = "sr"; break; + posix = _T("sr"); break; case SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC: case SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN: - posix = "bs"; break; + posix = _T("bs"); break; case SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN: - posix = "hr"; break; + posix = _T("hr"); break; } break; - case LANG_SWEDISH: posix = "sv"; break; - case LANG_TAMIL: posix = "ta"; break; - case LANG_TELUGU: posix = "te"; break; - case LANG_THAI: posix = "th"; break; - case LANG_TURKISH: posix = "tr"; break; - case LANG_UKRAINIAN: posix = "uk"; break; - case LANG_VIETNAMESE: posix = "vi"; break; - case LANG_XHOSA: posix = "xh"; break; + case LANG_SWEDISH: posix = _T("sv"); break; + case LANG_TAMIL: posix = _T("ta"); break; + case LANG_TELUGU: posix = _T("te"); break; + case LANG_THAI: posix = _T("th"); break; + case LANG_TURKISH: posix = _T("tr"); break; + case LANG_UKRAINIAN: posix = _T("uk"); break; + case LANG_VIETNAMESE: posix = _T("vi"); break; + case LANG_XHOSA: posix = _T("xh"); break; case LANG_CHINESE: switch (sub_id) { case SUBLANG_CHINESE_SIMPLIFIED: - posix = "zh_CN"; break; + posix = _T("zh_CN"); break; case SUBLANG_CHINESE_TRADITIONAL: - posix = "zh_TW"; break; + posix = _T("zh_TW"); break; default: - posix = "zh"; break; + posix = _T("zh"); break; } break; case LANG_URDU: break; @@ -394,8 +392,8 @@ /* Deal with exceptions */ if (posix == NULL) { switch (lcid) { - case 0x0455: posix = "my_MM"; break; /* Myanmar (Burmese) */ - case 9999: posix = "ku"; break; /* Kurdish (from NSIS) */ + case 0x0455: posix = _T("my_MM"); break; /* Myanmar (Burmese) */ + case 9999: posix = _T("ku"); break; /* Kurdish (from NSIS) */ } } @@ -407,19 +405,19 @@ - Check NSIS Installer Language reg value - Use default user locale */ -static const char *winpidgin_get_locale() { - const char *locale = NULL; +static const TCHAR *winpidgin_get_locale() { + const TCHAR *locale = NULL; LCID lcid; - char data[10]; - DWORD datalen = 10; + TCHAR data[10]; + DWORD datalen = sizeof(data) / sizeof(TCHAR); /* Check if user set PIDGINLANG env var */ - if ((locale = getenv("PIDGINLANG"))) + if ((locale = _tgetenv(_T("PIDGINLANG")))) return locale; - if (!portable_mode && read_reg_string(HKEY_CURRENT_USER, "SOFTWARE\\pidgin", - "Installer Language", (LPBYTE) &data, &datalen)) { - if ((locale = winpidgin_lcid_to_posix(atoi(data)))) + if (!portable_mode && read_reg_string(HKEY_CURRENT_USER, _T("SOFTWARE\\pidgin"), + _T("Installer Language"), (LPBYTE) &data, &datalen)) { + if ((locale = winpidgin_lcid_to_posix(_ttoi(data)))) return locale; } @@ -427,39 +425,39 @@ if ((locale = winpidgin_lcid_to_posix(lcid))) return locale; - return "en"; + return _T("en"); } static void winpidgin_set_locale() { - const char *locale = NULL; - char envstr[25]; + const TCHAR *locale; + TCHAR envstr[25]; locale = winpidgin_get_locale(); - _snprintf(envstr, 25, "LANG=%s", locale); - printf("Setting locale: %s\n", envstr); - _putenv(envstr); + _sntprintf(envstr, sizeof(envstr) / sizeof(TCHAR), _T("LANG=%s"), locale); + _tprintf(_T("Setting locale: %s\n"), envstr); + _tputenv(envstr); } static void winpidgin_add_stuff_to_path() { - char perl_path[MAX_PATH + 1]; - char *ppath = NULL; - char mit_kerberos_path[MAX_PATH + 1]; - char *mpath = NULL; + TCHAR perl_path[MAX_PATH + 1]; + TCHAR *ppath = NULL; + TCHAR mit_kerberos_path[MAX_PATH + 1]; + TCHAR *mpath = NULL; DWORD plen; printf("%s", "Looking for Perl... "); - plen = sizeof(perl_path); - if (read_reg_string(HKEY_LOCAL_MACHINE, "SOFTWARE\\Perl", "", + plen = sizeof(perl_path) / sizeof(TCHAR); + if (read_reg_string(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Perl"), _T(""), (LPBYTE) &perl_path, &plen)) { /* We *could* check for perl510.dll, but it seems unnecessary. */ - printf("found in '%s'.\n", perl_path); + _tprintf(_T("found in '%s'.\n"), perl_path); - if (perl_path[strlen(perl_path) - 1] != '\\') - strcat(perl_path, "\\"); - strcat(perl_path, "bin"); + if (perl_path[_tcslen(perl_path) - 1] != _T('\\')) + _tcscat(perl_path, _T("\\")); + _tcscat(perl_path, _T("bin")); ppath = perl_path; } else @@ -467,48 +465,47 @@ printf("%s", "Looking for MIT Kerberos... "); - plen = sizeof(mit_kerberos_path); - if (read_reg_string(HKEY_LOCAL_MACHINE, "SOFTWARE\\MIT\\Kerberos", "InstallDir", + plen = sizeof(mit_kerberos_path) / sizeof(TCHAR); + if (read_reg_string(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\MIT\\Kerberos"), _T("InstallDir"), (LPBYTE) &mit_kerberos_path, &plen)) { /* We *could* check for gssapi32.dll */ - printf("found in '%s'.\n", mit_kerberos_path); + _tprintf(_T("found in '%s'.\n"), mit_kerberos_path); - if (mit_kerberos_path[strlen(mit_kerberos_path) - 1] != '\\') - strcat(mit_kerberos_path, "\\"); - strcat(mit_kerberos_path, "bin"); + if (mit_kerberos_path[_tcslen(mit_kerberos_path) - 1] != _T('\\')) + _tcscat(mit_kerberos_path, _T("\\")); + _tcscat(mit_kerberos_path, _T("bin")); mpath = mit_kerberos_path; } else printf("%s", "not found.\n"); if (ppath != NULL || mpath != NULL) { - const char *path = getenv("PATH"); - BOOL add_ppath = ppath != NULL && (path == NULL || !strstr(path, ppath)); - BOOL add_mpath = mpath != NULL && (path == NULL || !strstr(path, mpath)); - char *newpath; + const TCHAR *path = _tgetenv(_T("PATH")); + BOOL add_ppath = ppath != NULL && (path == NULL || !_tcsstr(path, ppath)); + BOOL add_mpath = mpath != NULL && (path == NULL || !_tcsstr(path, mpath)); + TCHAR *newpath; int newlen; if (add_ppath || add_mpath) { /* Enough to add "PATH=" + path + ";" + ppath + ";" + mpath + \0 */ - newlen = 6 + (path ? strlen(path) + 1 : 0); + newlen = 6 + (path ? _tcslen(path) + 1 : 0); if (add_ppath) - newlen += strlen(ppath) + 1; + newlen += _tcslen(ppath) + 1; if (add_mpath) - newlen += strlen(mpath) + 1; - newpath = malloc(newlen); - *newpath = '\0'; + newlen += _tcslen(mpath) + 1; + newpath = malloc(newlen * sizeof(TCHAR)); - _snprintf(newpath, newlen, "PATH=%s%s%s%s%s%s", - path ? path : "", - path ? ";" : "", - add_ppath ? ppath : "", - add_ppath ? ";" : "", - add_mpath ? mpath : "", - add_mpath ? ";" : ""); + _sntprintf(newpath, newlen, _T("PATH=%s%s%s%s%s%s"), + path ? path : _T(""), + path ? _T(";") : _T(""), + add_ppath ? ppath : _T(""), + add_ppath ? _T(";") : _T(""), + add_mpath ? mpath : _T(""), + add_mpath ? _T(";") : _T("")); - printf("New PATH: %s\n", newpath); + _tprintf(_T("New PATH: %s\n"), newpath); - _putenv(newpath); + _tputenv(newpath); free(newpath); } } @@ -520,7 +517,7 @@ static BOOL winpidgin_set_running(BOOL fail_if_running) { HANDLE h; - if ((h = CreateMutex(NULL, FALSE, "pidgin_is_running"))) { + if ((h = CreateMutex(NULL, FALSE, _T("pidgin_is_running")))) { DWORD err = GetLastError(); if (err == ERROR_ALREADY_EXISTS) { if (fail_if_running) { @@ -528,14 +525,14 @@ printf("An instance of Pidgin is already running.\n"); - if((msg_win = FindWindowEx(NULL, NULL, TEXT("WinpidginMsgWinCls"), NULL))) + if((msg_win = FindWindowEx(NULL, NULL, _T("WinpidginMsgWinCls"), NULL))) if(SendMessage(msg_win, PIDGIN_WM_FOCUS_REQUEST, (WPARAM) NULL, (LPARAM) NULL)) return FALSE; /* If we get here, the focus request wasn't successful */ MessageBox(NULL, - "An instance of Pidgin is already running", + _T("An instance of Pidgin is already running"), NULL, MB_OK | MB_TOPMOST); return FALSE; @@ -546,80 +543,98 @@ return TRUE; } -#define PROTO_HANDLER_SWITCH "--protocolhandler=" +#define PROTO_HANDLER_SWITCH L"--protocolhandler=" -static void handle_protocol(char *cmd) { - char *remote_msg, *tmp1, *tmp2; - int len; +static void handle_protocol(wchar_t *cmd) { + char *remote_msg, *utf8msg; + wchar_t *tmp1, *tmp2; + int len, wlen; SIZE_T len_written; HWND msg_win; DWORD pid; HANDLE process; /* The start of the message */ - tmp1 = cmd + strlen(PROTO_HANDLER_SWITCH); + tmp1 = cmd + wcslen(PROTO_HANDLER_SWITCH); /* The end of the message */ - if ((tmp2 = strchr(tmp1, ' '))) - len = (tmp2 - tmp1); + if ((tmp2 = wcschr(tmp1, L' '))) + wlen = (tmp2 - tmp1); else - len = strlen(tmp1); + wlen = wcslen(tmp1); - if (len == 0) { + if (wlen == 0) { printf("No protocol message specified.\n"); return; } - if (!(msg_win = FindWindowEx(NULL, NULL, TEXT("WinpidginMsgWinCls"), NULL))) { + if (!(msg_win = FindWindowEx(NULL, NULL, _T("WinpidginMsgWinCls"), NULL))) { printf("Unable to find an instance of Pidgin to handle protocol message.\n"); return; } + len = WideCharToMultiByte(CP_UTF8, 0, tmp1, + wlen, NULL, 0, NULL, NULL); + if (len) { + utf8msg = malloc(len * sizeof(char)); + len = WideCharToMultiByte(CP_UTF8, 0, tmp1, + wlen, utf8msg, len, NULL, NULL); + } + + if (len == 0) { + printf("No protocol message specified.\n"); + return; + } + GetWindowThreadProcessId(msg_win, &pid); if (!(process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pid))) { DWORD dw = GetLastError(); - const char *err_msg = get_win32_error_message(dw); - printf("Unable to open Pidgin process. (%u) %s\n", (UINT) dw, err_msg); + const TCHAR *err_msg = get_win32_error_message(dw); + _tprintf(_T("Unable to open Pidgin process. (%u) %s\n"), (UINT) dw, err_msg); return; } - printf("Trying to handle protocol message:\n'%.*s'\n", len, tmp1); + wprintf(L"Trying to handle protocol message:\n'%.*s'\n", wlen, tmp1); - /* MEM_COMMIT initializes the memory to zero, - * so we don't need to worry that our section of tmp1 isn't nul-terminated */ + /* MEM_COMMIT initializes the memory to zero + * so we don't need to worry that our section of utf8msg isn't nul-terminated */ if ((remote_msg = (char*) VirtualAllocEx(process, NULL, len + 1, MEM_COMMIT, PAGE_READWRITE))) { - if (WriteProcessMemory(process, remote_msg, tmp1, len, &len_written)) { - if (!SendMessage(msg_win, PIDGIN_WM_PROTOCOL_HANDLE, len_written, (LPARAM) remote_msg)) + if (WriteProcessMemory(process, remote_msg, utf8msg, len, &len_written)) { + if (!SendMessageA(msg_win, PIDGIN_WM_PROTOCOL_HANDLE, len_written, (LPARAM) remote_msg)) printf("Unable to send protocol message to Pidgin instance.\n"); } else { DWORD dw = GetLastError(); - const char *err_msg = get_win32_error_message(dw); - printf("Unable to write to remote memory. (%u) %s\n", (UINT) dw, err_msg); + const TCHAR *err_msg = get_win32_error_message(dw); + _tprintf(_T("Unable to write to remote memory. (%u) %s\n"), (UINT) dw, err_msg); } VirtualFreeEx(process, remote_msg, 0, MEM_RELEASE); } else { DWORD dw = GetLastError(); - const char *err_msg = get_win32_error_message(dw); - printf("Unable to allocate remote memory. (%u) %s\n", (UINT) dw, err_msg); + const TCHAR *err_msg = get_win32_error_message(dw); + _tprintf(_T("Unable to allocate remote memory. (%u) %s\n"), (UINT) dw, err_msg); } CloseHandle(process); + free(utf8msg); } int _stdcall WinMain (struct HINSTANCE__ *hInstance, struct HINSTANCE__ *hPrevInstance, char *lpszCmdLine, int nCmdShow) { - char errbuf[512]; - char pidgin_dir[MAX_PATH]; - char exe_name[MAX_PATH]; + TCHAR errbuf[512]; + TCHAR pidgin_dir[MAX_PATH]; + TCHAR exe_name[MAX_PATH]; HMODULE hmod; - char *tmp; - int pidgin_argc = __argc; - char **pidgin_argv = __argv; - int i; - BOOL debug = FALSE, help = FALSE, version = FALSE, multiple = FALSE; + TCHAR *tmp; + wchar_t *wtmp; + int pidgin_argc; + char **pidgin_argv; /* This is in utf-8 */ + int i, j, k; + BOOL debug = FALSE, help = FALSE, version = FALSE, multiple = FALSE, success; + LPWSTR *szArglist; + LPWSTR cmdLine; /* If debug or help or version flag used, create console for output */ for (i = 1; i < __argc; i++) { @@ -652,7 +667,7 @@ * (_istty() doesn't work for stuff using the GUI subsystem) */ if (_fileno(stdout) == -1 || _fileno(stdout) == -2) { LPFNATTACHCONSOLE MyAttachConsole = NULL; - if ((hmod = GetModuleHandle("kernel32.dll"))) { + if ((hmod = GetModuleHandle(_T("kernel32.dll")))) { MyAttachConsole = (LPFNATTACHCONSOLE) GetProcAddress(hmod, "AttachConsole"); @@ -665,9 +680,11 @@ } } + cmdLine = GetCommandLineW(); + /* If this is a protocol handler invocation, deal with it accordingly */ - if ((tmp = strstr(lpszCmdLine, PROTO_HANDLER_SWITCH)) != NULL) { - handle_protocol(tmp); + if ((wtmp = wcsstr(cmdLine, PROTO_HANDLER_SWITCH)) != NULL) { + handle_protocol(wtmp); return 0; } @@ -675,18 +692,19 @@ if (GetModuleFileName(NULL, pidgin_dir, MAX_PATH) != 0) { /* primitive dirname() */ - tmp = strrchr(pidgin_dir, '\\'); + tmp = _tcsrchr(pidgin_dir, _T('\\')); if (tmp) { HMODULE hmod; - tmp[0] = '\0'; + tmp[0] = _T('\0'); /* tmp++ will now point to the executable file name */ - strcpy(exe_name, tmp + 1); + _tcscpy(exe_name, tmp + 1); - strcat(pidgin_dir, "\\exchndl.dll"); + _tcscat(pidgin_dir, _T("\\exchndl.dll")); if ((hmod = LoadLibrary(pidgin_dir))) { FARPROC proc; + /* exchndl.dll is built without UNICODE */ char debug_dir[MAX_PATH]; printf("Loaded exchndl.dll\n"); /* Temporarily override exchndl.dll's logfile @@ -694,7 +712,7 @@ * again when it initializes) */ proc = GetProcAddress(hmod, "SetLogFile"); if (proc) { - if (GetTempPath(sizeof(debug_dir), debug_dir) != 0) { + if (GetTempPathA(sizeof(debug_dir) * sizeof(char), debug_dir) != 0) { strcat(debug_dir, "pidgin.RPT"); printf(" Setting exchndl.dll LogFile to %s\n", debug_dir); @@ -703,47 +721,57 @@ } proc = GetProcAddress(hmod, "SetDebugInfoDir"); if (proc) { - tmp[0] = '\0'; - _snprintf(debug_dir, sizeof(debug_dir), - "%s\\pidgin-%s-dbgsym", - pidgin_dir, VERSION); - debug_dir[sizeof(debug_dir) - 1] = '\0'; - printf(" Setting exchndl.dll DebugInfoDir to %s\n", - debug_dir); - (proc)(debug_dir); + char *pidgin_dir_ansi = NULL; + tmp[0] = _T('\0'); +#ifdef _UNICODE + i = WideCharToMultiByte(CP_ACP, 0, pidgin_dir, + -1, NULL, 0, NULL, NULL); + if (i != 0) { + pidgin_dir_ansi = malloc(i * sizeof(char)); + i = WideCharToMultiByte(CP_ACP, 0, pidgin_dir, + -1, pidgin_dir_ansi, i, NULL, NULL); + if (i == 0) { + free(pidgin_dir_ansi); + pidgin_dir_ansi = NULL; + } + } +#else + pidgin_dir_ansi = pidgin_dir; +#endif + if (pidgin_dir_ansi != NULL) { + _snprintf(debug_dir, sizeof(debug_dir) / sizeof(char), + "%s\\pidgin-%s-dbgsym", + pidgin_dir_ansi, VERSION); + debug_dir[sizeof(debug_dir) / sizeof(char) - 1] = '\0'; + printf(" Setting exchndl.dll DebugInfoDir to %s\n", + debug_dir); + (proc)(debug_dir); +#ifdef _UNICODE + free(pidgin_dir_ansi); +#endif + } } } - tmp[0] = '\0'; + tmp[0] = _T('\0'); } } else { DWORD dw = GetLastError(); - const char *err_msg = get_win32_error_message(dw); - _snprintf(errbuf, 512, - "Error getting module filename.\nError: (%u) %s", + const TCHAR *err_msg = get_win32_error_message(dw); + _sntprintf(errbuf, 512, + _T("Error getting module filename.\nError: (%u) %s"), (UINT) dw, err_msg); - printf("%s\n", errbuf); + _tprintf(_T("%s\n"), errbuf); MessageBox(NULL, errbuf, NULL, MB_OK | MB_TOPMOST); - pidgin_dir[0] = '\0'; + pidgin_dir[0] = _T('\0'); } /* Determine if we're running in portable mode */ - if (strstr(lpszCmdLine, "--portable-mode") - || (exe_name != NULL && strstr(exe_name, "-portable.exe"))) { - int i = 0, c = 0; - + if (wcsstr(cmdLine, L"--portable-mode") + || (exe_name != NULL && _tcsstr(exe_name, _T("-portable.exe")))) { printf("Running in PORTABLE mode.\n"); portable_mode = TRUE; - - /* Remove the --portable-mode arg from the args passed to pidgin so it doesn't choke */ - pidgin_argv = malloc(sizeof(char*) * pidgin_argc); - for (; i < __argc; i++) { - if (strstr(__argv[i], "--portable-mode") == NULL) - pidgin_argv[c++] = __argv[i]; - else - pidgin_argc--; - } } if (portable_mode) @@ -761,23 +789,53 @@ return 0; /* Now we are ready for Pidgin .. */ - if ((hmod = LoadLibrary("pidgin.dll"))) + if ((hmod = LoadLibrary(_T("pidgin.dll")))) pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main"); if (!pidgin_main) { DWORD dw = GetLastError(); BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND); - const char *err_msg = get_win32_error_message(dw); + const TCHAR *err_msg = get_win32_error_message(dw); - _snprintf(errbuf, 512, "Error loading pidgin.dll.\nError: (%u) %s%s%s", + _sntprintf(errbuf, 512, _T("Error loading pidgin.dll.\nError: (%u) %s%s%s"), (UINT) dw, err_msg, - mod_not_found ? "\n" : "", - mod_not_found ? "This probably means that GTK+ can't be found." : ""); - printf("%s\n", errbuf); - MessageBox(NULL, errbuf, TEXT("Error"), MB_OK | MB_TOPMOST); + mod_not_found ? _T("\n") : _T(""), + mod_not_found ? _T("This probably means that GTK+ can't be found.") : _T("")); + _tprintf(_T("%s\n"), errbuf); + MessageBox(NULL, errbuf, _T("Error"), MB_OK | MB_TOPMOST); return 0; } + /* Convert argv to utf-8*/ + szArglist = CommandLineToArgvW(cmdLine, &j); + pidgin_argc = j; + pidgin_argv = malloc(pidgin_argc* sizeof(char*)); + k = 0; + for (i = 0; i < j; i++) { + success = FALSE; + /* Remove the --portable-mode arg from the args passed to pidgin so it doesn't choke */ + if (wcsstr(szArglist[i], L"--portable-mode") == NULL) { + int len = WideCharToMultiByte(CP_UTF8, 0, szArglist[i], + -1, NULL, 0, NULL, NULL); + if (len != 0) { + char *arg = malloc(len * sizeof(char)); + len = WideCharToMultiByte(CP_UTF8, 0, szArglist[i], + -1, arg, len, NULL, NULL); + if (len != 0) { + pidgin_argv[k++] = arg; + success = TRUE; + } + } + if (!success) + wprintf(L"Error converting argument '%s' to UTF-8\n", + szArglist[i]); + } + if (!success) + pidgin_argc--; + } + LocalFree(szArglist); + + return pidgin_main(hInstance, pidgin_argc, pidgin_argv); }