]> git.eshelyaron.com Git - emacs.git/commitdiff
Restore functionality on Windows 98
authorPo Lu <luangruo@yahoo.com>
Sun, 23 Jun 2024 08:28:22 +0000 (16:28 +0800)
committerEshel Yaron <me@eshelyaron.com>
Sun, 30 Jun 2024 21:01:56 +0000 (23:01 +0200)
* configure.ac (W32_LIBS): Don't link with -lusp10 on non-Cygwin
systems.

* src/emacs.c (main): Call globals_of_w32 before the startup
directory is initialized.

* src/w32.c (maybe_load_unicows_dll): Call
load_unicows_dll_for_w32fns.

* src/w32.h: Update prototypes.

* src/w32fns.c (Fx_create_frame, w32_create_tip_frame): Do not
register the Uniscribe font driver when unavailable.
(pfnSHFileOperationW): New function pointer.
(Fsystem_move_file_to_trash): Load UNICOWS.DLL if not yet
loaded.  Call SHFileOperationW through said function pointer.
(pfnShellExecuteExW): New function pointer.
(Fw32_shell_execute) [!CYGWIN]: Load UNICOWS.DLL if not yet
loaded.  Call ShellExecuteExW through said function pointer.
(pfnShell_NotifyIconW): New function pointer.
(add_tray_notification, delete_tray_notification): Call
Shell_NotifyIconW through said function pointer.
(Fw32_notification_notify): Load UNICOWS.DLL.
(Fw32_notification_close): Return if Shell_NotifyIconW is
unavailable, as when UNICOWS.DLL has yet to be loaded.
(load_unicows_dll_for_w32fns): New function.

* src/w32notify.c (pfnReadDirectoryChangesW): New function
pointer.
(watch_completion, remove_watch, Fw32notify_add_watch)
(Fw32notify_rm_watch, Fw32notify_valid_p): Call
ReadDirectoryChangesW through said function pointer, and assert
its presence.
(globals_of_w32notify): Load ReadDirectoryChangesW from
KERNEL32.DLL.

* src/w32uniscribe.c (pfnScriptItemize, pfnScriptShape)
(pfnScriptPlace, pfnScriptGetGlyphABCWidth, pfnScriptFreeCache)
(pfnScriptGetCMap): New function pointers.
(uniscribe_close, uniscribe_shape, uniscribe_encode_char)
(uniscribe_check_otf_1): Call Uniscribe functions through the
same.
(syms_of_w32uniscribe_for_pdumper): Load Uniscribe library and
required functions from the same, and if unavailable, return
while leaving uniscribe_available intact.  On Cygwin, simply
assign USP10.DLL functions to the said new function pointers.

(cherry picked from commit 18e7a9f3d0c27385f8efeb2b1ef80b3446dca288)

configure.ac
src/emacs.c
src/w32.c
src/w32.h
src/w32fns.c
src/w32notify.c
src/w32uniscribe.c

index 2162cf5f5782872a2d0f20e11ef51d45669eb497..1bc67a846b6fede98d2c0755504462c008e2ab03 100644 (file)
@@ -3133,7 +3133,7 @@ if test "${HAVE_W32}" = "yes"; then
       NATIVE_IMAGE_API="yes (w32)"
       W32_OBJ="$W32_OBJ w32image.o"
     fi
-    W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32"
+    W32_LIBS="$W32_LIBS -lwinmm -lgdi32 -lcomdlg32"
     W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32"
     W32_RES_LINK="\$(EMACSRES)"
     CLIENTRES="emacsclient.res"
index d786bc651413256141942ef8d48a2917c119b064..74a46468933f3806f72bd69c8c08d4b8b607777f 100644 (file)
@@ -1406,6 +1406,10 @@ main (int argc, char **argv)
      the additional call here is harmless.) */
   cache_system_info ();
 #ifdef WINDOWSNT
