From 86e45139698fe773ffb4efbe59387f90201b80c8 Mon Sep 17 00:00:00 2001
From: Jussi Lahdenniemi <jussi@aprikoodi.fi>
Date: Sat, 16 Jan 2016 11:46:14 +0200
Subject: [PATCH] Fix incompatbilities with MS-Windows 2000 and older

* src/w32.c <multiByteToWideCharFlags>: New global variable.
(filename_to_utf16, filename_from_ansi, check_windows_init_file):
Use it instead of the literal MB_ERR_INVALID_CHARS.
(maybe_load_unicows_dll): Initialize multiByteToWideCharFlags as
appropriate for the underlying OS version.  For details, see
http://lists.gnu.org/archive/html/emacs-devel/2016-01/msg00835.html.
* src/w32.h: Declare multiByteToWideCharFlags.
* src/w32fns.c (Fx_file_dialog, Fw32_shell_execute)
(add_tray_notification): Use multiByteToWideCharFlags instead of
the literal MB_ERR_INVALID_CHARS.
(_resetstkoflw_proc): New typedef.
(w32_reset_stack_overflow_guard): Call _resetstkoflw via a
pointer, as this function is absent in msvcrt.dll shipped with W2K
and older systems.

Copyright-paperwork-exempt: yes
---
 src/w32.c    | 23 +++++++++++++++--------
 src/w32.h    |  1 +
 src/w32fns.c | 42 ++++++++++++++++++++++++++----------------
 3 files changed, 42 insertions(+), 24 deletions(-)

diff --git a/src/w32.c b/src/w32.c
index 7884bad619c..6f1d5fd1698 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -486,6 +486,7 @@ typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
 
 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
+DWORD multiByteToWideCharFlags;
 
   /* ** A utility function ** */
 static BOOL
@@ -1552,8 +1553,8 @@ codepage_for_filenames (CPINFO *cp_info)
 int
 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
 {
-  int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
-				     fn_out, MAX_PATH);
+  int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
+				     -1, fn_out, MAX_PATH);
 
   if (!result)
     {
@@ -1643,8 +1644,8 @@ filename_from_ansi (const char *fn_in, char *fn_out)
 {
   wchar_t fn_utf16[MAX_PATH];
   int codepage = codepage_for_filenames (NULL);
-  int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
-				     fn_utf16, MAX_PATH);
+  int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
+				     -1, fn_utf16, MAX_PATH);
 
   if (!result)
     {
@@ -9134,14 +9135,14 @@ check_windows_init_file (void)
 		   "not unpacked properly.\nSee the README.W32 file in the "
 		   "top-level Emacs directory for more information.",
 		   init_file_name, load_path);
-	  needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
-					 -1, NULL, 0);
+	  needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+					 buffer, -1, NULL, 0);
 	  if (needed > 0)
 	    {
 	      wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
 
-	      pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
-				    msg_w, needed);
+	      pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
+				    -1, msg_w, needed);
 	      needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
 					     NULL, 0, NULL, NULL);
 	      if (needed > 0)
@@ -9328,6 +9329,7 @@ maybe_load_unicows_dll (void)
 	    (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
 	  pWideCharToMultiByte =
 	    (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
+          multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
 	  return ret;
 	}
       else
@@ -9357,6 +9359,11 @@ maybe_load_unicows_dll (void)
 	 pointers; no need for the LoadLibrary dance.  */
       pMultiByteToWideChar = MultiByteToWideChar;
       pWideCharToMultiByte = WideCharToMultiByte;
+      /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported.  */
+      if (w32_major_version < 5)
+        multiByteToWideCharFlags = 0;
+      else
+        multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
       return LoadLibrary ("Gdi32.dll");
     }
 }
diff --git a/src/w32.h b/src/w32.h
index ba3fec8b7e6..fde3803c739 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -183,6 +183,7 @@ typedef int (WINAPI *MultiByteToWideChar_Proc)(UINT,DWORD,LPCSTR,int,LPWSTR,int)
 typedef int (WINAPI *WideCharToMultiByte_Proc)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
 extern MultiByteToWideChar_Proc pMultiByteToWideChar;
 extern WideCharToMultiByte_Proc pWideCharToMultiByte;
+extern DWORD multiByteToWideCharFlags;
 
 extern void init_environment (char **);
 extern void check_windows_init_file (void);
diff --git a/src/w32fns.c b/src/w32fns.c
index f3806a992a0..01f5d6f3ae0 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -6984,12 +6984,12 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
 	    if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0)
 	      report_file_error ("filename too long", default_filename);
 	  }
