emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Windows 9X without KernelEx


From: Po Lu
Subject: Windows 9X without KernelEx
Date: Fri, 14 Jun 2024 23:12:59 +0800

Having become concerned that Emacs doesn't function on the complete set
of systems advertised in nt/README*, and after a comparison of the
symbol imports of emacs.exe with those exported by system libraries on
MS-Windows 95 confirmed my fears, I've produced a patch that should
enable Emacs to function on all Windows 9X systems with UNICOWS.DLL,
whether or not KernelEx is installed.  It further converts the linker
dependency on USP10.DLL to an optional dependency, because information
on the internet as to the availability of USP10.DLL on Windows 95 is too
ambiguous and contradictory to be trusted.

It has not been put to the test, but barring glaring oversights or
prejudice to modern Windows users, might this be installed now in its
untested condition?  Otherwise we are liable to proceed to more
important business till the release, by which time it will be far too
late.

2024-06-14    Po Lu <luangruo@yahoo.com>

        * configure.ac: Do not link with -lusp10 on non-Cygwin W32
        systems.

        * src/emacs.c (main): Call init_w32notify.

        * src/w32.c (w32_init_file_name_codepage): Clear
        g_b_init_is_windows9x, so that is_windows_9x may return values
        independent of the dump system before globals_of_w32 is called.
        Set w32_unicode_filenames to 0, again that it may be independent
        of its value at the time of dumping.
        (pfnCancelIo): New function pointer.
        (sys_write): Do not call CancelIo when absent.
        (init_ntproc): Initialize pfnCancelIo.

        * src/w32.h (init_w32notify): New function declaration.

        * src/w32fns.c (pfnSendInput): New function.
        (funhook): Use new function pointer.
        (setup_w32_kbdhook): Return if !pfnSendInput.
        (Fx_create_frame): Do not register Uniscribe font drivers if
        Uniscribe is unavailable.
        (pfnSHFileOperationW): New variable.
        (Fsystem_move_file_to_trash): Call SHFileOperationW through such
        variable.
        (pfnShellExecuteExW): New variable.
        (Fw32_shell_execute): Call ShellExecuteExW through such variable.
        (pfnGetMenuBarInfo, pfnGetWindowInfo): New variables.
        (Fw32_frame_geometry): Call GetWindowInfo and GetMenuBarInfo
        through those variables.  When the former is absent, substitute
        GetWindowLongA and GetWindowRect for the same.
        (pfnShell_NotifyIconW): New function pointer.
        (add_tray_notification, delete_tray_notification)
        (Fw32_notification_notify): Call Shell_NotifyIconW through such
        function pointer, punting when it is unavailable.
        (Fw32_notification_close): Likewise.
        (globals_of_w32fns): Initialize new function pointers.

        * src/w32notify.c (pfnReadDirectoryChangesW, pfnCancelIo): New
        variables.
        (watch_end, watch_completion, WINAPI, remove_watch)
        (Fw32notify_rm_watch, Fw32notify_valid_p): Call
        ReadDirectoryChangesW and CancelIo through those variables.
        (init_w32notify): Attempt to load those functions from
        kernel32.dll.

        * src/w32term.c (w32_set_window_size): Do not call GetMenuBarInfo
        when absent.
        (syms_of_w32term): Document status of feature consequently
        unavailable on Windows 95.

        * 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.

diff --git a/configure.ac b/configure.ac
index f75c0a98820..e4ce59b8a05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3133,7 +3133,7 @@ AC_DEFUN
       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"
diff --git a/src/emacs.c b/src/emacs.c
index d786bc65141..bb3070ed2fa 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2187,6 +2187,7 @@ main (int argc, char **argv)
      Emacs.  */
   init_environment (argv);
   init_ntproc (will_dump_p ()); /* must precede init_editfns.  */
+  init_w32notify ();
 #endif
 
   /* AIX crashes are reported in system versions 3.2.3 and 3.2.4
diff --git a/src/w32.c b/src/w32.c
index 1c6a56bcbd9..67aec88cb65 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -1683,6 +1683,15 @@ w32_valid_pointer_p (void *p, int size)
 void
 w32_init_file_name_codepage (void)
 {
+  /* This must be initialized to a suitable value lest it be in a dumped
+     Emacs erroneously set to that of the build system during
+     startup.  */
+  g_b_init_is_windows_9x = false;
+  if (is_windows_9x ())
+    w32_unicode_filenames = 0;
+  else
+    w32_unicode_filenames = 1;
+
   file_name_codepage = CP_ACP;
   w32_ansi_code_page = CP_ACP;
 }