+  /* This must be called to initialize w32_unicode_filenames and
+     is_windows_9x prior to w32_init_current_directory.  */
+  globals_of_w32 ();
+
   /* On Windows 9X, we have to load UNICOWS.DLL as early as possible,
      to have non-stub implementations of APIs we need to convert file
      names between UTF-8 and the system's ANSI codepage.  */
@@ -1517,11 +1521,10 @@ main (int argc, char **argv)
         }
     }
 #endif
-
   emacs_wd = emacs_get_current_dir_name ();
 #ifdef WINDOWSNT
   initial_wd = emacs_wd;
-#endif
+#endif /* WINDOWSNT */
 #ifdef HAVE_PDUMPER
   if (dumped_with_pdumper_p ())
     pdumper_record_wd (emacs_wd);
@@ -2176,7 +2179,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
   init_atimer ();
 
 #ifdef WINDOWSNT
-  globals_of_w32 ();
 #ifdef HAVE_W32NOTIFY
   globals_of_w32notify ();
 #endif
index 1c6a56bcbd9bcc9d0f07b94e03bcc0302e951103..4986d4c66768dfc88595135504c2ba58548db51b 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -10624,6 +10624,7 @@ maybe_load_unicows_dll (void)
          pWideCharToMultiByte = (WideCharToMultiByte_Proc)
             get_proc_addr (ret, "WideCharToMultiByte");
           multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
+         load_unicows_dll_for_w32fns (ret);
          return ret;
        }
       else
@@ -10658,6 +10659,7 @@ maybe_load_unicows_dll (void)
         multiByteToWideCharFlags = 0;
       else
         multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
+      load_unicows_dll_for_w32fns (NULL);
       return LoadLibrary ("Gdi32.dll");
     }
 }
index cf470ae9901e8663123e7151021104c5af09ee2f..3dc79dabf4b9c10bb11aff2a9810e0b8384579ff 100644 (file)
--- a/src/w32.h
+++ b/src/w32.h
@@ -170,6 +170,7 @@ extern void release_listen_threads (void);
 extern void init_ntproc (int);
 extern void term_ntproc (int);
 extern HANDLE maybe_load_unicows_dll (void);
+extern void load_unicows_dll_for_w32fns (HMODULE);
 extern void globals_of_w32 (void);
 
 extern void term_timers (void);
index 4c2f18abd084f72f319cd744ef6129ee53a150b1..6090eb34e82d6ed7ef8e40ca5c959847b68b272c 100644 (file)
@@ -2612,6 +2612,7 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 }
 
 #ifdef WINDOWSNT
+
 /* The Windows keyboard hook callback.  */
 static LRESULT CALLBACK
 funhook (int code, WPARAM w, LPARAM l)
@@ -2688,8 +2689,8 @@ funhook (int code, WPARAM w, LPARAM l)
                     can prevent this by setting the
                     w32-pass-[lr]window-to-system variable to
                     NIL.  */
