From a679ae6f791ac6b02f342d3b73d6b4aecb9ca6e9 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sun, 7 Oct 2018 10:06:00 -0700 Subject: [PATCH] Use wsetargv.obj, and wmain() rather than main(), on Windows. Doing so for command-line programs means that the argument list doesn't ever get converted to the local code page; converting to the local code page can mangle file names that *can't* be converted to the local code page. Furthermore, code that uses setargv.obj rather than wsetargv.obj has issues in some versions of Windows 10; see bug 15151. That means that converting the argument list to UTF-8 is a bit simpler - we don't need to call GetCommandLineW() or CommandLineToArgvW(), we just loop over the UTF-16LE argument strings in argv[]. While we're at it, note in Wireshark's main() why we discard argv on Windows (Qt does the same "convert-to-the-local-code-page" stuff); that means we *do* need to call GetCommandLineW() and CommandLineToArgvW() in main() (i.e., we duplicate what Qt's WinMain() does, but converting to UTF-8 rather than to the local code page). Change-Id: I35b57c1b658fb3e9b0c685097afe324e9fe98649 Ping-Bug: 15151 Reviewed-on: https://code.wireshark.org/review/30051 Petri-Dish: Guy Harris Tested-by: Petri Dish Buildbot Reviewed-by: Guy Harris --- CMakeLists.txt | 4 ++-- capinfos.c | 25 ++++++++++++++++++++++--- captype.c | 25 ++++++++++++++++++++++--- dumpcap.c | 24 +++++++++++++++++++++--- editcap.c | 25 ++++++++++++++++++++++--- mergecap.c | 27 ++++++++++++++++++++++----- randpkt.c | 25 ++++++++++++++++++++++--- rawshark.c | 25 ++++++++++++++++++++++--- text2pcap.c | 34 ++++++++++++++++++++++++++-------- tfshark.c | 25 ++++++++++++++++++++++--- tshark.c | 25 ++++++++++++++++++++++--- ui/qt/main.cpp | 36 +++++++++++++++++++++++++++++------- wsutil/unicode-utils.c | 18 ------------------ wsutil/unicode-utils.h | 14 -------------- 14 files changed, 254 insertions(+), 78 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cf4de119c..18145188a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,9 +176,9 @@ endif() if(WIN32) - # Linking with setargv.obj enables "wildcard expansion" of + # Linking with wsetargv.obj enables "wildcard expansion" of # command-line arguments. - set(WILDCARD_OBJ setargv.obj) + set(WILDCARD_OBJ wsetargv.obj) endif(WIN32) # Banner shown at top right of Qt welcome screen. diff --git a/capinfos.c b/capinfos.c index 52ef4ec33c..3bf92a72ca 100644 --- a/capinfos.c +++ b/capinfos.c @@ -1397,8 +1397,8 @@ hash_to_str(const unsigned char *hash, size_t length, char *str) { } } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -1445,7 +1445,6 @@ main(int argc, char *argv[]) g_string_free(runtime_info_str, TRUE); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -1725,6 +1724,26 @@ exit: return overall_error_status; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * diff --git a/captype.c b/captype.c index 9083b5d8cf..e93f8637a2 100644 --- a/captype.c +++ b/captype.c @@ -81,8 +81,8 @@ failure_message_cont(const char *msg_format, va_list ap) fprintf(stderr, "\n"); } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -121,7 +121,6 @@ main(int argc, char *argv[]) g_string_free(runtime_info_str, TRUE); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -206,6 +205,26 @@ main(int argc, char *argv[]) return overall_error_status; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * diff --git a/dumpcap.c b/dumpcap.c index 10832d5fc6..b4ef6422ea 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -4503,8 +4503,8 @@ get_dumpcap_runtime_info(GString *str) } /* And now our feature presentation... [ fade to music ] */ -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -4565,7 +4565,6 @@ main(int argc, char *argv[]) g_string_free(runtime_info_str, TRUE); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); /* @@ -5272,6 +5271,25 @@ main(int argc, char *argv[]) return 0; /* never here, make compiler happy */ } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif static void console_log_handler(const char *log_domain, GLogLevelFlags log_level, diff --git a/editcap.c b/editcap.c index 99985a636d..8f754f88e1 100644 --- a/editcap.c +++ b/editcap.c @@ -955,8 +955,8 @@ editcap_dump_open(const char *filename, guint32 snaplen, return pdh; } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -1011,7 +1011,6 @@ main(int argc, char *argv[]) cmdarg_err_init(failure_warning_message, failure_message_cont); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -1953,6 +1952,26 @@ clean_exit: return ret; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /* Skip meta-information read from file to return offset of real * protocol data */ static int diff --git a/mergecap.c b/mergecap.c index bc55d63bc9..516ab714da 100644 --- a/mergecap.c +++ b/mergecap.c @@ -225,9 +225,8 @@ merge_callback(merge_event event, int num, return FALSE; } - -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -259,7 +258,6 @@ main(int argc, char *argv[]) cmdarg_err_init(mergecap_cmdarg_err, mergecap_cmdarg_err_cont); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -473,6 +471,26 @@ clean_exit: return (status == MERGE_OK) ? 0 : 2; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * @@ -485,4 +503,3 @@ clean_exit: * vi: set shiftwidth=2 tabstop=8 expandtab: * :indentSize=2:tabSize=8:noTabs=true: */ - diff --git a/randpkt.c b/randpkt.c index 2a2ce08d89..c4786c6452 100644 --- a/randpkt.c +++ b/randpkt.c @@ -99,8 +99,8 @@ usage(gboolean is_error) fprintf(output, "\nIf type is not specified, a random packet will be chosen\n\n"); } -int -main(int argc, char **argv) +static int +real_main(int argc, char **argv) { char *init_progfile_dir_error; int opt; @@ -143,7 +143,6 @@ main(int argc, char **argv) cmdarg_err_init(failure_warning_message, failure_message_cont); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -247,6 +246,26 @@ clean_exit: return ret; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t **argv) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char **argv) +{ + return real_main(argc, argv); +} +#endif + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * diff --git a/rawshark.c b/rawshark.c index 29cb2ba801..c488bc44fd 100644 --- a/rawshark.c +++ b/rawshark.c @@ -405,8 +405,8 @@ set_link_type(const char *lt_arg) { return FALSE; } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -459,7 +459,6 @@ main(int argc, char *argv[]) get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -831,6 +830,26 @@ clean_exit: return ret; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /** * Read data from a raw pipe. The "raw" data consists of a libpcap * packet header followed by the payload. diff --git a/text2pcap.c b/text2pcap.c index a5cb5b263d..3aa39bc87f 100644 --- a/text2pcap.c +++ b/text2pcap.c @@ -1459,11 +1459,6 @@ parse_options (int argc, char *argv[]) }; struct tm *now_tm; -#ifdef _WIN32 - arg_list_utf_16to8(argc, argv); - create_app_running_mutex(); -#endif /* _WIN32 */ - /* Get the compile-time version information string */ comp_info_str = get_compiled_version_info(NULL, NULL); @@ -1864,11 +1859,15 @@ parse_options (int argc, char *argv[]) return EXIT_SUCCESS; } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { int ret = EXIT_SUCCESS; +#ifdef _WIN32 + create_app_running_mutex(); +#endif /* _WIN32 */ + if (parse_options(argc, argv) != EXIT_SUCCESS) { ret = EXIT_FAILURE; goto clean_exit; @@ -1932,6 +1931,26 @@ clean_exit: return ret; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * @@ -1944,4 +1963,3 @@ clean_exit: * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */ - diff --git a/tfshark.c b/tfshark.c index 552588e92d..d91faeadf5 100644 --- a/tfshark.c +++ b/tfshark.c @@ -303,8 +303,8 @@ get_tfshark_runtime_version_info(GString *str) epan_get_runtime_version_info(str); } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -360,7 +360,6 @@ main(int argc, char *argv[]) cmdarg_err_init(failure_warning_message, failure_message_cont); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -1006,6 +1005,26 @@ clean_exit: return exit_status; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + static const nstime_t * tfshark_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num) { diff --git a/tshark.c b/tshark.c index 2d84153611..e716aa9db3 100644 --- a/tshark.c +++ b/tshark.c @@ -667,8 +667,8 @@ must_do_dissection(dfilter_t *rfcode, dfilter_t *dfcode, tap_listeners_require_dissection() || dissect_color; } -int -main(int argc, char *argv[]) +static int +real_main(int argc, char *argv[]) { GString *comp_info_str; GString *runtime_info_str; @@ -764,7 +764,6 @@ main(int argc, char *argv[]) cmdarg_err_init(failure_warning_message, failure_message_cont); #ifdef _WIN32 - arg_list_utf_16to8(argc, argv); create_app_running_mutex(); #endif /* _WIN32 */ @@ -2259,6 +2258,26 @@ clean_exit: return exit_status; } +#ifdef _WIN32 +int +wmain(int argc, wchar_t *argv[]) +{ + char **argv_utf8; + + /* Convert our arg list from UTF-16LE to UTF-8. */ + argv_utf8 = g_malloc(argc * sizeof *argv_utf8); + for (int i = 0; i < argc; i++) + argv_utf8[i] = g_utf16_to_utf8(argv[i], -1, NULL, NULL, NULL); + return real_main(argc, argv_utf8); +} +#else +int +main(int argc, char *argv[]) +{ + return real_main(argc, argv); +} +#endif + /*#define USE_BROKEN_G_MAIN_LOOP*/ #ifdef USE_BROKEN_G_MAIN_LOOP diff --git a/ui/qt/main.cpp b/ui/qt/main.cpp index 9826f64f00..fbd367085a 100644 --- a/ui/qt/main.cpp +++ b/ui/qt/main.cpp @@ -13,6 +13,13 @@ #include +#ifdef _WIN32 +#include +#include +#include +#include +#endif + #ifdef HAVE_GETOPT_H #include #endif @@ -92,7 +99,6 @@ #ifdef _WIN32 # include "caputils/capture-wpcap.h" # include "caputils/capture_wpcap_packet.h" -# include /* Needed for Unicode */ # include #endif /* _WIN32 */ @@ -352,6 +358,8 @@ int main(int argc, char *qt_argv[]) #ifdef _WIN32 int opt; + LPWSTR *wc_argv; + int wc_argc; #endif int ret_val = EXIT_SUCCESS; char **argv = qt_argv; @@ -400,12 +408,26 @@ int main(int argc, char *qt_argv[]) setlocale(LC_ALL, ""); #ifdef _WIN32 - // QCoreApplication clobbers argv. Let's have a local copy. - argv = (char **) g_malloc(sizeof(char *) * argc); - for (opt = 0; opt < argc; opt++) { - argv[opt] = qt_argv[opt]; - } - arg_list_utf_16to8(argc, argv); + // + // On Windows, QCoreApplication has its own WinMain(), which gets the + // command line using GetCommandLineW(), breaks it into individual + // arguments using CommandLineToArgvW(), and then "helpfully" + // converts those UTF-16LE arguments into strings in the local code + // page. + // + // We don't want that, because not all file names can be represented + // in the local code page, so we do the same, but we convert the + // strings into UTF-8. + // + wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc); + if (wc_argv && wc_argc == argc) { + argv = (char **) g_malloc(sizeof(char *) * argc); + for (opt = 0; opt < argc; opt++) { + argv[opt] = g_utf16_to_utf8((const gunichar2 *)wc_argv[opt], -1, NULL, NULL, NULL); + } + } /* XXX else bail because something is horribly, horribly wrong? */ + LocalFree(wc_argv); + create_app_running_mutex(); #endif /* _WIN32 */ diff --git a/wsutil/unicode-utils.c b/wsutil/unicode-utils.c index 80323a53aa..5a8fa2336a 100644 --- a/wsutil/unicode-utils.c +++ b/wsutil/unicode-utils.c @@ -27,7 +27,6 @@ ws_utf8_char_len(guint8 ch) #ifdef _WIN32 -#include #include /** @file @@ -142,23 +141,6 @@ utf_16to8(const wchar_t *utf16str) return utf8buf[idx]; } - -/* Convert our argument list from UTF-16 to UTF-8. */ -void -arg_list_utf_16to8(int argc, char *argv[]) { - LPWSTR *wc_argv; - int wc_argc, i; - - /* Convert our arg list to UTF-8. */ - wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc); - if (wc_argv && wc_argc == argc) { - for (i = 0; i < argc; i++) { - argv[i] = g_utf16_to_utf8(wc_argv[i], -1, NULL, NULL, NULL); - } - } /* XXX else bail because something is horribly, horribly wrong? */ - LocalFree(wc_argv); -} - #endif /* diff --git a/wsutil/unicode-utils.h b/wsutil/unicode-utils.h index 8bb06eeaa7..1190d63b03 100644 --- a/wsutil/unicode-utils.h +++ b/wsutil/unicode-utils.h @@ -62,20 +62,6 @@ void utf_8to16_snprintf(TCHAR *utf16buf, gint utf16buf_len, const gchar* fmt, */ WS_DLL_PUBLIC gchar * utf_16to8(const wchar_t *utf16str); - -/** Convert the program argument list from UTF-16 to UTF-8 and - * store it in the supplied array. This is intended to be used - * to normalize command line arguments at program startup. - * - * @param argc The number of arguments. You should simply pass the - * first argument from main(). - * @param argv The argument values (vector). You should simply pass - * the second argument from main(). - */ -WS_DLL_PUBLIC -void arg_list_utf_16to8(int argc, char *argv[]); - - #endif /* _WIN32 */ /*