@@ -9261,6 +9270,9 @@ sys_read (int fd, char * buffer, unsigned int count)
 /* From w32xfns.c */
 extern HANDLE interrupt_handle;
 
+/* Functions required for serial port communications.  */
+static BOOL (WINAPI *pfnCancelIo) (HANDLE);
+
 int
 sys_write (int fd, const void * buffer, unsigned int count)
 {
@@ -9350,7 +9362,8 @@ sys_write (int fd, const void * buffer, unsigned int 
count)
                     Don't bother cleaning up as we may only get stuck
                     in buggy drivers.  */
                  PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
-                 CancelIo (hnd);
+                 if (pfnCancelIo)
+                   (*pfnCancelIo) (hnd);
                  errno = EIO;  /* Why not EINTR? */
                  nchars = -1;
                  break;
@@ -10555,6 +10568,13 @@ init_ntproc (int dumping)
     /* Reset the volume info cache.  */
     volume_cache = NULL;
   }
+
+  {
+    HANDLE kernel32 = GetModuleHandle ("kernel32");
+
+    if (kernel32)
+      pfnCancelIo = (void *) get_proc_addr (kernel32, "CancelIo");
+  }
 }
 
 /* shutdown_handler ensures that buffers' autosave files are up to
diff --git a/src/w32.h b/src/w32.h
index cf470ae9901..8a732de7e79 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -249,6 +249,9 @@ #define FILE_DONT_CLOSE         0x1000
 /* Used instead of execvp to restart Emacs.  */
 extern int w32_reexec_emacs (char *, const char *);
 
+/* Initialize w32notify.c.  */
+extern void init_w32notify (void);
+
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
 
diff --git a/src/w32fns.c b/src/w32fns.c
index 5b0e4a895d0..81261281ae9 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -2613,6 +2613,9 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM 
wParam, LPARAM lParam)
 }
 
 #ifdef WINDOWSNT
+
+static UINT (WINAPI *pfnSendInput) (UINT, LPINPUT, int);
+
 /* The Windows keyboard hook callback.  */
 static LRESULT CALLBACK
 funhook (int code, WPARAM w, LPARAM l)