-                 if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system)) ||
-                     (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system)))
+                 if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system))
+                      || (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system)))
                    {
                      /* Not prevented - Simulate the keypress to the system.  */
                      memset (inputs, 0, sizeof (inputs));
@@ -2704,7 +2705,6 @@ funhook (int code, WPARAM w, LPARAM l)
                      inputs[1].ki.dwFlags
                        = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
                      inputs[1].ki.time = 0;
-                     SendInput (2, inputs, sizeof (INPUT));
                    }
                  else if (focus != NULL)
                    {
@@ -6150,7 +6150,8 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
   if (harfbuzz_available)
     register_font_driver (&harfbuzz_font_driver, f);
 #endif
-  register_font_driver (&uniscribe_font_driver, f);
+  if (uniscribe_available)
+    register_font_driver (&uniscribe_font_driver, f);
   register_font_driver (&w32font_driver, f);
 
   gui_default_parameter (f, parameters, Qfont_backend, Qnil,
@@ -7227,7 +7228,8 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
   if (harfbuzz_available)
     register_font_driver (&harfbuzz_font_driver, f);
 #endif
-  register_font_driver (&uniscribe_font_driver, f);
+  if (uniscribe_available)
+    register_font_driver (&uniscribe_font_driver, f);
   register_font_driver (&w32font_driver, f);
 
   gui_default_parameter (f, parms, Qfont_backend, Qnil,
@@ -8265,6 +8267,8 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
 
 \f
 #ifdef WINDOWSNT
+static int (WINAPI *pfnSHFileOperationW) (LPSHFILEOPSTRUCTW);
+
 /* Moving files to the system recycle bin.
    Used by `move-file-to-trash' instead of the default moving to ~/.Trash  */
 DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
@@ -8276,6 +8280,9 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
   Lisp_Object encoded_file;
   Lisp_Object operation;
 
+  /* Required on Windows 9X.  */
+  maybe_load_unicows_dll ();
+
   operation = Qdelete_file;
   if (!NILP (Ffile_directory_p (filename))
       && NILP (Ffile_symlink_p (filename)))
@@ -8324,7 +8331,10 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
            | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
          file_op_w.fAnyOperationsAborted = FALSE;
 
-         result = SHFileOperationW (&file_op_w);
+         /* This is stated to exist on all versions of Windows NT Emacs
+            supports.  */
+         eassert (pfnSHFileOperationW);
+         result = (*pfnSHFileOperationW) (&file_op_w);
        }
       else
        {
@@ -8389,6 +8399,10 @@ If optional parameter FRAME is not specified, use selected frame.  */)
   return Qnil;
 }
 
+#ifndef CYGWIN
+static BOOL (WINAPI *pfnShellExecuteExW) (LPSHELLEXECUTEINFOW);
+#endif /* !CYGWIN */
+
 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
        doc: /* Get Windows to perform OPERATION on DOCUMENT.
 This is a wrapper around the ShellExecute system function, which
@@ -8539,6 +8553,9 @@ a ShowWindow flag:
   const int file_url_len = sizeof (file_url_str) - 1;
   int doclen;
 
+  /* Required on Windows 9X.  */
+  maybe_load_unicows_dll ();
+
   if (strncmp (SSDATA (document), file_url_str, file_url_len) == 0)
     {
       /* Passing "file:///" URLs to ShellExecute causes shlwapi.dll to
@@ -8598,7 +8615,7 @@ a ShowWindow flag:
   doc_w = xmalloc (doclen * sizeof (wchar_t));
   pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                        SSDATA (document), -1, doc_w, doclen);
-  if (use_unicode)
+  if (use_unicode && pfnShellExecuteExW)
     {
       wchar_t current_dir_w[MAX_PATH];
       SHELLEXECUTEINFOW shexinfo_w;
@@ -8650,7 +8667,7 @@ a ShowWindow flag:
       shexinfo_w.lpDirectory = current_dir_w;
       shexinfo_w.nShow =
        (FIXNUMP (show_flag) ? XFIXNUM (show_flag) : SW_SHOWDEFAULT);
-      success = ShellExecuteExW (&shexinfo_w);
+      success = (*pfnShellExecuteExW) (&shexinfo_w);
       xfree (doc_w);
     }
   else
@@ -9121,6 +9138,7 @@ and width values are in pixels.
   menu_bar.cbSize = sizeof (menu_bar);
   menu_bar.rcBar.right = menu_bar.rcBar.left = 0;
   menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0;
+
   GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar);
   single_menu_bar_height = GetSystemMetrics (SM_CYMENU);
   wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
@@ -10007,6 +10025,8 @@ Internal use only.  */)
 
 #if defined WINDOWSNT && !defined HAVE_DBUS
 
+static BOOL (WINAPI *pfnShell_NotifyIconW) (DWORD, PNOTIFYICONDATAW);
+
 /***********************************************************************
                          Tray notifications
  ***********************************************************************/
@@ -10273,7 +10293,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
            }
        }
 