-	len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 				    SSDATA (prompt), -1, NULL, 0);
 	if (len > 32768)
 	  len = 32768;
 	prompt_w = alloca (len * sizeof (wchar_t));
-	pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 			      SSDATA (prompt), -1, prompt_w, len);
       }
     else
@@ -7002,12 +7002,12 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
 	    if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0)
 	      report_file_error ("filename too long", default_filename);
 	  }
-	len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 				    SSDATA (prompt), -1, NULL, 0);
 	if (len > 32768)
 	  len = 32768;
 	prompt_w = alloca (len * sizeof (wchar_t));
-	pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 			      SSDATA (prompt), -1, prompt_w, len);
 	len = pWideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL);
 	if (len > 32768)
@@ -7489,10 +7489,10 @@ a ShowWindow flag:
   current_dir = ENCODE_FILE (current_dir);
   /* Cannot use filename_to_utf16/ansi with DOCUMENT, since it could
      be a URL that is not limited to MAX_PATH chararcters.  */
-  doclen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+  doclen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 				 SSDATA (document), -1, NULL, 0);
   doc_w = xmalloc (doclen * sizeof (wchar_t));
-  pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+  pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 			SSDATA (document), -1, doc_w, doclen);
   if (use_unicode)
     {
@@ -7507,12 +7507,12 @@ a ShowWindow flag:
 	  int len;
 
 	  parameters = ENCODE_SYSTEM (parameters);
-	  len = pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
+	  len = pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
 				      SSDATA (parameters), -1, NULL, 0);
 	  if (len > 32768)
 	    len = 32768;
 	  params_w = alloca (len * sizeof (wchar_t));
-	  pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
+	  pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
 				SSDATA (parameters), -1, params_w, len);
 	  params_w[len - 1] = 0;
 	}
@@ -8959,7 +8959,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
 	 later versions support up to 128.  */
       if (nidw.cbSize == MYNOTIFYICONDATAW_V1_SIZE)
 	{
-	  tiplen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	  tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 					 tip, utf8_mbslen_lim (tip, 63),
 					 tipw, 64);
 	  if (tiplen >= 63)
@@ -8967,7 +8967,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
 	}
       else
 	{
-	  tiplen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	  tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 					 tip, utf8_mbslen_lim (tip, 127),
 					 tipw, 128);
 	  if (tiplen >= 127)
@@ -8986,7 +8986,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
 	{
 	  int slen;
 
-	  slen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	  slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 					     msg, utf8_mbslen_lim (msg, 255),
 					     msgw, 256);
 	  if (slen >= 255)
@@ -8999,7 +8999,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
 	    }
 	  wcscpy (nidw.szInfo, msgw);
 	  nidw.uTimeout = timeout;
-	  slen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+	  slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
 				       title, utf8_mbslen_lim (title, 63),
 				       titlew, 64);
 	  if (slen >= 63)
@@ -9670,6 +9670,12 @@ static PVOID except_addr;
 
 /* Stack overflow recovery.  */
 
+/* MinGW headers don't declare this (should be in malloc.h).  Also,
+   the function is not present pre-W2K, so make the call through
+   a function pointer.  */
+typedef int (__cdecl *_resetstkoflw_proc) (void);
+static _resetstkoflw_proc resetstkoflw;
+
 /* Re-establish the guard page at stack limit.  This is needed because
    when a stack overflow is detected, Windows removes the guard bit
    from the guard page, so if we don't re-establish that protection,
@@ -9677,12 +9683,14 @@ static PVOID except_addr;
 void
 w32_reset_stack_overflow_guard (void)
 {
-  /* MinGW headers don't declare this (should be in malloc.h).  */
-  _CRTIMP int __cdecl _resetstkoflw (void);
-
+  if (resetstkoflw == NULL)
+    resetstkoflw =
+      (_resetstkoflw_proc)GetProcAddress (GetModuleHandle ("msvcrt.dll"),
+					  "_resetstkoflw");
   /* We ignore the return value.  If _resetstkoflw fails, the next
      stack overflow will crash the program.  */
-  (void)_resetstkoflw ();
+  if (resetstkoflw != NULL)
+    (void)resetstkoflw ();
 }
 
 static void
@@ -9927,6 +9935,8 @@ globals_of_w32fns (void)
 
   after_deadkey = -1;
 
+  resetstkoflw = NULL;
+
   /* MessageBox does not work without this when linked to comctl32.dll 6.0.  */
   InitCommonControls ();
 
-- 
2.39.5