Use wsetargv.obj, and wmain() rather than main(), on Windows.
authorGuy Harris <guy@alum.mit.edu>
Sun, 7 Oct 2018 17:06:00 +0000 (10:06 -0700)
committerGuy Harris <guy@alum.mit.edu>
Sun, 7 Oct 2018 18:57:54 +0000 (18:57 +0000)
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 <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot
Reviewed-by: Guy Harris <guy@alum.mit.edu>
14 files changed:
CMakeLists.txt
capinfos.c
captype.c
dumpcap.c
editcap.c
mergecap.c
randpkt.c
rawshark.c
text2pcap.c
tfshark.c
tshark.c
ui/qt/main.cpp
wsutil/unicode-utils.c
wsutil/unicode-utils.h

index 4cf4de119c24b0e2771d1437bd4ba2e39d73edea..18145188a7a015043ab775669b6896a81fc4ce23 100644 (file)
@@ -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.
index 52ef4ec33c4a78afb686bcdcf1639824dee91da2..3bf92a72cae29b9eaedd751711847a5bd9690583 100644 (file)
@@ -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
  *
index 9083b5d8cf0ceed9d391f37b16685d586f75e6e1..e93f8637a2b9d9fbff298c317d0467e1df3a01e1 100644 (file)
--- 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
  *
index 10832d5fc6bf0096477a25a995759098e0856fb1..b4ef6422ea833a2700b515938706a4a611c94918 100644 (file)
--- 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,
index 99985a636d92a85b8e8ebc9ce0446fb47a7d3aa9..8f754f88e1c70b15771519a1659373041a645ace 100644 (file)
--- 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
index bc55d63bc9dc2357e3575d25610a1c442d03c475..516ab714da6d6c1106265dff195d563b8c0f6b4f 100644 (file)
@@ -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:
  */
-
index 2a2ce08d8933bfb5d9bef5801db0106fb8cacf0d..c4786c6452d5e5940b27743e0fb7fabc44383766 100644 (file)
--- 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
  *
index 29cb2ba80175669df9db8eb4db2a94fe27557bf3..c488bc44fdf9a9b617f328ee5be7d4b4391f3889 100644 (file)
@@ -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.
index a5cb5b263d8f0c3b66cbd6b3e03ebfec35ff7a91..3aa39bc87f905080c434d700a51adf98bc2882c3 100644 (file)
@@ -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:
  */
-
index 552588e92db4bf2054e8e9e28592392ced2b90ba..d91faeadf50e2db267ed964297c11a196df6c289 100644 (file)
--- 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)
 {
index 2d841536111869c6bee80587879781e971e3758b..e716aa9db3a8d09bcfd92ba5dad8f3069ccc404e 100644 (file)
--- 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
index 9826f64f006d96c7d35568dd9e3727e3a903cb60..fbd367085a49381f4d5f4fb4bfebddf91b809232 100644 (file)
 
 #include <locale.h>
 
+#ifdef _WIN32
+#include <windows.h>
+#include <tchar.h>
+#include <wchar.h>
+#include <shellapi.h>
+#endif
+
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #endif
@@ -92,7 +99,6 @@
 #ifdef _WIN32
 #  include "caputils/capture-wpcap.h"
 #  include "caputils/capture_wpcap_packet.h"
-#  include <tchar.h> /* Needed for Unicode */
 #  include <wsutil/file_util.h>
 #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 */
 
index 80323a53aa2a1b3b1c782b5a3500530e0d2c0a9a..5a8fa2336a43fc6365c78129c719e2e751cf22d9 100644 (file)
@@ -27,7 +27,6 @@ ws_utf8_char_len(guint8 ch)
 
 #ifdef _WIN32
 
-#include <shellapi.h>
 #include <strsafe.h>
 
 /** @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
 
 /*
index 8bb06eeaa74b957edaee19f4984940b66360d45c..1190d63b033889054a3c1fb7da7b00dbdf9ff245 100644 (file)
@@ -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 */
 
 /*