-      if (!Shell_NotifyIconW (NIM_ADD, (PNOTIFYICONDATAW)&nidw))
+      if (!(*pfnShell_NotifyIconW) (NIM_ADD, (PNOTIFYICONDATAW)&nidw))
        {
          /* GetLastError returns meaningless results when
             Shell_NotifyIcon fails.  */
@@ -10305,7 +10325,7 @@ delete_tray_notification (struct frame *f, int id)
       nidw.hWnd = FRAME_W32_WINDOW (f);
       nidw.uID = id;
 
-      if (!Shell_NotifyIconW (NIM_DELETE, (PNOTIFYICONDATAW)&nidw))
+      if (!(*pfnShell_NotifyIconW) (NIM_DELETE, (PNOTIFYICONDATAW)&nidw))
        {
          /* GetLastError returns meaningless results when
             Shell_NotifyIcon fails.  */
@@ -10372,8 +10392,8 @@ The following parameters are supported:
                     characters long, and will be truncated if it's longer.
 
 Note that versions of Windows before W2K support only `:icon' and `:tip'.
-You can pass the other parameters, but they will be ignored on those
-old systems.
+You can pass the other parameters, but they will be ignored on
+those old systems.
 
 There can be at most one active notification at any given time.  An
 active notification must be removed by calling `w32-notification-close'
@@ -10389,7 +10409,10 @@ usage: (w32-notification-notify &rest PARAMS)  */)
   enum NI_Severity severity;
   unsigned timeout = 0;
 
-  if (nargs == 0)
+  /* Required on Windows 9X.  */
+  maybe_load_unicows_dll ();
+
+  if (nargs == 0 || !pfnShell_NotifyIconW)
     return Qnil;
 
   arg_plist = Flist (nargs, args);
@@ -10448,7 +10471,7 @@ DEFUN ("w32-notification-close",
 {
   struct frame *f = SELECTED_FRAME ();
 
-  if (FIXNUMP (id))
+  if (FIXNUMP (id) && !pfnShell_NotifyIconW)
     delete_tray_notification (f, XFIXNUM (id));
 
   return Qnil;
@@ -11499,7 +11522,7 @@ globals_of_w32fns (void)
     get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification");
   WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc)
     get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification");
-#endif
+#endif /* WINDOWSNT */
 
   /* Support OS dark mode on Windows 10 version 1809 and higher.
      See `w32_applytheme' which uses appropriate APIs per version of Windows.
@@ -11580,6 +11603,32 @@ Changing the value takes effect only for frames created after the change.  */);
   syms_of_w32uniscribe ();
 }
 
+#ifdef WINDOWSNT
+
+/* Initialize pointers to functions whose real implementations exist in
+   UNICOWS.DLL on Windows 9X.  UNICOWS should be a pointer to a loaded
+   handle referencing UNICOWS.DLL, or NULL on Windows NT systems.  */
+
+void
+load_unicows_dll_for_w32fns (HMODULE unicows)
+{
+  if (!unicows)
+    /* The functions following are defined by SHELL32.DLL onw Windows
+       NT.  */
+    unicows = GetModuleHandle ("shell32");
+
+  pfnSHFileOperationW
+    = (void *) get_proc_addr (unicows, "SHFileOperationW");
+  pfnShellExecuteExW
+    = (void *) get_proc_addr (unicows, "ShellExecuteExW");
+#ifndef HAVE_DBUS
+  pfnShell_NotifyIconW
+    = (void *) get_proc_addr (unicows, "Shell_NotifyIconW");
+#endif /* !HAVE_DBUS */
+}
+
+#endif /* WINDOWSNT */
+
 #ifdef NTGUI_UNICODE
 
 Lisp_Object