@@ -2689,8 +2692,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));
@@ -2705,7 +2708,7 @@ 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));
+                     (*pfnSendInput) (2, inputs, sizeof (INPUT));
                    }
                  else if (focus != NULL)
                    {
@@ -2758,7 +2761,7 @@ funhook (int code, WPARAM w, LPARAM l)
          inputs[1].ki.dwFlags =
            (hs->flags & LLKHF_EXTENDED) ? KEYEVENTF_EXTENDEDKEY : 0;
          inputs[1].ki.time = 0;
-         SendInput (2, inputs, sizeof (INPUT));
+         (*pfnSendInput) (2, inputs, sizeof (INPUT));
          /* Stop processing of this Win sequence here; the
             corresponding keyup messages will come through the normal
             channel when the keys are released.  */
@@ -2815,6 +2818,9 @@ setup_w32_kbdhook (HWND hwnd)
 {
   kbdhook.hook_count++;
 
+  if (!pfnSendInput)
+    return;
+
   /* This hook gets in the way of debugging, since when Emacs stops,
      its input thread stops, and there's nothing to process keyboard
      events, whereas this hook is global, and is invoked in the
@@ -6168,7 +6174,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,
@@ -8285,6 +8292,8 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 
2, 5, 0,
 
 
 #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,
@@ -8344,7 +8353,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
        {
@@ -8409,6 +8421,10 @@ DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
   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
@@ -8618,7 +8634,7 @@ parameters (e.g., \"printto\" requires the printer 
address).  Otherwise,
   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;
@@ -8670,7 +8686,7 @@ parameters (e.g., \"printto\" requires the printer 
address).  Otherwise,
       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
@@ -9051,6 +9067,9 @@ DEFUN ("w32-window-exists-p", Fw32_window_exists_p, 
Sw32_window_exists_p,
   return Qt;
 }
 
+BOOL (WINAPI *pfnGetMenuBarInfo) (HWND, LONG, LONG, PMENUBARINFO);
+static BOOL (WINAPI *pfnGetWindowInfo) (HWND, PWINDOWINFO);
+
 DEFUN ("w32-frame-geometry", Fw32_frame_geometry, Sw32_frame_geometry, 0, 1, 0,
        doc: /* Return geometric attributes of FRAME.
 FRAME must be a live frame and defaults to the selected one.  The return
@@ -9113,7 +9132,16 @@ DEFUN ("w32-frame-geometry", Fw32_frame_geometry, 
Sw32_frame_geometry, 0, 1, 0,
   block_input ();
   /* Outer rectangle and borders.  */
   window.cbSize = sizeof (window);
-  GetWindowInfo (FRAME_W32_WINDOW (f), &window);
+  if (pfnGetWindowInfo)
+    (*pfnGetWindowInfo) (FRAME_W32_WINDOW (f), &window);
+  else
+    {
+      /* Windows 95.  */
+      memset (&window, 0, sizeof window);
+      window.dwStyle = GetWindowLongA (FRAME_W32_WINDOW (f),
+                                      GWL_STYLE);
+      GetWindowRect (FRAME_W32_WINDOW (f), &window.rcWindow);
+    }
   external_border_width = window.cxWindowBorders;
   external_border_height = window.cyWindowBorders;
   /* Title bar.  */
@@ -9141,7 +9169,10 @@ DEFUN ("w32-frame-geometry", Fw32_frame_geometry, 
Sw32_frame_geometry, 0, 1, 0,
   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);
+
+  /* XXX: How to implement this on Windows 95?  */
+  if (pfnGetMenuBarInfo)
+    (*pfnGetMenuBarInfo) (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar);
   single_menu_bar_height = GetSystemMetrics (SM_CYMENU);
   wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
   unblock_input ();
@@ -10027,6 +10058,8 @@ DEFUN ("w32--menu-bar-in-use", Fw32__menu_bar_in_use, 
Sw32__menu_bar_in_use,
 
 #if defined WINDOWSNT && !defined HAVE_DBUS
 
+static BOOL (WINAPI *pfnShell_NotifyIconW) (DWORD, PNOTIFYICONDATAW);
+
 /***********************************************************************
                          Tray notifications
  ***********************************************************************/
@@ -10293,7 +10326,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.  */
@@ -10325,7 +10358,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.  */
@@ -10391,9 +10424,9 @@ DEFUN ("w32-notification-notify",
                     broken into lines.  The body text can be up to 255
                     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.
+Note that versions of Windows before W2K support only `:icon' and
+`:tip', and that this function does nothing on Windows 95.  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'
@@ -10409,7 +10442,7 @@ DEFUN ("w32-notification-notify",
   enum NI_Severity severity;
   unsigned timeout = 0;
 
-  if (nargs == 0)
+  if (nargs == 0 || !pfnShell_NotifyIconW)
     return Qnil;
 
   arg_plist = Flist (nargs, args);
@@ -10468,7 +10501,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;
@@ -11489,6 +11522,14 @@ globals_of_w32fns (void)
   SetGestureConfig_fn
     = (SetGestureConfig_proc) get_proc_addr (user32_lib,
                                             "SetGestureConfig");
+  pfnGetMenuBarInfo
+    = (void *) get_proc_addr (user32_lib, "GetMenuBarInfo");
+  pfnGetWindowInfo
+    = (void *) get_proc_addr (user32_lib, "GetWindowInfo");
+#ifdef WINDOWSNT
+  pfnSendInput
+    = (void *) get_proc_addr (user32_lib, "SendInput");
+#endif /* WINDOWSNT */
 
   {
     HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
@@ -11519,7 +11560,17 @@ globals_of_w32fns (void)
     get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification");
   WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc)
     get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification");
-#endif
+
+  HMODULE shell32_lib = GetModuleHandle ("shell32");
+  pfnSHFileOperationW
+    = (void *) get_proc_addr (shell32_lib, "SHFileOperationW");
+  pfnShellExecuteExW
+    = (void *) get_proc_addr (shell32_lib, "ShellExecuteExW");
+#ifndef HAVE_DBUS
+  pfnShell_NotifyIconW
+    = (void *) get_proc_addr (shell32_lib, "Shell_NotifyIconW");
+#endif /* !HAVE_DBUS */
+#endif /* WINDOWSNT */
 
   /* Support OS dark mode on Windows 10 version 1809 and higher.
      See `w32_applytheme' which uses appropriate APIs per version of Windows.
diff --git a/src/w32notify.c b/src/w32notify.c
index c93e8796fe2..b3ba1357a05 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -120,6 +120,12 @@ #define DIRWATCH_SIGNATURE 0x01233210
 /* 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 BOOL (WINAPI *pfnCancelIo) (HANDLE);
+
 static Lisp_Object watch_list;
 
 /* Signal to the main thread that we have file notifications for it to
@@ -175,7 +181,7 @@ watch_end (ULONG_PTR arg)
   HANDLE hdir = (HANDLE)arg;
 
   if (hdir && hdir != INVALID_HANDLE_VALUE)
-    CancelIo (hdir);
+    (*pfnCancelIo) (hdir);
 }
 
 /* A completion routine (a.k.a. "APC function") for handling events
@@ -252,10 +258,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 +276,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 +290,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 +442,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 +472,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);
@@ -649,7 +655,7 @@ DEFUN ("w32notify-rm-watch", Fw32notify_rm_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 @@ DEFUN ("w32notify-valid-p", Fw32notify_valid_p, 
Sw32notify_valid_p, 1, 1, 0,
   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;
@@ -722,3 +728,18 @@ syms_of_w32notify (void)
 
   Fprovide (intern_c_string ("w32notify"), Qnil);
 }
+
+void
+init_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.  */
+  pfnCancelIo = (void *) get_proc_addr (kernel32, "CancelIo");
+  pfnReadDirectoryChangesW
+    = (void *) get_proc_addr (kernel32, "ReadDirectoryChangesW");
+}
diff --git a/src/w32term.c b/src/w32term.c
index 62037e3b2cd..30f0f9b50f9 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -7143,6 +7143,9 @@ w32fullscreen_hook (struct frame *f)
     f->want_fullscreen |= FULLSCREEN_WAIT;
 }
 
+/* Defined in w32fns.c.  */
+extern BOOL (WINAPI *pfnGetMenuBarInfo) (HWND, LONG, LONG, PMENUBARINFO);
+
 /* Change the size of frame F's Windows window to WIDTH and HEIGHT
    pixels.  If CHANGE_GRAVITY, change to top-left-corner window gravity
    for this size change and subsequent size changes.  Otherwise leave
@@ -7163,10 +7166,11 @@ w32_set_window_size (struct frame *f, bool 
change_gravity,
      third argument for AdjustWindowRect.  See bug#22105.  */
   info.cbSize = sizeof (info);
   info.rcBar.top = info.rcBar.bottom = 0;
-  GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &info);
+  if (pfnGetMenuBarInfo)
+    (*pfnGetMenuBarInfo) (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &info);
   menu_bar_height = info.rcBar.bottom - info.rcBar.top;
 
-  if (w32_add_wrapped_menu_bar_lines)
+  if (w32_add_wrapped_menu_bar_lines && pfnGetMenuBarInfo)
     {
       /* When the menu bar wraps sending a SetWindowPos shrinks the
         height of the frame then the wrapped menu bar lines are not
@@ -8323,7 +8327,9 @@ syms_of_w32term (void)
 This usually means that the resulting frame height is off by the number
 of wrapped menu bar lines.  If this is non-nil, Emacs adds the height of
 wrapped menu bar lines when sending frame resize requests to the Windows
-API.  */);
+API.
+
+This feature is unavailable on Windows 95.  */);
   w32_add_wrapped_menu_bar_lines = 1;
 
   /* Tell Emacs about this window system.  */
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c
index b3112912c76..2fe90afd5f6 100644
--- a/src/w32uniscribe.c
+++ b/src/w32uniscribe.c
@@ -108,6 +108,31 @@ memq_no_quit (Lisp_Object elt, Lisp_Object list)
   return (CONSP (list));
 }
 
+
+/* 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 *);
+
 
 /* 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;
 }
 
@@ -1505,10 +1539,27 @@ syms_of_w32uniscribe_for_pdumper (void)
     return;
 
   /* 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, "GetGlyphABCWidth");
+  pfnScriptFreeCache
+    = (void *) get_proc_addr (uniscribe, "ScriptFreeCache");
+  pfnScriptGetCMap
+    = (void *) get_proc_addr (uniscribe, "ScriptGetCMap");
+  if (!pfnScriptItemize || !pfnScriptShape || !pfnScriptPlace
+      || !pfnScriptGetGlyphABCWidth || !pfnScriptFreeCache
+      || !pfnScriptGetCMap)
+    {
+      FreeLibrary (uniscribe);
+      return;
+    }
+
   uniscribe_available = 1;
 
   register_font_driver (&uniscribe_font_driver, NULL);


reply via email to

[Prev in Thread] Current Thread [Next in Thread]