From 9785d95b98c184d5051775555e5af0b707a5ce9a Mon Sep 17 00:00:00 2001 From: Ben Key Date: Wed, 18 Dec 2002 06:16:28 +0000 Subject: [PATCH] Revisited my earlier fix for the following entry in etc/PROBLEMS: 'Emacs built on Windows 9x/ME crashes at startup on Windows XP, or Emacs builtpart of on XP crashes at startup on Windows 9x/ME.' Fixed several Windows API errors detected by BoundsChecker --- src/ChangeLog | 85 +++++++++++++++++++++++++++++++++++++++ src/emacs.c | 12 ++++++ src/w32.c | 107 +++++++++++++++++++++++++++++++++++--------------- src/w32.h | 3 ++ src/w32fns.c | 55 +++++++++++--------------- src/w32menu.c | 43 +++++++++----------- src/w32term.c | 12 ++++-- 7 files changed, 226 insertions(+), 91 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index ae7f978823..f7fc7bb125 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,88 @@ +2002-12-17 Ben Key + * Revisited my earlier fix for the following entry in + etc/PROBLEMS: + "Emacs built on Windows 9x/ME crashes at startup on Windows XP, + or Emacs builtpart of on XP crashes at startup on Windows 9x/ME." + + These changes were in part based upon suggestions made by Peter + 'Luna' Runestig [peter@runestig.com]. + + * w32.c (g_b_init_is_windows_9x, g_b_init_open_process_token, + g_b_init_get_token_information, g_b_init_lookup_account_sid, + g_b_init_get_sid_identifier_authority ): Added several static + global variables. + + * w32.c (globals_of_w32): New function. Used to initialize those + global variables that must always be initialized on startup even + when the global variable initialized is non zero. Its primary + purpose at this time is to set the global variables + g_b_init_is_windows_9x, g_b_init_open_process_token, + g_b_init_get_token_information, g_b_init_lookup_account_sid, and + g_b_init_get_sid_identifier_authority to 0 on startup. Called + from main. + + * w32.c (is_windows_9x): Perform initialization only if + g_b_init_is_windows_9x is equal to 0. On initialization set + g_b_init_is_windows_9x equal to 1. + + * w32.c (open_process_token): Perform initialization only if + g_b_init_open_process_token is equal to 0. On initialization set + g_b_init_open_process_token equal to 1. + + * w32.c (get_token_information): Perform initialization only if + g_b_init_get_token_information is equal to 0. On initialization + set g_b_init_get_token_information equal to 1. + + * w32.c (lookup_account_sid): Perform initialization only if + g_b_init_lookup_account_sid is equal to 0. On initialization + set g_b_init_lookup_account_sid equal to 1. + + * w32.c (get_sid_identifier_authority): Perform initialization + only if g_b_init_get_sid_identifier_authority is equal to 0. On + initialization set g_b_init_get_sid_identifier_authority equal to + 1. + + * w32fns.c (globals_of_w32fns): New function. Used to initialize + those global variables that must always be initialized on startup + even when the global variable initialized is non zero. Its + primary purpose at this time is to initialize the global variable + track_mouse_event_fn. + + * w32fns.c (w32_wnd_proc): Remove initialization of + track_mouse_event_fn from the handler for the WM_SETFOCUS + message. + + * w32fns.c (syms_of_w32fns): Call globals_of_w32fns. + + * w32menu.c (globals_of_w32menu): New function. Used to + initialize those global variables that must always be initialized + on startup even when the global variable initialized is non zero. + Its primary purpose at this time is to initialize the global + variables get_menu_item_info and set_menu_item_info. + + * w32menu.c (initialize_frame_menubar): Remove initialization of + get_menu_item_info and set_menu_item_info. + + * w32menu.c (syms_of_w32menu): Call globals_of_w32menu. + + * w32.h (globals_of_w32, globals_of_w32fns, globals_of_w32menu): + Declare them. + + * emacs.c (main): Call globals_of_w32 prior to calling + init_environment if WINDOWSNT is defined. Call globals_of_w32fns + and globals_of_w32menu if initialized is non zero and HAVE_NTGUI + is defined. + + * w32term.c (x_update_window_begin): Fix Windows API error + detected by BoundsChecker. Test to determine if + w32_system_caret_hwnd is NULL prior to attempting to use + SendMessage to send the WM_EMACS_HIDE_CARET message to it. + + * w32term.c (x_update_window_end): Fix Windows API error + detected by BoundsChecker. Test to determine if + w32_system_caret_hwnd is NULL prior to attempting to use + SendMessage to send the WM_EMACS_SHOW_CARET message to it. + 2002-12-17 Kenichi Handa * coding.c (coding_system_require_warning): New variable. diff --git a/src/emacs.c b/src/emacs.c index 7bbaac8f92..7b5830c06a 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1375,6 +1375,7 @@ main (argc, argv #endif /* MSDOS */ #ifdef WINDOWSNT + globals_of_w32 (); /* Initialize environment from registry settings. */ init_environment (argv); init_ntproc (); /* must precede init_editfns. */ @@ -1540,6 +1541,17 @@ main (argc, argv keys_of_keymap (); keys_of_minibuf (); keys_of_window (); + } + else + { + /* + Initialization that must be done even if the global variable + initialized is non zero + */ +#ifdef HAVE_NTGUI + globals_of_w32fns (); + globals_of_w32menu (); +#endif /* end #ifdef HAVE_NTGUI */ } if (!noninteractive) diff --git a/src/w32.c b/src/w32.c index a608aad36f..57b0e28d0c 100644 --- a/src/w32.c +++ b/src/w32.c @@ -99,12 +99,23 @@ Boston, MA 02111-1307, USA. #include "w32heap.h" #include "systime.h" +void globals_of_w32 (); + extern Lisp_Object Vw32_downcase_file_names; extern Lisp_Object Vw32_generate_fake_inodes; extern Lisp_Object Vw32_get_true_file_attributes; extern Lisp_Object Vw32_num_mouse_buttons; +/* + Initialization states + */ +static BOOL g_b_init_is_windows_9x; +static BOOL g_b_init_open_process_token; +static BOOL g_b_init_get_token_information; +static BOOL g_b_init_lookup_account_sid; +static BOOL g_b_init_get_sid_identifier_authority; + /* BEGIN: Wrapper functions around OpenProcessToken and other functions in advapi32.dll that are only @@ -140,15 +151,19 @@ typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) ( /* ** A utility function ** */ static BOOL is_windows_9x () { - BOOL b_ret=0; + static BOOL s_b_ret=0; OSVERSIONINFO os_ver; - ZeroMemory(&os_ver, sizeof(OSVERSIONINFO)); - os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx (&os_ver)) + if (g_b_init_is_windows_9x == 0) { - b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); + g_b_init_is_windows_9x = 1; + ZeroMemory(&os_ver, sizeof(OSVERSIONINFO)); + os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx (&os_ver)) + { + s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); + } } - return b_ret; + return s_b_ret; } /* ** The wrapper functions ** */ @@ -158,21 +173,25 @@ BOOL WINAPI open_process_token ( DWORD DesiredAccess, PHANDLE TokenHandle) { - OpenProcessToken_Proc pfn_Open_Process_Token = NULL; + static OpenProcessToken_Proc s_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) + if (g_b_init_open_process_token == 0) + { + g_b_init_open_process_token = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Open_Process_Token = + (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken"); + } + if (s_pfn_Open_Process_Token == NULL) { return FALSE; } return ( - pfn_Open_Process_Token ( + s_pfn_Open_Process_Token ( ProcessHandle, DesiredAccess, TokenHandle) @@ -186,21 +205,25 @@ BOOL WINAPI get_token_information ( DWORD TokenInformationLength, PDWORD ReturnLength) { - GetTokenInformation_Proc pfn_Get_Token_Information = NULL; + static GetTokenInformation_Proc s_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) + if (g_b_init_get_token_information == 0) + { + g_b_init_get_token_information = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Get_Token_Information = + (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation"); + } + if (s_pfn_Get_Token_Information == NULL) { return FALSE; } return ( - pfn_Get_Token_Information ( + s_pfn_Get_Token_Information ( TokenHandle, TokenInformationClass, TokenInformation, @@ -218,21 +241,25 @@ BOOL WINAPI lookup_account_sid ( LPDWORD cbDomainName, PSID_NAME_USE peUse) { - LookupAccountSid_Proc pfn_Lookup_Account_Sid = NULL; + static LookupAccountSid_Proc s_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) + if (g_b_init_lookup_account_sid == 0) + { + g_b_init_lookup_account_sid = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Lookup_Account_Sid = + (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name); + } + if (s_pfn_Lookup_Account_Sid == NULL) { return FALSE; } return ( - pfn_Lookup_Account_Sid ( + s_pfn_Lookup_Account_Sid ( lpSystemName, Sid, Name, @@ -246,21 +273,25 @@ BOOL WINAPI lookup_account_sid ( PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority ( PSID pSid) { - GetSidIdentifierAuthority_Proc pfn_Get_Sid_Identifier_Authority = NULL; + static GetSidIdentifierAuthority_Proc s_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) + if (g_b_init_get_sid_identifier_authority == 0) + { + g_b_init_get_sid_identifier_authority = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Get_Sid_Identifier_Authority = + (GetSidIdentifierAuthority_Proc) GetProcAddress ( + hm_advapi32, "GetSidIdentifierAuthority"); + } + if (s_pfn_Get_Sid_Identifier_Authority == NULL) { return NULL; } - return (pfn_Get_Sid_Identifier_Authority (pSid)); + return (s_pfn_Get_Sid_Identifier_Authority (pSid)); } /* @@ -3909,4 +3940,18 @@ init_ntproc () check_windows_init_file (); } +/* + globals_of_w32 is used to initialize those global variables that + must always be initialized on startup even when the global variable + initialized is non zero (see the function main in emacs.c). +*/ +void globals_of_w32 () +{ + g_b_init_is_windows_9x = 0; + g_b_init_open_process_token = 0; + g_b_init_get_token_information = 0; + g_b_init_lookup_account_sid = 0; + g_b_init_get_sid_identifier_authority = 0; +} + /* end of nt.c */ diff --git a/src/w32.h b/src/w32.h index 24fda2c648..c8733c41a2 100644 --- a/src/w32.h +++ b/src/w32.h @@ -124,10 +124,13 @@ extern LPBYTE w32_get_resource (char * key, LPDWORD type); extern void init_ntproc (); extern void term_ntproc (); +extern void globals_of_w32 (); extern void syms_of_w32term (); extern void syms_of_w32fns (); +extern void globals_of_w32fns (); extern void syms_of_w32select (); extern void syms_of_w32menu (); +extern void globals_of_w32menu (); extern void syms_of_fontset (); #endif /* EMACS_W32_H */ diff --git a/src/w32fns.c b/src/w32fns.c index 86984597e9..08d81d1029 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -55,6 +55,9 @@ Boston, MA 02111-1307, USA. */ #include #define FILE_NAME_TEXT_FIELD edt1 +void syms_of_w32fns (); +void globals_of_w32fns (); + extern void free_frame_menubar (); extern void x_compute_fringe_widths P_ ((struct frame *, int)); extern double atof (); @@ -4934,30 +4937,6 @@ 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); @@ -14906,14 +14885,9 @@ If the underlying system call fails, value is nil. */) void syms_of_w32fns () { - HMODULE user32_lib = GetModuleHandle ("user32.dll"); - - /* This is zero if not using MS-Windows. */ + globals_of_w32fns (); + /* This is zero if not using MS-Windows. */ w32_in_use = 0; - - /* 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 = (TrackMouseEvent_Proc) GetProcAddress (user32_lib, "TrackMouseEvent"); track_mouse_window = NULL; w32_visible_system_caret_hwnd = NULL; @@ -15496,7 +15470,26 @@ versions of Windows) characters. */); defsubr (&Sx_file_dialog); } + +/* + globals_of_w32fns is used to initialize those global variables that + must always be initialized on startup even when the global variable + initialized is non zero (see the function main in emacs.c). + globals_of_w32fns is called from syms_of_w32fns when the global + variable initialized is 0 and directly from main when initialized + is non zero. + */ +void globals_of_w32fns () +{ + HMODULE user32_lib = GetModuleHandle ("user32.dll"); + /* + 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 = (TrackMouseEvent_Proc) GetProcAddress (user32_lib, "TrackMouseEvent"); +} + void init_xfns () { diff --git a/src/w32menu.c b/src/w32menu.c index 8139a0ad95..e573986b31 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -130,6 +130,7 @@ typedef struct _widget_value static HMENU current_popup_menu; void syms_of_w32menu (); +void globals_of_w32menu (); typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) ( IN HMENU, @@ -1606,26 +1607,6 @@ 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)); @@ -2392,11 +2373,7 @@ w32_free_menu_strings (hwnd) void syms_of_w32menu () { - /* See if Get/SetMenuItemInfo functions are available. */ - HMODULE user32 = GetModuleHandle ("user32.dll"); - get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); - set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); - + globals_of_w32menu (); staticpro (&menu_items); menu_items = Qnil; @@ -2415,3 +2392,19 @@ The enable predicate for a menu command should check this variable. */); defsubr (&Sx_popup_dialog); #endif } + +/* + globals_of_w32menu is used to initialize those global variables that + must always be initialized on startup even when the global variable + initialized is non zero (see the function main in emacs.c). + globals_of_w32menu is called from syms_of_w32menu when the global + variable initialized is 0 and directly from main when initialized + is non zero. + */ +void globals_of_w32menu () +{ + /* See if Get/SetMenuItemInfo functions are available. */ + HMODULE user32 = GetModuleHandle ("user32.dll"); + get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); + set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); +} diff --git a/src/w32term.c b/src/w32term.c index 73740b2555..08b076df03 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -603,8 +603,10 @@ x_update_window_begin (w) struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f); /* Hide the system caret during an update. */ - if (w32_use_visible_system_caret) - SendMessage (w32_system_caret_hwnd, WM_EMACS_HIDE_CARET, 0, 0); + if (w32_use_visible_system_caret && w32_system_caret_hwnd) + { + SendMessage (w32_system_caret_hwnd, WM_EMACS_HIDE_CARET, 0, 0); + } updated_window = w; set_output_cursor (&w->cursor); @@ -730,8 +732,10 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) /* Unhide the caret. This won't actually show the cursor, unless it was visible before the corresponding call to HideCaret in x_update_window_begin. */ - if (w32_use_visible_system_caret) - SendMessage (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0); + if (w32_use_visible_system_caret && w32_system_caret_hwnd) + { + SendMessage (w32_system_caret_hwnd, WM_EMACS_SHOW_CARET, 0, 0); + } updated_window = NULL; } -- 2.20.1