index c93e8796fe27768d0ca42314f43886bd9170caca..1001c85fdbe9a5722135bfa0713c6bd98eb6c409 100644 (file)
@@ -120,6 +120,10 @@ struct notification {
 /* Used for communicating notifications to the main thread.  */
 struct notifications_set *notifications_set_head;
 
+/* Function pointers.  */
+static BOOL (WINAPI *pfnReadDirectoryChangesW) (HANDLE, PVOID, DWORD, BOOL,
+                                               DWORD, PDWORD, LPOVERLAPPED,
+                                               LPOVERLAPPED_COMPLETION_ROUTINE);
 static Lisp_Object watch_list;
 
 /* Signal to the main thread that we have file notifications for it to
@@ -252,10 +256,10 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
 
   /* Calling ReadDirectoryChangesW quickly to watch again for new
      notifications.  */
-  if (!ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf,
-                             DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
-                             dirwatch->filter, &_bytes, dirwatch->io_info,
-                             watch_completion))
+  if (!(*pfnReadDirectoryChangesW) (dirwatch->dir, dirwatch->buf,
+                                   DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
+                                   dirwatch->filter, &_bytes,
+                                   dirwatch->io_info, watch_completion))
     {
       DebPrint (("ReadDirectoryChangesW error: %lu\n", GetLastError ()));
       /* If this call fails, it means that the directory is not
@@ -270,7 +274,7 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
 
   /* If we were asked to terminate the thread, then fire the event. */
   if (terminate)
-    SetEvent(dirwatch->terminate);
+    SetEvent (dirwatch->terminate);
 }
 
 /* Worker routine for the watch thread.  */
@@ -284,10 +288,10 @@ watch_worker (LPVOID arg)
 
   if (dirwatch->dir)
     {
-      bErr = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf,
-                                   DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
-                                   dirwatch->filter, &_bytes,
-                                   dirwatch->io_info, watch_completion);
+      bErr = (*pfnReadDirectoryChangesW) (dirwatch->dir, dirwatch->buf,
+                                         DIRWATCH_BUFFER_SIZE, dirwatch->subtree,
+                                         dirwatch->filter, &_bytes,
+                                         dirwatch->io_info, watch_completion);
       if (!bErr)
        {
          DebPrint (("ReadDirectoryChangesW: %lu\n", GetLastError ()));
@@ -436,7 +440,7 @@ remove_watch (struct notification *dirwatch)
        DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ()));
 
       /* We also signal the thread that it can terminate.  */
-      SetEvent(dirwatch->terminate);
+      SetEvent (dirwatch->terminate);
 
       /* Wait for the thread to exit.  FIXME: is there a better method
         that is not overly complex?  */
@@ -466,7 +470,7 @@ remove_watch (struct notification *dirwatch)
          CloseHandle (dirwatch->thr);
          dirwatch->thr = NULL;
        }
-      CloseHandle(dirwatch->terminate);
+      CloseHandle (dirwatch->terminate);
       xfree (dirwatch->buf);
       xfree (dirwatch->io_info);
       xfree (dirwatch->watchee);
@@ -575,6 +579,8 @@ generate notifications correctly, though.  */)
       report_file_notify_error ("Watching filesystem events is not supported",
                                Qnil);
     }
+  else
+    eassert (pfnReadDirectoryChangesW);
 
   /* filenotify.el always passes us a directory, either the parent
      directory of a file to be watched, or the directory to be
@@ -649,7 +655,7 @@ WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'.  */)
   if (!NILP (watch_object))
     {
       watch_list = Fdelete (watch_object, watch_list);
-      dirwatch = (struct notification *)xmint_pointer (watch_descriptor);
+      dirwatch = (struct notification *) xmint_pointer (watch_descriptor);
       if (w32_valid_pointer_p (dirwatch, sizeof(struct notification)))
        status = remove_watch (dirwatch);
     }
@@ -687,7 +693,7 @@ watch by calling `w32notify-rm-watch' also makes it invalid.  */)
   if (!NILP (watch_object))
     {
       struct notification *dirwatch =
-       (struct notification *)xmint_pointer (watch_descriptor);
+       (struct notification *) xmint_pointer (watch_descriptor);
       if (w32_valid_pointer_p (dirwatch, sizeof(struct notification))
          && dirwatch->dir != NULL)
        return Qt;
@@ -699,6 +705,16 @@ watch by calling `w32notify-rm-watch' also makes it invalid.  */)
 void
 globals_of_w32notify (void)
 {
+  HANDLE kernel32 = GetModuleHandle ("kernel32");
+
+  /* Initialize pointers to IO functions that provide file
+     notifications.  In the event that these are absent, no harm will be
+     done, since their absence indicates that Emacs is running on
+     Windows 9X, where file notifications are unavailable at the
+     outset.  */
+  pfnReadDirectoryChangesW
+    = (void *) get_proc_addr (kernel32, "ReadDirectoryChangesW");
+
   watch_list = Qnil;
 }
 
