From f60ae425e9095d06f4ad06e5b277903606c25dca Mon Sep 17 00:00:00 2001 From: Ben Key Date: Sun, 17 Nov 2002 22:35:26 +0000 Subject: [PATCH] Added a partial implementation of play-sound-internal for Windows. Fixed the following entry in etc/PROBLEMS: Emacs built on Windows 9x/ME crashes at startup on Windows XP, or Emacs built on XP crashes at startup on Windows 9x/ME. --- nt/ChangeLog | 8 + nt/gmake.defs | 1 + nt/nmake.defs | 1 + src/ChangeLog | 69 +++++++ src/makefile.w32-in | 9 + src/s/ms-w32.h | 1 + src/sound.c | 446 +++++++++++++++++++++++++++++++------------- src/w32.c | 183 +++++++++++++++++- src/w32.h | 5 + src/w32fns.c | 33 +++- src/w32menu.c | 46 ++++- 11 files changed, 661 insertions(+), 141 deletions(-) diff --git a/nt/ChangeLog b/nt/ChangeLog index 8b0172f2e8c..a8d5f53495d 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,11 @@ +2002-11-17 Ben Key + * nmake.defs: Made changes so that Emacs would link with + WinMM.lib. This change was required for my addition of a Windows + compatible implementation of play-sound-internal. + * gmake.defs: Made changes so that Emacs would link with + WinMM.lib. This change was required for my addition of a Windows + compatible implementation of play-sound-internal. + 2002-09-03 Juanma Barranquero (tiny change) * emacs.rc: Version updated to 21.3.50. From Peter Runestig diff --git a/nt/gmake.defs b/nt/gmake.defs index d75239d30c6..2235417aca4 100644 --- a/nt/gmake.defs +++ b/nt/gmake.defs @@ -166,6 +166,7 @@ MPR = -lmpr SHELL32 = -lshell32 USER32 = -luser32 WSOCK32 = -lwsock32 +WINMM = -lwinmm ifdef NOOPT DEBUG_CFLAGS = -DEMACSDEBUG diff --git a/nt/nmake.defs b/nt/nmake.defs index 3c3e8b5bca2..e2bfd58fc57 100644 --- a/nt/nmake.defs +++ b/nt/nmake.defs @@ -123,6 +123,7 @@ MPR = mpr.lib SHELL32 = shell32.lib USER32 = user32.lib WSOCK32 = wsock32.lib +WINMM = winmm.lib !ifdef NOOPT DEBUG_CFLAGS = -DEMACSDEBUG diff --git a/src/ChangeLog b/src/ChangeLog index ad38b61b789..b174d8d6ab1 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,72 @@ +2002-11-17 Ben Key + * w32.c: Added wrapper functions around the win32 API functions + OpenProcessToken, GetTokenInformation, LookupAccountSid, and + GetSidIdentifierAuthority. These wrapper functions serve two + purposes: + 1. They ensure that the wrapped function can never be called + when Emacs is running on an operating system on which they are + not supported (Microsoft Windows 95 / 98 / ME). + 2. They call the wrapped functions via function pointers rather + than calling them directly. This avoids taking advantage of the + undocumented fact that although these functions are not supported + in the 9x branch of Microsoft Windows, the functions do exist in + the version of advapi32.dll that is found in the 9x branch of + Microsoft Windows. + This change is part of my fix for the following entry in + etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on + Windows XP, or Emacs built on XP crashes at startup on Windows + 9x/ME." + + * w32.c (init_user_info): Replaced the calls to the win32 API + functions OpenProcessToken, GetTokenInformation, LookupAccountSid, + and GetSidIdentifierAuthority with calls to the newly added + wrapper functions. + This change is part of my fix for the following entry in + etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on + Windows XP, or Emacs built on XP crashes at startup on Windows + 9x/ME." + + * w32.h: Added extern declarations for the following functions: + syms_of_w32term, syms_of_w32fns, syms_of_w32select, + syms_of_w32menu, and void syms_of_fontset. + This change is part of my fix for the following entry in + etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on + Windows XP, or Emacs built on XP crashes at startup on Windows + 9x/ME." + + * w32fns.c (w32_wnd_proc): Added code to reinitialize the + function pointer track_mouse_event_fn in the handler for the + WM_SETFOCUS message. + This change is part of my fix for the following entry in + etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on + Windows XP, or Emacs built on XP crashes at startup on Windows + 9x/ME." + + * w32menu.c (initialize_frame_menubar): Added code to + reinitialize the function pointers set_menu_item_info and + get_menu_item_info. + This change is part of my fix for the following entry in + etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on + Windows XP, or Emacs built on XP crashes at startup on Windows + 9x/ME." + + * sound.c: Added a partial implementation of play-sound-internal + for Microsoft Windows. Added various #ifdef / #else / #endif + code blocks to separate the code that will compile under + Microsoft Windows from the code that is specific to Gnu/Linux. + Moved several blocks of code around to make this separation of + code into Windows compatible and Gnu/Linux compatible code blocks + easier. + + * makefile.w32-in: Made modifications so that sound.c would be + included in the Windows port of Emacs and that it would link with + WinMM.lib. + + * s/ms-w32.h: Defined the symbol HAVE_SOUND so that the newly + added support for play-sound-internal under Windows would be + included in the build of Emacs. + + 2002-11-16 Jason Rumney * w32fns.c (w32_load_system_font): Don't disable Cleartype. diff --git a/src/makefile.w32-in b/src/makefile.w32-in index 8c56c25667a..0a11245df0e 100644 --- a/src/makefile.w32-in +++ b/src/makefile.w32-in @@ -94,6 +94,7 @@ OBJ1 = $(BLD)/abbrev.$(O) \ $(BLD)/regex.$(O) \ $(BLD)/scroll.$(O) \ $(BLD)/search.$(O) \ + $(BLD)/sound.$(O) \ $(BLD)/syntax.$(O) \ $(BLD)/sysdep.$(O) \ $(BLD)/term.$(O) \ @@ -133,6 +134,7 @@ LIBS = $(TLIB0) \ $(TLIB1) \ $(TLIBW32) \ $(TLASTLIB) \ + $(WINMM) \ $(ADVAPI32) \ $(GDI32) \ $(COMDLG32) \ @@ -1094,6 +1096,13 @@ $(BLD)/search.$(O) : \ $(SRC)/w32bdf.h \ $(SRC)/w32gui.h +$(BLD)/sound.$(O) : \ + $(SRC)/sound.c \ + $(SRC)/lisp.h \ + $(SRC)/dispextern.h \ + $(SRC)/atimer.h \ + $(SRC)/syssignal.h + $(BLD)/strftime.$(O) : \ $(SRC)/strftime.c \ $(EMACS_ROOT)/src/s/ms-w32.h \ diff --git a/src/s/ms-w32.h b/src/s/ms-w32.h index 0585c22d0fe..51f3e9ddb25 100644 --- a/src/s/ms-w32.h +++ b/src/s/ms-w32.h @@ -217,6 +217,7 @@ Boston, MA 02111-1307, USA. */ #define MAXPATHLEN _MAX_PATH #endif +#define HAVE_SOUND 1 #define LISP_FLOAT_TYPE 1 #undef HAVE_SYS_SELECT_H diff --git a/src/sound.c b/src/sound.c index a9336a04af9..185ba864be7 100644 --- a/src/sound.c +++ b/src/sound.c @@ -21,10 +21,26 @@ Boston, MA 02111-1307, USA. */ /* Written by Gerd Moellmann . Tested with Luigi's driver on FreeBSD 2.2.7 with a SoundBlaster 16. */ +/* + Modified by Ben Key to add a partial + implementation of the play-sound specification for Windows. + + Notes: + In the Windows implementation of play-sound-internal only the + :file and :volume keywords are supported. The :device keyword, + if present, is ignored. The :data keyword, if present, will + cause an error to be generated. + + The Windows implementation of play-sound is implemented via the + Win32 API functions mciSendString, waveOutGetVolume, and + waveOutGetVolume which are exported by Winmm.dll. +*/ + #include #if defined HAVE_SOUND +/* BEGIN: Common Includes */ #include #include #include @@ -34,6 +50,11 @@ Boston, MA 02111-1307, USA. */ #include "atimer.h" #include #include "syssignal.h" +/* END: Common Includes */ + + +/* BEGIN: Non Windows Includes */ +#ifndef WINDOWSNT #ifndef MSDOS #include @@ -51,12 +72,55 @@ Boston, MA 02111-1307, USA. */ #ifdef HAVE_SOUNDCARD_H #include #endif +/* END: Non Windows Includes */ + +#else /* WINDOWSNT */ + +/* BEGIN: Windows Specific Includes */ +#include +#include +#include +#include +#include +#include +/* END: Windows Specific Includes */ + +#endif /* WINDOWSNT */ + +/* BEGIN: Common Definitions */ +#define abs(X) ((X) < 0 ? -(X) : (X)) + +/* Symbols. */ + +extern Lisp_Object QCfile, QCdata; +Lisp_Object QCvolume, QCdevice; +Lisp_Object Qsound; +Lisp_Object Qplay_sound_functions; + +/* Indices of attributes in a sound attributes vector. */ + +enum sound_attr +{ + SOUND_FILE, + SOUND_DATA, + SOUND_DEVICE, + SOUND_VOLUME, + SOUND_ATTR_SENTINEL +}; + +static void sound_perror P_ ((char *)); +static void sound_warning P_ ((char *)); +static int parse_sound P_ ((Lisp_Object, Lisp_Object *)); + +/* END: Common Definitions */ + +/* BEGIN: Non Windows Definitions */ +#ifndef WINDOWSNT #ifndef DEFAULT_SOUND_DEVICE #define DEFAULT_SOUND_DEVICE "/dev/dsp" #endif -#define abs(X) ((X) < 0 ? -(X) : (X)) /* Structure forward declarations. */ @@ -203,24 +267,6 @@ struct sound void (* play) P_ ((struct sound *s, struct sound_device *sd)); }; -/* Indices of attributes in a sound attributes vector. */ - -enum sound_attr -{ - SOUND_FILE, - SOUND_DATA, - SOUND_DEVICE, - SOUND_VOLUME, - SOUND_ATTR_SENTINEL -}; - -/* Symbols. */ - -extern Lisp_Object QCfile, QCdata; -Lisp_Object QCvolume, QCdevice; -Lisp_Object Qsound; -Lisp_Object Qplay_sound_functions; - /* These are set during `play-sound-internal' so that sound_cleanup has access to them. */ @@ -235,9 +281,6 @@ static void vox_close P_ ((struct sound_device *sd)); static void vox_choose_format P_ ((struct sound_device *, struct sound *)); static void vox_init P_ ((struct sound_device *)); static void vox_write P_ ((struct sound_device *, const char *, int)); -static void sound_perror P_ ((char *)); -static void sound_warning P_ ((char *)); -static int parse_sound P_ ((Lisp_Object, Lisp_Object *)); static void find_sound_type P_ ((struct sound *)); static u_int32_t le2hl P_ ((u_int32_t)); static u_int16_t le2hs P_ ((u_int16_t)); @@ -251,12 +294,22 @@ static void au_play P_ ((struct sound *, struct sound_device *)); static u_int16_t be2hs P_ ((u_int16_t)); #endif +/* END: Non Windows Definitions */ +#else /* WINDOWSNT */ + +/* BEGIN: Windows Specific Definitions */ +static int do_play_sound P_ ((const char *, unsigned long)); +/* + END: Windows Specific Definitions */ +#endif /* WINDOWSNT */ /*********************************************************************** General ***********************************************************************/ +/* BEGIN: Common functions */ + /* Like perror, but signals an error. */ static void @@ -327,10 +380,21 @@ parse_sound (sound, attrs) attrs[SOUND_DEVICE] = Fplist_get (sound, QCdevice); attrs[SOUND_VOLUME] = Fplist_get (sound, QCvolume); +#ifndef WINDOWSNT /* File name or data must be specified. */ if (!STRINGP (attrs[SOUND_FILE]) && !STRINGP (attrs[SOUND_DATA])) return 0; +#else /* WINDOWSNT */ + /* + Data is not supported in Windows. Therefore a + File name MUST be supplied. + */ + if (!STRINGP (attrs[SOUND_FILE])) + { + return 0; + } +#endif /* WINDOWSNT */ /* Volume must be in the range 0..100 or unspecified. */ if (!NILP (attrs[SOUND_VOLUME])) @@ -351,14 +415,23 @@ parse_sound (sound, attrs) return 0; } +#ifndef WINDOWSNT /* Device must be a string or unspecified. */ if (!NILP (attrs[SOUND_DEVICE]) && !STRINGP (attrs[SOUND_DEVICE])) return 0; - +#endif /* WINDOWSNT */ + /* + Since device is ignored in Windows, it does not matter + what it is. + */ return 1; } +/* END: Common functions */ + +/* BEGIN: Non Windows functions */ +#ifndef WINDOWSNT /* Find out the type of the sound file whose file descriptor is FD. S is the sound file structure to fill in. */ @@ -389,105 +462,6 @@ sound_cleanup (arg) return Qnil; } - -DEFUN ("play-sound-internal", Fplay_sound_internal, Splay_sound_internal, 1, 1, 0, - doc: /* Play sound SOUND. - -Internal use only, use `play-sound' instead. */) - (sound) - Lisp_Object sound; -{ - Lisp_Object attrs[SOUND_ATTR_SENTINEL]; - Lisp_Object file; - struct gcpro gcpro1, gcpro2; - struct sound_device sd; - struct sound s; - Lisp_Object args[2]; - int count = SPECPDL_INDEX (); - - file = Qnil; - GCPRO2 (sound, file); - bzero (&sd, sizeof sd); - bzero (&s, sizeof s); - current_sound_device = &sd; - current_sound = &s; - record_unwind_protect (sound_cleanup, Qnil); - s.header = (char *) alloca (MAX_SOUND_HEADER_BYTES); - - /* Parse the sound specification. Give up if it is invalid. */ - if (!parse_sound (sound, attrs)) - error ("Invalid sound specification"); - - if (STRINGP (attrs[SOUND_FILE])) - { - /* Open the sound file. */ - s.fd = openp (Fcons (Vdata_directory, Qnil), - attrs[SOUND_FILE], Qnil, &file, Qnil); - if (s.fd < 0) - sound_perror ("Could not open sound file"); - - /* Read the first bytes from the file. */ - s.header_size = emacs_read (s.fd, s.header, MAX_SOUND_HEADER_BYTES); - if (s.header_size < 0) - sound_perror ("Invalid sound file header"); - } - else - { - s.data = attrs[SOUND_DATA]; - s.header_size = min (MAX_SOUND_HEADER_BYTES, SBYTES (s.data)); - bcopy (SDATA (s.data), s.header, s.header_size); - } - - /* Find out the type of sound. Give up if we can't tell. */ - find_sound_type (&s); - - /* Set up a device. */ - if (STRINGP (attrs[SOUND_DEVICE])) - { - int len = SCHARS (attrs[SOUND_DEVICE]); - sd.file = (char *) alloca (len + 1); - strcpy (sd.file, SDATA (attrs[SOUND_DEVICE])); - } - - if (INTEGERP (attrs[SOUND_VOLUME])) - sd.volume = XFASTINT (attrs[SOUND_VOLUME]); - else if (FLOATP (attrs[SOUND_VOLUME])) - sd.volume = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100; - - args[0] = Qplay_sound_functions; - args[1] = sound; - Frun_hook_with_args (2, args); - - /* There is only one type of device we currently support, the VOX - sound driver. Set up the device interface functions for that - device. */ - vox_init (&sd); - - /* Open the device. */ - sd.open (&sd); - - /* Play the sound. */ - s.play (&s, &sd); - - /* Close the input file, if any. */ - if (!STRINGP (s.data)) - { - emacs_close (s.fd); - s.fd = -1; - } - - /* Close the device. */ - sd.close (&sd); - - /* Clean up. */ - current_sound_device = NULL; - current_sound = NULL; - UNGCPRO; - unbind_to (count, Qnil); - return Qnil; -} - - /*********************************************************************** Byte-order Conversion ***********************************************************************/ @@ -555,7 +529,6 @@ be2hs (value) #endif /* 0 */ - /*********************************************************************** RIFF-WAVE (*.wav) ***********************************************************************/ @@ -645,7 +618,6 @@ wav_play (s, sd) } - /*********************************************************************** Sun Audio (*.au) ***********************************************************************/ @@ -735,7 +707,6 @@ au_play (s, sd) } - /*********************************************************************** Voxware Driver Interface ***********************************************************************/ @@ -909,7 +880,6 @@ vox_init (sd) sd->write = vox_write; } - /* Write NBYTES bytes from BUFFER to device SD. */ static void @@ -923,7 +893,231 @@ vox_write (sd, buffer, nbytes) sound_perror ("Error writing to sound device"); } +/* END: Non Windows functions */ +#else /* WINDOWSNT */ +/* BEGIN: Windows specific functions */ + +static int +do_play_sound (psz_file, ui_volume) + const char * psz_file; + unsigned long ui_volume; +{ + int i_result=0; + MCIERROR mci_error=0; + char sz_cmd_buf[520]={0}; + char sz_ret_buf[520]={0}; + MMRESULT mm_result=MMSYSERR_NOERROR; + unsigned long ui_volume_org=0; + BOOL b_reset_volume=FALSE; + memset (sz_cmd_buf, 0, sizeof(sz_cmd_buf)); + memset (sz_ret_buf, 0, sizeof(sz_ret_buf)); + sprintf ( + sz_cmd_buf, + "open \"%s\" alias GNUEmacs_PlaySound_Device wait", + psz_file); + mci_error=mciSendString (sz_cmd_buf, sz_ret_buf, 520, NULL); + if (mci_error != 0) + { + sound_warning ( + "The open mciSendString command failed to open\n" + "the specified sound file"); + i_result=(int)mci_error; + return i_result; + } + if ((ui_volume > 0) && (ui_volume != UINT_MAX)) + { + mm_result=waveOutGetVolume ((HWAVEOUT)WAVE_MAPPER, &ui_volume_org); + if (mm_result == MMSYSERR_NOERROR) + { + b_reset_volume=TRUE; + mm_result=waveOutSetVolume ((HWAVEOUT)WAVE_MAPPER, ui_volume); + if ( mm_result != MMSYSERR_NOERROR) + { + sound_warning ( + "waveOutSetVolume failed to set the volume level\n" + "of the WAVE_MAPPER device.\n" + "As a result, the user selected volume level will\n" + "not be used."); + } + } + else + { + sound_warning ( + "waveOutGetVolume failed to obtain the original\n" + "volume level of the WAVE_MAPPER device.\n" + "As a result, the user selected volume level will\n" + "not be used."); + } + } + memset (sz_cmd_buf, 0, sizeof(sz_cmd_buf)); + memset (sz_ret_buf, 0, sizeof(sz_ret_buf)); + strcpy (sz_cmd_buf, "play GNUEmacs_PlaySound_Device wait"); + mci_error=mciSendString (sz_cmd_buf, sz_ret_buf, 520, NULL); + if (mci_error != 0) + { + sound_warning ( + "The play mciSendString command failed to play the\n" + "opened sound file."); + i_result=(int)mci_error; + } + memset (sz_cmd_buf, 0, sizeof(sz_cmd_buf)); + memset (sz_ret_buf, 0, sizeof(sz_ret_buf)); + strcpy (sz_cmd_buf, "close GNUEmacs_PlaySound_Device wait"); + mci_error=mciSendString ( sz_cmd_buf, sz_ret_buf, 520, NULL); + if (b_reset_volume == TRUE) + { + mm_result=waveOutSetVolume ((HWAVEOUT)WAVE_MAPPER, ui_volume_org); + if (mm_result != MMSYSERR_NOERROR) + { + sound_warning ( + "waveOutSetVolume failed to reset the original volume\n" + "level of the WAVE_MAPPER device."); + } + } + return i_result; +} + +/* END: Windows specific functions */ + +#endif /* WINDOWSNT */ + + +DEFUN ("play-sound-internal", Fplay_sound_internal, Splay_sound_internal, 1, 1, 0, + doc: /* Play sound SOUND. + +Internal use only, use `play-sound' instead.\n */) + (sound) + Lisp_Object sound; +{ + Lisp_Object attrs[SOUND_ATTR_SENTINEL]; + int count = SPECPDL_INDEX (); + +#ifndef WINDOWSNT + Lisp_Object file; + struct gcpro gcpro1, gcpro2; + struct sound_device sd; + struct sound s; + Lisp_Object args[2]; +#else /* WINDOWSNT */ + int len=0; + Lisp_Object lo_file={0}; + char * psz_file=NULL; + unsigned long ui_volume_tmp=UINT_MAX; + unsigned long ui_volume=UINT_MAX; + int i_result=0; +#endif /* WINDOWSNT */ + + /* Parse the sound specification. Give up if it is invalid. */ + if (!parse_sound (sound, attrs)) + error ("Invalid sound specification"); + +#ifndef WINDOWSNT + file = Qnil; + GCPRO2 (sound, file); + bzero (&sd, sizeof sd); + bzero (&s, sizeof s); + current_sound_device = &sd; + current_sound = &s; + record_unwind_protect (sound_cleanup, Qnil); + s.header = (char *) alloca (MAX_SOUND_HEADER_BYTES); + + if (STRINGP (attrs[SOUND_FILE])) + { + /* Open the sound file. */ + s.fd = openp (Fcons (Vdata_directory, Qnil), + attrs[SOUND_FILE], Qnil, &file, Qnil); + if (s.fd < 0) + sound_perror ("Could not open sound file"); + + /* Read the first bytes from the file. */ + s.header_size = emacs_read (s.fd, s.header, MAX_SOUND_HEADER_BYTES); + if (s.header_size < 0) + sound_perror ("Invalid sound file header"); + } + else + { + s.data = attrs[SOUND_DATA]; + s.header_size = min (MAX_SOUND_HEADER_BYTES, SBYTES (s.data)); + bcopy (SDATA (s.data), s.header, s.header_size); + } + + /* Find out the type of sound. Give up if we can't tell. */ + find_sound_type (&s); + + /* Set up a device. */ + if (STRINGP (attrs[SOUND_DEVICE])) + { + int len = SCHARS (attrs[SOUND_DEVICE]); + sd.file = (char *) alloca (len + 1); + strcpy (sd.file, SDATA (attrs[SOUND_DEVICE])); + } + + if (INTEGERP (attrs[SOUND_VOLUME])) + sd.volume = XFASTINT (attrs[SOUND_VOLUME]); + else if (FLOATP (attrs[SOUND_VOLUME])) + sd.volume = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100; + + args[0] = Qplay_sound_functions; + args[1] = sound; + Frun_hook_with_args (2, args); + + /* There is only one type of device we currently support, the VOX + sound driver. Set up the device interface functions for that + device. */ + vox_init (&sd); + + /* Open the device. */ + sd.open (&sd); + + /* Play the sound. */ + s.play (&s, &sd); + + /* Close the input file, if any. */ + if (!STRINGP (s.data)) + { + emacs_close (s.fd); + s.fd = -1; + } + + /* Close the device. */ + sd.close (&sd); + + /* Clean up. */ + current_sound_device = NULL; + current_sound = NULL; + UNGCPRO; +#else /* WINDOWSNT */ + lo_file=Fexpand_file_name (attrs[SOUND_FILE], Qnil); + len=XSTRING (lo_file)->size; + psz_file=(char *)alloca (len+1); + strcpy (psz_file, XSTRING (lo_file)->data); + if (INTEGERP (attrs[SOUND_VOLUME])) + { + ui_volume_tmp=XFASTINT (attrs[SOUND_VOLUME]); + } + else if (FLOATP (attrs[SOUND_VOLUME])) + { + ui_volume_tmp=(unsigned long)XFLOAT_DATA (attrs[SOUND_VOLUME])*100; + } + /* + Based on some experiments I have conducted, a value of 100 or less + for the sound volume is much too low. You cannot even hear it. + A value of UINT_MAX indicates that you wish for the sound to played + at the maximum possible volume. A value of UINT_MAX/2 plays the + sound at 50% maximum volume. Therefore the value passed to do_play_sound + (and thus to waveOutSetVolume must be some fraction of UINT_MAX. + The following code adjusts the user specified volume level appropriately. + */ + if ((ui_volume_tmp > 0) && (ui_volume_tmp <= 100)) + { + ui_volume=ui_volume_tmp * (UINT_MAX / 100); + } + i_result=do_play_sound (psz_file, ui_volume); +#endif /* WINDOWSNT */ + unbind_to (count, Qnil); + return Qnil; +} /*********************************************************************** Initialization diff --git a/src/w32.c b/src/w32.c index 7a31e78d1da..c80c4232bc6 100644 --- a/src/w32.c +++ b/src/w32.c @@ -104,6 +104,171 @@ extern Lisp_Object Vw32_generate_fake_inodes; extern Lisp_Object Vw32_get_true_file_attributes; extern Lisp_Object Vw32_num_mouse_buttons; + +/* + BEGIN: Wrapper functions around OpenProcessToken + and other functions in advapi32.dll that are only + supported in Windows NT / 2k / XP +*/ + /* ** Function pointer typedefs ** */ +typedef BOOL (WINAPI * OpenProcessToken_Proc) ( + HANDLE ProcessHandle, + DWORD DesiredAccess, + PHANDLE TokenHandle); +typedef BOOL (WINAPI * GetTokenInformation_Proc) ( + HANDLE TokenHandle, + TOKEN_INFORMATION_CLASS TokenInformationClass, + LPVOID TokenInformation, + DWORD TokenInformationLength, + PDWORD ReturnLength); +#ifdef _UNICODE +const char * const LookupAccountSid_Name = "LookupAccountSidW"; +#else +const char * const LookupAccountSid_Name = "LookupAccountSidA"; +#endif +typedef BOOL (WINAPI * LookupAccountSid_Proc) ( + LPCTSTR lpSystemName, + PSID Sid, + LPTSTR Name, + LPDWORD cbName, + LPTSTR DomainName, + LPDWORD cbDomainName, + PSID_NAME_USE peUse); +typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) ( + PSID pSid); + + /* ** A utility function ** */ +static BOOL is_windows_9x () +{ + BOOL b_ret=0; + OSVERSIONINFO os_ver; + ZeroMemory(&os_ver, sizeof(OSVERSIONINFO)); + os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx (&os_ver)) + { + b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); + } + return b_ret; +} + + /* ** The wrapper functions ** */ + +BOOL WINAPI open_process_token ( + HANDLE ProcessHandle, + DWORD DesiredAccess, + PHANDLE TokenHandle) +{ + OpenProcessToken_Proc pfn_Open_Process_Token = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + return FALSE; + } + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + pfn_Open_Process_Token = + (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken"); + if (pfn_Open_Process_Token == NULL) + { + return FALSE; + } + return ( + pfn_Open_Process_Token ( + ProcessHandle, + DesiredAccess, + TokenHandle) + ); +} + +BOOL WINAPI get_token_information ( + HANDLE TokenHandle, + TOKEN_INFORMATION_CLASS TokenInformationClass, + LPVOID TokenInformation, + DWORD TokenInformationLength, + PDWORD ReturnLength) +{ + GetTokenInformation_Proc pfn_Get_Token_Information = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + return FALSE; + } + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + pfn_Get_Token_Information = + (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation"); + if (pfn_Get_Token_Information == NULL) + { + return FALSE; + } + return ( + pfn_Get_Token_Information ( + TokenHandle, + TokenInformationClass, + TokenInformation, + TokenInformationLength, + ReturnLength) + ); +} + +BOOL WINAPI lookup_account_sid ( + LPCTSTR lpSystemName, + PSID Sid, + LPTSTR Name, + LPDWORD cbName, + LPTSTR DomainName, + LPDWORD cbDomainName, + PSID_NAME_USE peUse) +{ + LookupAccountSid_Proc pfn_Lookup_Account_Sid = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + return FALSE; + } + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + pfn_Lookup_Account_Sid = + (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name); + if (pfn_Lookup_Account_Sid == NULL) + { + return FALSE; + } + return ( + pfn_Lookup_Account_Sid ( + lpSystemName, + Sid, + Name, + cbName, + DomainName, + cbDomainName, + peUse) + ); +} + +PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority ( + PSID pSid) +{ + GetSidIdentifierAuthority_Proc pfn_Get_Sid_Identifier_Authority = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + return NULL; + } + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + pfn_Get_Sid_Identifier_Authority = + (GetSidIdentifierAuthority_Proc) GetProcAddress ( + hm_advapi32, "GetSidIdentifierAuthority"); + if (pfn_Get_Sid_Identifier_Authority == NULL) + { + return NULL; + } + return (pfn_Get_Sid_Identifier_Authority (pSid)); +} + +/* + END: Wrapper functions around OpenProcessToken + and other functions in advapi32.dll that are only + supported in Windows NT / 2k / XP +*/ + /* Equivalent of strerror for W32 error codes. */ char * @@ -254,11 +419,15 @@ init_user_info () HANDLE token = NULL; SID_NAME_USE user_type; - if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token) - && GetTokenInformation (token, TokenUser, + if ( + open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token) + && get_token_information ( + token, TokenUser, (PVOID) user_sid, sizeof (user_sid), &trash) - && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length, - domain, &dlength, &user_type)) + && lookup_account_sid ( + NULL, *((PSID *) user_sid), name, &length, + domain, &dlength, &user_type) + ) { strcpy (the_passwd.pw_name, name); /* Determine a reasonable uid value. */ @@ -271,7 +440,7 @@ init_user_info () { SID_IDENTIFIER_AUTHORITY * pSIA; - pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid)); + pSIA = get_sid_identifier_authority (*((PSID *) user_sid)); /* I believe the relative portion is the last 4 bytes (of 6) with msb first. */ the_passwd.pw_uid = ((pSIA->Value[2] << 24) + @@ -282,12 +451,12 @@ init_user_info () the_passwd.pw_uid = the_passwd.pw_uid % 60001; /* Get group id */ - if (GetTokenInformation (token, TokenPrimaryGroup, + if (get_token_information (token, TokenPrimaryGroup, (PVOID) user_sid, sizeof (user_sid), &trash)) { SID_IDENTIFIER_AUTHORITY * pSIA; - pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid)); + pSIA = get_sid_identifier_authority (*((PSID *) user_sid)); the_passwd.pw_gid = ((pSIA->Value[2] << 24) + (pSIA->Value[3] << 16) + (pSIA->Value[4] << 8) + diff --git a/src/w32.h b/src/w32.h index 2b87f58a567..24fda2c648b 100644 --- a/src/w32.h +++ b/src/w32.h @@ -124,5 +124,10 @@ extern LPBYTE w32_get_resource (char * key, LPDWORD type); extern void init_ntproc (); extern void term_ntproc (); +extern void syms_of_w32term (); +extern void syms_of_w32fns (); +extern void syms_of_w32select (); +extern void syms_of_w32menu (); +extern void syms_of_fontset (); #endif /* EMACS_W32_H */ diff --git a/src/w32fns.c b/src/w32fns.c index e0925869d89..7037493e3a1 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -283,7 +283,12 @@ static unsigned mouse_move_timer = 0; /* Window that is tracking the mouse. */ static HWND track_mouse_window; -FARPROC track_mouse_event_fn; + +typedef BOOL (WINAPI * TrackMouseEvent_Proc) ( + IN OUT LPTRACKMOUSEEVENT lpEventTrack + ); + +TrackMouseEvent_Proc track_mouse_event_fn=NULL; /* W95 mousewheel handler */ unsigned int msh_mousewheel = 0; @@ -4929,6 +4934,30 @@ w32_wnd_proc (hwnd, msg, wParam, lParam) goto dflt; case WM_SETFOCUS: + /* + Reinitialize the function pointer track_mouse_event_fn here. + This is required even though it is initialized in syms_of_w32fns + which is called in main (emacs.c). + Reinitialize the function pointer track_mouse_event_fn here. + Even though this function pointer is initialized in + syms_of_w32fns which is called from main (emacs.c), + we need to initialize it again here in order to prevent + a crash that occurs in Windows 9x (possibly only when Emacs + was built on Windows NT / 2000 / XP?) when handling the + WM_MOUSEMOVE message. + The crash occurs when attempting to call the Win32 API + function TrackMouseEvent through the function pointer. + It appears as if the function pointer that is obtained when + syms_of_w32fns is called from main is no longer valid + (possibly due to DLL relocation?). + To resolve this issue, I have placed a call to reinitialize + this function pointer here because this message gets received + when the Emacs window gains focus. + */ + track_mouse_event_fn = + (TrackMouseEvent_Proc) GetProcAddress ( + GetModuleHandle ("user32.dll"), + "TrackMouseEvent"); dpyinfo->faked_key = 0; reset_modifiers (); register_hot_keys (hwnd); @@ -14843,7 +14872,7 @@ syms_of_w32fns () /* TrackMouseEvent not available in all versions of Windows, so must load it dynamically. Do it once, here, instead of every time it is used. */ - track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent"); + track_mouse_event_fn = (TrackMouseEvent_Proc) GetProcAddress (user32_lib, "TrackMouseEvent"); track_mouse_window = NULL; w32_visible_system_caret_hwnd = NULL; diff --git a/src/w32menu.c b/src/w32menu.c index 44791448d94..8139a0ad956 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -129,8 +129,23 @@ typedef struct _widget_value static HMENU current_popup_menu; -FARPROC get_menu_item_info; -FARPROC set_menu_item_info; +void syms_of_w32menu (); + +typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) ( + IN HMENU, + IN UINT, + IN BOOL, + IN OUT LPMENUITEMINFOA + ); +typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) ( + IN HMENU, + IN UINT, + IN BOOL, + IN LPCMENUITEMINFOA + ); + +GetMenuItemInfoA_Proc get_menu_item_info=NULL; +SetMenuItemInfoA_Proc set_menu_item_info=NULL; Lisp_Object Vmenu_updating_frame; @@ -1591,6 +1606,26 @@ void initialize_frame_menubar (f) FRAME_PTR f; { + HMODULE user32 = GetModuleHandle ("user32.dll"); + /* + Reinitialize the function pointers set_menu_item_info and + get_menu_item_info here. + Even though these function pointers are initialized in + syms_of_w32menu which is called from main (emacs.c), + we need to initialize them again here in order to prevent + a crash that occurs in Windows 9x (possibly only when Emacs + was built on Windows NT / 2000 / XP?) in add_menu_item. + The crash occurs when attempting to call the Win32 API + function SetMenuItemInfo through the function pointer. + It appears as if the function pointer that is obtained when + syms_of_w32menu is called from main is no longer valid + (possibly due to DLL relocation?). + To resolve this issue, I have placed calls to reinitialize + these function pointers here because this function is the + entry point for menu creation. + */ + get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); + set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); /* This function is called before the first chance to redisplay the frame. It has to be, so the frame will have the right size. */ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); @@ -2355,13 +2390,12 @@ w32_free_menu_strings (hwnd) #endif /* HAVE_MENUS */ - -syms_of_w32menu () +void syms_of_w32menu () { /* See if Get/SetMenuItemInfo functions are available. */ HMODULE user32 = GetModuleHandle ("user32.dll"); - get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA"); - set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA"); + get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); + set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); staticpro (&menu_items); menu_items = Qnil;