index dacd6dd766ed5fd2b28ef54d83cfc9f7eb33d160..e840e14541e4a5206be816e52f009f7d23c67539 100644 (file)
@@ -108,6 +108,31 @@ memq_no_quit (Lisp_Object elt, Lisp_Object list)
   return (CONSP (list));
 }
 
+\f
+/* Uniscribe function pointers.  */
+static HRESULT (WINAPI * pfnScriptItemize) (const WCHAR *,
+                                           int,
+                                           int,
+                                           const SCRIPT_CONTROL *,
+                                           const SCRIPT_STATE *,
+                                           SCRIPT_ITEM *, int *);
+static HRESULT (WINAPI * pfnScriptShape) (HDC, SCRIPT_CACHE *,
+                                         const WCHAR *,
+                                         int, int, SCRIPT_ANALYSIS *,
+                                         WORD *, WORD *, SCRIPT_VISATTR *,
+                                         int *);
+static HRESULT (WINAPI * pfnScriptPlace) (HDC, SCRIPT_CACHE *,
+                                         const WORD *, int,
+                                         const SCRIPT_VISATTR *,
+                                         SCRIPT_ANALYSIS *,
+                                         int *, GOFFSET *, ABC *);
+static HRESULT (WINAPI * pfnScriptGetGlyphABCWidth) (HDC, SCRIPT_CACHE *,
+                                                    WORD, ABC *);
+static HRESULT (WINAPI * pfnScriptFreeCache) (SCRIPT_CACHE *);
+static HRESULT (WINAPI * pfnScriptGetCMap) (HDC, SCRIPT_CACHE *,
+                                           const WCHAR *,
+                                           int, DWORD, WORD *);
+
 \f
 /* Font backend interface implementation.  */
 static Lisp_Object
@@ -202,7 +227,7 @@ uniscribe_close (struct font *font)
   else
 #endif
   if (uniscribe_font->cache)
-    ScriptFreeCache ((SCRIPT_CACHE) &(uniscribe_font->cache));
+    (*pfnScriptFreeCache) ((SCRIPT_CACHE) &(uniscribe_font->cache));
 
   uniscribe_font->cache = NULL;
 
@@ -320,8 +345,8 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
   max_items = 2;
   items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
 
-  while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
-                                 items, &nitems)) == E_OUTOFMEMORY)
+  while ((result = (*pfnScriptItemize) (chars, nchars, max_items, NULL, NULL,
+                                       items, &nitems)) == E_OUTOFMEMORY)
     {
       /* If that wasn't enough, keep trying with one more run.  */
       max_items++;
@@ -344,17 +369,18 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
     {
       int nglyphs, nchars_in_run;
       nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
-      /* Force ScriptShape to generate glyphs in the same order as
+      /* Force (*pfnScriptShape) to generate glyphs in the same order as
         they are in the input LGSTRING, which is in the logical
         order.  */
       items[i].a.fLogicalOrder = 1;
 
       /* Context may be NULL here, in which case the cache should be
          used without needing to select the font.  */
-      result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
-                           chars + items[i].iCharPos, nchars_in_run,
-                           max_glyphs - done_glyphs, &(items[i].a),
-                           glyphs, clusters, attributes, &nglyphs);
+      result
+       = (*pfnScriptShape) (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
+                            chars + items[i].iCharPos, nchars_in_run,
+                            max_glyphs - done_glyphs, &(items[i].a),
+                            glyphs, clusters, attributes, &nglyphs);
 
       if (result == E_PENDING && !context)
        {
@@ -365,10 +391,12 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
          context = get_frame_dc (f);
          old_font = SelectObject (context, FONT_HANDLE (font));
 
-         result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
-                               chars + items[i].iCharPos, nchars_in_run,
-                               max_glyphs - done_glyphs, &(items[i].a),
-                               glyphs, clusters, attributes, &nglyphs);
+         result
+           = (*pfnScriptShape) (context,
+                                (SCRIPT_CACHE) &(uniscribe_font->cache),
+                                chars + items[i].iCharPos, nchars_in_run,
+                                max_glyphs - done_glyphs, &(items[i].a),
+                                glyphs, clusters, attributes, &nglyphs);
        }
 
       if (result == E_OUTOFMEMORY)
@@ -390,9 +418,11 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
        }
       else
        {
-         result = ScriptPlace (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
-                               glyphs, nglyphs, attributes, &(items[i].a),
-                               advances, offsets, &overall_metrics);
+         result
+           = (*pfnScriptPlace) (context,
+                                (SCRIPT_CACHE) &(uniscribe_font->cache),
+                                glyphs, nglyphs, attributes, &(items[i].a),
+                                advances, offsets, &overall_metrics);
          if (result == E_PENDING && !context)
            {
              /* Cache not complete...  */
@@ -400,10 +430,11 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
              context = get_frame_dc (f);
              old_font = SelectObject (context, FONT_HANDLE (font));
 
-             result = ScriptPlace (context,
-                                   (SCRIPT_CACHE) &(uniscribe_font->cache),
-                                   glyphs, nglyphs, attributes, &(items[i].a),
-                                   advances, offsets, &overall_metrics);
+             result
+               = (*pfnScriptPlace) (context,
+                                    (SCRIPT_CACHE) &(uniscribe_font->cache),
+                                    glyphs, nglyphs, attributes, &(items[i].a),
+                                    advances, offsets, &overall_metrics);
            }
           if (SUCCEEDED (result))
            {
@@ -469,7 +500,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
                         then updated for each successive glyph in the
                         grapheme cluster.  */
                      /* FIXME: Should we use DIRECTION here instead
-                        of what ScriptItemize guessed?  */
+                        of what (*pfnScriptItemize) guessed?  */
                      if (items[i].a.fRTL)
                        {
                          int j1 = j;
@@ -496,7 +527,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
                  LGLYPH_SET_ASCENT (lglyph, font->ascent);
                  LGLYPH_SET_DESCENT (lglyph, font->descent);
 
-                 result = ScriptGetGlyphABCWidth
+                 result = (*pfnScriptGetGlyphABCWidth)
                    (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
                     glyphs[j], &char_metric);
                  if (result == E_PENDING && !context)
@@ -505,7 +536,7 @@ uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
                      f = XFRAME (selected_frame);
                      context = get_frame_dc (f);
                      old_font = SelectObject (context, FONT_HANDLE (font));
-                     result = ScriptGetGlyphABCWidth
+                     result = (*pfnScriptGetGlyphABCWidth)
                        (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
                         glyphs[j], &char_metric);
                    }
@@ -624,7 +655,8 @@ uniscribe_encode_char (struct font *font, int c)
      convert surrogate pairs to glyph indexes correctly.  */
     {
       items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
-      if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
+      if (SUCCEEDED ((*pfnScriptItemize) (ch, len, 2, NULL, NULL, items,
+                                         &nitems)))
        {
          HRESULT result;
           /* Surrogates seem to need 2 here, even though only one glyph is
@@ -635,14 +667,14 @@ uniscribe_encode_char (struct font *font, int c)
           SCRIPT_VISATTR attrs[2];
           int nglyphs;
 
-         /* Force ScriptShape to generate glyphs in the logical
+         /* Force (*pfnScriptShape) to generate glyphs in the logical
             order.  */
          items[0].a.fLogicalOrder = 1;
 
-          result = ScriptShape (context,
-                               (SCRIPT_CACHE) &(uniscribe_font->cache),
-                                ch, len, 2, &(items[0].a),
-                                glyphs, clusters, attrs, &nglyphs);
+          result = (*pfnScriptShape) (context,
+                                     (SCRIPT_CACHE) &(uniscribe_font->cache),
+                                     ch, len, 2, &(items[0].a),
+                                     glyphs, clusters, attrs, &nglyphs);
 
           if (result == E_PENDING)
             {
@@ -651,10 +683,11 @@ uniscribe_encode_char (struct font *font, int c)
               f = XFRAME (selected_frame);
               context = get_frame_dc (f);
               old_font = SelectObject (context, FONT_HANDLE (font));
-              result = ScriptShape (context,
-                                   (SCRIPT_CACHE) &(uniscribe_font->cache),
-                                    ch, len, 2, &(items[0].a),
-                                    glyphs, clusters, attrs, &nglyphs);
+              result
+               = (*pfnScriptShape) (context,
+                                    (SCRIPT_CACHE) &(uniscribe_font->cache),
+                                    ch, len, 2, &(items[0].a),
+                                    glyphs, clusters, attrs, &nglyphs);
             }
 
           if (SUCCEEDED (result) && nglyphs == 1)
@@ -670,9 +703,10 @@ uniscribe_encode_char (struct font *font, int c)
                  when shaped. But we still need the return from here
                  to be valid for the shaping engine to be invoked
                  later.  */
-              result = ScriptGetCMap (context,
-                                     (SCRIPT_CACHE) &(uniscribe_font->cache),
-                                      ch, len, 0, glyphs);
+              result
+               = (*pfnScriptGetCMap) (context,
+                                      (SCRIPT_CACHE) &(uniscribe_font->cache),
+                                      ch, len, 0, glyphs);
               if (SUCCEEDED (result) && glyphs[0])
                 code = glyphs[0];
             }
@@ -942,7 +976,7 @@ uniscribe_check_otf_1 (HDC context, Lisp_Object script, Lisp_Object lang,
 
  no_support:
   if (cache)
-    ScriptFreeCache (&cache);
+    (*pfnScriptFreeCache) (&cache);
   return ret;
 }
 
@@ -1504,11 +1538,37 @@ syms_of_w32uniscribe_for_pdumper (void)
   if (!initialized)
     return;
 
+#ifdef WINDOWSNT
   /* Don't register if Uniscribe is not available.  */
-  HMODULE uniscribe = GetModuleHandle ("usp10");
+  HMODULE uniscribe = LoadLibrary ("usp10.dll");
   if (!uniscribe)
     return;
 
+  pfnScriptItemize = (void *) get_proc_addr (uniscribe, "ScriptItemize");
+  pfnScriptShape = (void *) get_proc_addr (uniscribe, "ScriptShape");
+  pfnScriptPlace = (void *) get_proc_addr (uniscribe, "ScriptPlace");
+  pfnScriptGetGlyphABCWidth
+    = (void *) get_proc_addr (uniscribe, "ScriptGetGlyphABCWidth");
+  pfnScriptFreeCache
+    = (void *) get_proc_addr (uniscribe, "ScriptFreeCache");
+  pfnScriptGetCMap
+    = (void *) get_proc_addr (uniscribe, "ScriptGetCMap");
+  if (!pfnScriptItemize || !pfnScriptShape || !pfnScriptPlace
+      || !pfnScriptGetGlyphABCWidth || !pfnScriptFreeCache
+      || !pfnScriptGetCMap)
+    {
+      FreeLibrary (uniscribe);
+      return;
+    }
+#else /* Cygwin */
+  pfnScriptItemize = &ScriptItemize;
+  pfnScriptShape = &ScriptShape;
+  pfnScriptPlace = &ScriptPlace;
+  pfnScriptGetGlyphABCWidth = &ScriptGetGlyphABCWidth;
+  pfnScriptFreeCache = &ScriptFreeCache;
+  pfnScriptGetCMap = &ScriptGetCMap;
+#endif /* Cygwin */
+
   uniscribe_available = 1;
 
   register_font_driver (&uniscribe_font_driver, NULL);