www.pudn.com > helpview.zip > Menu.c, change:1997-10-15,size:35729b


/* 
  
Copyright 1997 Willows Software, Inc.  
 
This library is free software; you can redistribute it and/or 
modify it under the terms of the GNU Library General Public License as 
published by the Free Software Foundation; either version 2 of the 
License, or (at your option) any later version. 
 
This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
Library General Public License for more details. 
 
You should have received a copy of the GNU Library General Public 
License along with this library; see the file COPYING.LIB.  If 
not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
Cambridge, MA 02139, USA. 
 
*/ 
 
/************************************************************************* 
* 
* MENU.C 
* Menu routines.      
* 
* Author: Paul E. Kissel 
* 
**************************************************************************/ 
 
/*********************************** 
** 
**  System Includes 
** 
***********************************/ 
 
#include <string.h> 
 
 
/*********************************** 
** 
**  App. Includes 
** 
***********************************/ 
 
#include "menu.h" 
#include "winmem.h" 
#include "globals.h" 
#include "msgbox.h" 
#include "twhlprc.h" 
#include "wnddata.h" 
#include "hlpmacro.h" 
#include "macroeng.h" 
 
 
/*********************************** 
** 
**  Private File Defines 
** 
***********************************/ 
 
 
/* 
** Information for an menu in the list. 
*/ 
typedef HGLOBAL HMENUINFO; 
typedef struct tagMENUINFO 
{ 
  ATOM      MenuID;       /* Menu ID string converted to an ATOM. Atom used for the  
                             WM_COMMAND ID.*/ 
  HMENU     hMenu;        /* If the item is a popup menu, this is its menu handle. */ 
  HMENU     hParentMenu;  /* Menu on which the item resides. */ 
  HGLOBAL   hMacroString; /* Macro to run. */ 
  HMENUINFO Next;         /* Next MENUINFO structure. */ 
}  
MENUINFO; 
typedef MENUINFO * FPMENUINFO; 
 
 
/* 
** Information for the menu system. 
*/ 
typedef HMENUINFO HMENULIST; 
typedef struct tagMENUSYS 
{ 
  HWND      hDataWnd;        /* Main data window. */ 
  HMENU     hMenuBar;        /* Handle to help window's menu bar. */ 
  HMENULIST hMenuList;       /* Top of the menu list. */ 
}  
MENUSYS; 
typedef MENUSYS * FPMENUSYS; 
 
 
/*  
** EnumMenuInfo() callback function.  
*/ 
typedef BOOL ( CALLBACK * MENUINFOENUMPROC )( FPMENUINFO fpMenuInfo, LPARAM lParam ); 
 
 
/*  
** Data used by the MenuSelected() function.  
*/ 
typedef struct tagMENUSELFUNCDATA 
{ 
  BOOL bProcessed; 
  HWND hExecWnd; 
  HWND hDataWnd; 
  ATOM MenuID; 
} 
MENUSELFUNCDATA; 
typedef MENUSELFUNCDATA * FPMENUSELFUNCDATA; 
 
 
/*  
** Data used by the GetMenuInfo() function.  
*/ 
typedef struct tagGETMENUINFOFUNCDATA 
{ 
  BOOL       bFound; 
  ATOM       MenuID; 
  FPMENUINFO MenuInfoPtr; 
} 
GETMENUINFOFUNCDATA; 
typedef GETMENUINFOFUNCDATA * FPGETWINDOWFUNCDATA; 
 
 
/*  
** Data used by the ChangeItemBinding() function.  
*/ 
typedef struct tagCHANGEBINDINGFUNCDATA 
{ 
  BOOL  bSuccess;         /* Was the function successsful. */ 
  ATOM  MenuID;           /* Menu's ID. */ 
  LPSTR MacroStringPtr;   /* Replacement macro. */ 
  HWND  hErrorWnd;        /* Window to use for errors. */ 
} 
CHANGEBINDINGFUNCDATA; 
typedef CHANGEBINDINGFUNCDATA * FPCHANGEBINDINGFUNCDATA; 
 
 
 
/*********************************** 
** 
**  Private Function Prototypes 
** 
***********************************/ 
 
static BOOL CALLBACK ChangeItemBindingProc( FPMENUINFO fpMenuInfo, LPARAM lParam ); 
BOOL GetMenuInfo( HMENULIST hMenuList, LPSTR lpMenuID, FPMENUINFO MenuInfoPtr ); 
static BOOL CALLBACK FindMenuInfo( FPMENUINFO MenuInfoPtr, LPARAM lParam ); 
static BOOL CALLBACK MenuSelectedProc( FPMENUINFO fpMenuInfo, LPARAM lParam ); 
static BOOL SaveMenuInfo( HWND hErrorWnd, HMENULIST * hMenuList, FPMENUINFO fpMenuInfo ); 
static HMENUINFO NewMenuInfo( HWND hErrorWnd, FPMENUINFO fpMenuInfo ); 
static void FreeMenuInfo( HMENUINFO hMenuInfo ); 
static void InsertMenuInfo( HMENULIST * hMenuList, HMENUINFO hNewMenuInfo ); 
static void FreeMenuList( HMENULIST * hMenuList ); 
static HMENUINFO GetNextMenuInfo( HMENUINFO hMenuInfo ); 
static void EnumMenuInfo( HMENULIST hMenuList, MENUINFOENUMPROC MenuInfoEnumProc, LPARAM lParam ); 
static BOOL DeleteMenuInfo( HMENULIST * hMenuList, FPMENUINFO fpDelMenuInfo ); 
 
 
/*********************************************************************************** 
** 
**                              Shared Functions 
** 
************************************************************************************/ 
 
                                                                  
/*********************************** 
** 
**  Starts menu support system.  
** 
**  Returns: 
** 
**     Success - TRUE. 
**     Failure - FALSE. 
** 
***********************************/ 
BOOL StartMenuSupport( HWND hWnd, HWND hDataWnd ) 
{ 
  HMENUSYS  hMenuSys; 
  FPMENUSYS MenuSysPtr; 
   
  /* Allocate memory for menu support data. */ 
  if( !GlobalAllocMem( hWnd, &hMenuSys, sizeof(MENUSYS) ) ) 
  { 
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTSTARTMENUSYS, MB_ICONHAND | MB_OK ); 
 
    /* Set the menu sys. data to NULL. */ 
    WndData( hWnd, WDM_SETMENUSYS, (DWORD) NULL, NULL ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
   
  /* Lock data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
       
  /* Init. structure. */ 
  MenuSysPtr->hDataWnd = hDataWnd; 
  MenuSysPtr->hMenuBar = 0; 
  MenuSysPtr->hMenuList = 0; 
 
  /* Unlock data. */ 
  GlobalUnlock( hMenuSys ); 
 
    /* Set the menu sys. data. */ 
  WndData( hWnd, WDM_SETMENUSYS, (DWORD) hMenuSys, NULL ); 
             
  /* Success. */ 
  return( TRUE );   
} 
 
 
/*********************************** 
** 
**  Stops menu support system.  
** 
**  Returns: None 
** 
***********************************/ 
void StopMenuSupport( HWND hWnd ) 
{ 
  HMENUSYS  hMenuSys; 
             
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* If we have a menu support. */ 
  if( hMenuSys != 0 ) 
  { 
    /* Destroy the help window's menu and the list. */ 
    DeleteAllMenus( hWnd ); 
   
    /* Free menu support data. */ 
    MyGlobalFree( hMenuSys ); 
 
    /* Set the menu sys. data. */ 
    WndData( hWnd, WDM_SETMENUSYS, (DWORD) 0, NULL ); 
  } 
} 
 
 
/********************************************************************* 
** 
**  Runs macro for the given menu command. 
** 
**  Returns: 
** 
**      TRUE: Processed key. 
**     FALSE: Not Processed key. 
** 
**********************************************************************/ 
BOOL MenuSelected( HWND hWnd, WORD MenuID ) 
{ 
  MENUSELFUNCDATA MenuSelData; 
  HMENULIST hMenuList; 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* If we have a menu support. */ 
  if( hMenuSys != NULL ) 
  { 
    /* Lock data. */ 
    MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
     
    /* Get handle to the menu list. */     
    hMenuList =  MenuSysPtr->hMenuList; 
 
    /* Unlock data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Init. data struct. */ 
    MenuSelData.bProcessed  = FALSE; 
    MenuSelData.hDataWnd    = MenuSysPtr->hDataWnd; 
    MenuSelData.hExecWnd    = hWnd; 
    MenuSelData.MenuID      = MenuID; 
         
    /* Find menu item and run macro. */ 
    EnumMenuInfo( hMenuList, (MENUINFOENUMPROC) MenuSelectedProc, (LPARAM) (FPMENUSELFUNCDATA) &MenuSelData ); 
  } 
  else 
  { 
    /* Not processed. */ 
    return( FALSE ); 
  } 
 
  /* Processed? */ 
  return( MenuSelData.bProcessed ); 
} 
 
 
 
/********************************************************************* 
** 
**  Adds a new popup menu to the list and to the menu bar.  
** 
**  Position is the position of the new menu.  If position is -1, 
**  the menu is inserted as the last item. 
** 
**********************************************************************/ 
BOOL MyCreatePopup 
(  
  HWND hWnd,  
  LPSTR lpMenuID, 
  LPSTR lpMenuText, 
  short int nPosition 
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
 
  /* Menu info. to store in menu info. list. */ 
  MENUINFO MenuInfo; 
   
  BOOL bReturn; 
   
  BOOL bCreatedBar; 
   
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
     
  /* Verify that the new menu's ID string is unique. */ 
  if( GetMenuInfo( MenuSysPtr->hMenuList, lpMenuID, &MenuInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUALREADYEXISTS, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
 
  /* If there is no menu bar the create one and set it. */ 
  if( MenuSysPtr->hMenuBar == NULL )  
  { 
    /* Create the menu bar. */ 
    MenuSysPtr->hMenuBar = CreateMenu(); 
    bCreatedBar = TRUE; 
 
    /* Error. */ 
    if( MenuSysPtr->hMenuBar == NULL )  
    { 
      /* Unlock menu sys. data. */ 
      GlobalUnlock( hMenuSys ); 
       
      /* Error. */  
      MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTCREATEMENU, MB_ICONHAND | MB_OK ); 
   
      /* Failure. */ 
      return( FALSE ); 
    } 
 
    SetMenu( hWnd, MenuSysPtr->hMenuBar ); 
  } 
  else bCreatedBar = FALSE; 
 
 
  /* Create the popup menu. */ 
  MenuInfo.hMenu = CreatePopupMenu(); 
  if( MenuInfo.hMenu == NULL )  
  { 
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTCREATEMENU, MB_ICONHAND | MB_OK ); 
 
    /* If just created the bar. */ 
    if( bCreatedBar == TRUE ) 
    { 
      /* Remove the bar. */ 
      SetMenu( hWnd, NULL ); 
      DestroyMenu( MenuSysPtr->hMenuBar ); 
      MenuSysPtr->hMenuBar = NULL; 
    } 
     
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Failure. */ 
    return( FALSE ); 
  } 
 
 
  /* Add the menu to the menu bar. */ 
  if( ! InsertMenu( MenuSysPtr->hMenuBar, nPosition, MF_BYPOSITION | MF_ENABLED | MF_STRING | MF_POPUP, (UINT) MenuInfo.hMenu, lpMenuText) ) 
  { 
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTCREATEMENU, MB_ICONHAND | MB_OK ); 
 
    /* If just created the bar. */ 
    if( bCreatedBar == TRUE ) 
    { 
      /* Remove the bar. */ 
      SetMenu( hWnd, NULL ); 
      DestroyMenu( MenuSysPtr->hMenuBar ); 
      MenuSysPtr->hMenuBar = NULL; 
    } 
     
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Failure. */ 
    return( FALSE ); 
  } 
   
  /* Init. the other menu info. */ 
  MenuInfo.MenuID       = AddAtom( lpMenuID );    
  MenuInfo.hParentMenu  = MenuSysPtr->hMenuBar;    
  MenuInfo.hMacroString = NULL;    
 
  /* Save the menu info. */ 
  bReturn = SaveMenuInfo( hWnd, &(MenuSysPtr)->hMenuList, (FPMENUINFO) &MenuInfo ); 
  if( bReturn == FALSE ) 
  { 
    /* Remove the new menu from the menu bar. */ 
    DeleteMenu( MenuSysPtr->hMenuBar, nPosition, MF_BYPOSITION ); 
    DestroyMenu( MenuInfo.hMenu ); 
     
    /* If just created the bar. */ 
    if( bCreatedBar == TRUE ) 
    { 
      /* Remove the bar. */ 
      SetMenu( hWnd, NULL ); 
      DestroyMenu( MenuSysPtr->hMenuBar ); 
      MenuSysPtr->hMenuBar = NULL; 
    } 
     
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Failure. */ 
    return( FALSE ); 
  } 
       
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
   
  /* Show changes. */ 
  DrawMenuBar( hWnd ); 
     
  /* Success. */ 
  return( TRUE ); 
} 
 
 
 
/********************************************************************* 
** 
**  Adds a new menu item to a menu.  
** 
**  Position is the position of the new menu item.  If position is -1, 
**  the menu item is inserted as the last item. 
** 
**********************************************************************/ 
BOOL MyInsertMenu 
(  
  HWND hWnd,  
  LPSTR lpMenuID, 
  LPSTR lpItemID, 
  LPSTR lpItemText, 
  LPSTR lpMacro, 
  short int nPosition 
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
 
  /* Menu info. to store in menu info. list. */ 
  MENUINFO MenuInfo, MenuItemInfo; 
   
  BOOL bReturn; 
   
  /* Pointer to macro string. */ 
  char * MacroStringPtr; 
 
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
     
  /* Menubar does not even exist. */ 
  if( MenuSysPtr->hMenuBar == NULL )  
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
  /* Find the menu that the item will be added to. */ 
  if( ! GetMenuInfo( MenuSysPtr->hMenuList, lpMenuID, &MenuInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
 
  /* Verify that the new menu's ID string is unique. */ 
  if( GetMenuInfo( MenuSysPtr->hMenuList, lpItemID, &MenuItemInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUALREADYEXISTS, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
 
  /* Allocate memory for storage of macro string. */ 
  if( !GlobalAllocMem( hWnd, &(MenuItemInfo).hMacroString, strlen( lpMacro ) + sizeof(char) ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTCREATEMENU, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
   
  /* Copy macro string storage area. */ 
  MacroStringPtr = (char *) GlobalLock( MenuItemInfo.hMacroString ); 
  strcpy( MacroStringPtr, lpMacro ); 
  GlobalUnlock( MenuItemInfo.hMacroString ); 
 
  /* Init. the other menu item info. */ 
  MenuItemInfo.MenuID       = AddAtom( lpItemID );    
  MenuItemInfo.hMenu        = NULL;    
  MenuItemInfo.hParentMenu  = MenuInfo.hMenu;    
 
  /* Add the menu item to the menu. */ 
  if( ! InsertMenu( MenuInfo.hMenu, nPosition, MF_BYPOSITION | MF_ENABLED | MF_STRING, MenuItemInfo.MenuID, lpItemText) ) 
  { 
    /* Delete allocated info. */ 
    DeleteAtom( MenuItemInfo.MenuID ); 
    MyGlobalFree( MenuItemInfo.hMacroString );  
 
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTCREATEMENU, MB_ICONHAND | MB_OK ); 
 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Failure. */ 
    return( FALSE ); 
  } 
   
  /* Save the menu info. */ 
  bReturn = SaveMenuInfo( hWnd, &(MenuSysPtr)->hMenuList, (FPMENUINFO) &MenuItemInfo ); 
  if( bReturn == FALSE ) 
  { 
    /* Delete allocated info. */ 
    DeleteAtom( MenuItemInfo.MenuID ); 
    MyGlobalFree( MenuItemInfo.hMacroString );  
 
    /* Remove the new menu item. */ 
    DeleteMenu( MenuInfo.hMenu, nPosition, MF_BYPOSITION ); 
     
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Failure. */ 
    return( FALSE ); 
  } 
       
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
     
  /* Show changes. */ 
  DrawMenuBar( hWnd ); 
 
  /* Success. */ 
  return( TRUE ); 
} 
 
 
 
/********************************************************************* 
** 
**  Adds a separator to a menu.  
** 
**  Position is the position of the separator.  If position is -1, 
**  the separator is inserted as the last item. 
** 
**********************************************************************/ 
BOOL InsertMenuSeparator 
(  
  HWND hWnd,  
  LPSTR lpMenuID, 
  short int nPosition 
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
 
  /* Menu info. to store in menu info. list. */ 
  MENUINFO MenuInfo; 
   
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
     
  /* Menubar does not even exist. */ 
  if( MenuSysPtr->hMenuBar == NULL )  
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
  /* Find the menu that the item will be added to. */ 
  if( ! GetMenuInfo( MenuSysPtr->hMenuList, lpMenuID, &MenuInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
 
  /* Add the menu item to the menu. */ 
  if( ! InsertMenu( MenuInfo.hMenu, nPosition, MF_BYPOSITION | MF_SEPARATOR, 0, 0) ) 
  { 
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, CANTCREATEMENU, MB_ICONHAND | MB_OK ); 
 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Failure. */ 
    return( FALSE ); 
  } 
   
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
     
  /* Show changes. */ 
  DrawMenuBar( hWnd ); 
 
  /* Success. */ 
  return( TRUE ); 
} 
 
 
 
/********************************************************************* 
** 
**  Remove an item from a menu.   
** 
**  Unlike the real RemoveMenu(), it does not handle removing a menu 
**  item that is also popup menu.  
** 
**********************************************************************/ 
BOOL MyRemoveMenu 
(  
  HWND hWnd, 
  LPSTR lpItemID 
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
   
  MENUINFO MenuItemInfo;    
 
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
 
  /* Find the menu item's info. */ 
  if( !GetMenuInfo( MenuSysPtr->hMenuList, lpItemID, &MenuItemInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
  /* Remove the menu item. */ 
  RemoveMenu( MenuItemInfo.hParentMenu, MenuItemInfo.MenuID, MF_BYCOMMAND ); 
 
  /* Delete the menu item from the list. */ 
  DeleteMenuInfo( &(MenuSysPtr)->hMenuList, &MenuItemInfo ); 
   
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
 
  /* Show changes. */ 
  DrawMenuBar( hWnd ); 
   
  /* Success. */ 
  return( TRUE ); 
} 
 
 
/********************************************************************* 
** 
**  Remove all of the menus in the help system. 
** 
**********************************************************************/ 
void DeleteAllMenus( HWND hWnd ) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
 
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
  if( hMenuSys == 0 ) return; 
 
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
   
  /* If there's no menus. */ 
  if( MenuSysPtr->hMenuList == 0 ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
    return; 
  } 
 
  /* Free menu list. */ 
  FreeMenuList( &(MenuSysPtr)->hMenuList ); 
     
  /* Remove the bar. */ 
  DestroyMenu( MenuSysPtr->hMenuBar ); 
  MenuSysPtr->hMenuBar = NULL; 
     
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
} 
 
 
 
 
/********************************************************************* 
** 
**  Disable/Enable an item on a menu.   
** 
**********************************************************************/ 
BOOL MyEnableMenuItem 
(  
  HWND hWnd, 
  LPSTR lpItemID, 
  BOOL bEnabled 
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
   
  MENUINFO MenuItemInfo;    
 
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
 
  /* Find the menu item's info. */ 
  if( !GetMenuInfo( MenuSysPtr->hMenuList, lpItemID, &MenuItemInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
  /* Disable/Enable the menu item. */ 
  if( bEnabled ) 
  { 
    EnableMenuItem( MenuItemInfo.hParentMenu, MenuItemInfo.MenuID, MF_BYCOMMAND | MF_ENABLED ); 
  } 
  else 
  { 
    EnableMenuItem( MenuItemInfo.hParentMenu, MenuItemInfo.MenuID, MF_BYCOMMAND | MF_GRAYED ); 
  } 
 
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
   
  /* Show changes. */ 
  DrawMenuBar( hWnd ); 
 
  /* Success. */ 
  return( TRUE ); 
} 
 
 
 
/********************************************************************* 
** 
**  Checks/Unchecks an item on a menu.   
** 
**********************************************************************/ 
BOOL MyCheckMenuItem 
(  
  HWND hWnd, 
  LPSTR lpItemID, 
  BOOL bChecked 
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
   
  MENUINFO MenuItemInfo;    
 
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
 
  /* Find the menu item's info. */ 
  if( !GetMenuInfo( MenuSysPtr->hMenuList, lpItemID, &MenuItemInfo ) ) 
  { 
    /* Unlock menu sys. data. */ 
    GlobalUnlock( hMenuSys ); 
     
    /* Error. */  
    MsgBox( GetLibInst(), hWnd, IDS_ERRORTITLE, MENUDOESNOTEXIST, MB_ICONHAND | MB_OK ); 
 
    /* Failure. */ 
    return( FALSE ); 
  } 
 
  /* Check/Uncheck the menu item. */ 
  if( bChecked ) 
  { 
    CheckMenuItem( MenuItemInfo.hParentMenu, MenuItemInfo.MenuID, MF_BYCOMMAND | MF_CHECKED ); 
  } 
  else 
  { 
    CheckMenuItem( MenuItemInfo.hParentMenu, MenuItemInfo.MenuID, MF_BYCOMMAND | MF_UNCHECKED ); 
  } 
 
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
   
  /* Show changes. */ 
  DrawMenuBar( hWnd ); 
 
  /* Success. */ 
  return( TRUE ); 
} 
 
 
/********************************************************************* 
** 
**  Change the macro of a button in the button bar given its ID. 
** 
**********************************************************************/ 
BOOL ChangeItemBinding 
(  
  HWND hWnd, 
  LPSTR lpItemID, 
  LPSTR lpMacro  
) 
{ 
  HMENUSYS hMenuSys; 
  FPMENUSYS MenuSysPtr; 
 
  CHANGEBINDINGFUNCDATA FuncData; 
   
   
  /* Get the menu sys. data */ 
  hMenuSys = (HMENUSYS) WndData( hWnd, WDM_GETMENUSYS, 0, NULL ); 
   
  /* Lock menu sys. data. */ 
  MenuSysPtr = ( FPMENUSYS ) GlobalLock( hMenuSys ); 
 
  /* Initialize the data. */ 
  FuncData.bSuccess = FALSE; 
  FuncData.MenuID = FindAtom( lpItemID ); 
  FuncData.MacroStringPtr = lpMacro; 
  FuncData.hErrorWnd = hWnd; 
   
  /* No atom regisitered means no button exists. */ 
  if( FuncData.MenuID == 0 ) return FALSE; 
   
  /* Position each button. */ 
  EnumMenuInfo( MenuSysPtr->hMenuList, (MENUINFOENUMPROC) ChangeItemBindingProc, (LPARAM) (FPCHANGEBINDINGFUNCDATA) &FuncData ); 
 
  /* Unlock menu sys. data. */ 
  GlobalUnlock( hMenuSys ); 
 
  /* Successful? */ 
  return( FuncData.bSuccess ); 
} 
 
 
 
/*********************************************************************************** 
** 
**                              Private Functions 
** 
************************************************************************************/ 
 
 
/********************************************************************* 
** 
**  Callback function for the ChangeItemBinding() function. 
**  Finds the menu with the ID and changes its macro string. 
** 
**********************************************************************/ 
static BOOL CALLBACK ChangeItemBindingProc( FPMENUINFO fpMenuInfo, LPARAM lParam ) 
{ 
  FPCHANGEBINDINGFUNCDATA FuncData ; 
   
  /* Pointer to macro string. */ 
  HGLOBAL      hMacroString; 
  char * MacroStringPtr; 
   
 
  /* Get lParam data. */ 
  FuncData = (FPCHANGEBINDINGFUNCDATA) lParam; 
 
  /* Found correct button. */ 
  if( FuncData->MenuID == fpMenuInfo->MenuID ) 
  { 
    /* Allocate memory for storage of macro string. */ 
    if( !GlobalAllocMem( FuncData->hErrorWnd, &hMacroString,  
                        strlen( FuncData->MacroStringPtr ) + sizeof(char) ) ) 
    { 
      /* Stop enumerating. */ 
      return( FALSE ); 
    } 
     
    /* Copy macro string storage area. */ 
    MacroStringPtr = (char *) GlobalLock( hMacroString ); 
    strcpy( MacroStringPtr, FuncData->MacroStringPtr ); 
    GlobalUnlock( hMacroString ); 
 
    /* Free the current macro string. */ 
    MyGlobalFree( fpMenuInfo->hMacroString );  
 
    /* Assign new macro string. */ 
    fpMenuInfo->hMacroString = hMacroString; 
     
    /* Successful. */ 
    FuncData->bSuccess = TRUE; 
     
    /* Stop enumerating. */ 
    return FALSE; 
  } 
 
  /* Get next button's info. */ 
  return TRUE; 
} 
 
 
/********************************************************************* 
** 
**  Gets the menu info for a menu entry in the menu list. 
** 
**********************************************************************/ 
BOOL GetMenuInfo( HMENULIST hMenuList, LPSTR lpMenuID, FPMENUINFO MenuInfoPtr ) 
{ 
  GETMENUINFOFUNCDATA FuncData; 
   
  /* No list. */ 
  if( hMenuList == 0 ) return( FALSE ); 
   
  /* Initialize the data. */ 
  FuncData.bFound      = FALSE; 
  FuncData.MenuID      = FindAtom( lpMenuID ); 
  FuncData.MenuInfoPtr = MenuInfoPtr; 
 
  /* No atom regisitered means no button exists. */ 
  if( FuncData.MenuID == 0 ) return( FALSE ); 
   
  /* Find the menu entry's info. */ 
  EnumMenuInfo( hMenuList, (MENUINFOENUMPROC) FindMenuInfo, (LPARAM) (FPGETWINDOWFUNCDATA) &FuncData ); 
 
  /* Return button window found. */ 
  return( FuncData.bFound ); 
} 
 
 
/********************************************************************* 
** 
**  Callback function for the GetMenuInfo() function. 
** 
**  Finds the menu entry with the given ID and saves its info to the 
**  buffer. 
** 
**********************************************************************/ 
static BOOL CALLBACK FindMenuInfo( FPMENUINFO MenuInfoPtr, LPARAM lParam ) 
{ 
  FPGETWINDOWFUNCDATA FuncData; 
   
  /* Get lParam data. */ 
  FuncData = (FPGETWINDOWFUNCDATA) lParam; 
 
  /* Found correct button. */ 
  if( FuncData->MenuID == MenuInfoPtr->MenuID ) 
  { 
    /* Save button's window handle. */ 
    *(FuncData->MenuInfoPtr) = *MenuInfoPtr; 
 
    /* Found it! */ 
    FuncData->bFound = TRUE; 
 
    /* Stop enumerating. */ 
    return FALSE; 
  } 
 
  /* Get next button's info. */ 
  return TRUE; 
} 
 
 
/********************************************************************* 
** 
**  Callback function when the menu bar is notified that an menu  
*   is pressed. Runs the macro associated with the pressed menu 
** 
**********************************************************************/ 
static BOOL CALLBACK MenuSelectedProc( FPMENUINFO fpMenuInfo, LPARAM lParam ) 
{ 
  char * MacroStringPtr; 
  char szMacro[MAX_MACRO_STRING]; 
  FPMENUSELFUNCDATA FuncDataPtr; 
 
  /* Get key pressed data. */ 
  FuncDataPtr = ( FPMENUSELFUNCDATA ) lParam; 
   
  /* If this is the correct menu */ 
  if( FuncDataPtr->MenuID == fpMenuInfo->MenuID ) 
  { 
    /* Copy the macro string. */ 
    MacroStringPtr = (char *) GlobalLock( fpMenuInfo->hMacroString ); 
    strcpy( szMacro, MacroStringPtr ); 
    GlobalUnlock( fpMenuInfo->hMacroString ); 
   
    /* Run the macro. */ 
    RunHelpMacro( FuncDataPtr->hExecWnd, FuncDataPtr->hDataWnd, szMacro ); 
 
    /* Processed key input. */ 
    FuncDataPtr->bProcessed = TRUE; 
     
    /* Found it - stop enumerating. */ 
    return FALSE; 
  } 
 
  /* Get next menu's info. */ 
  return TRUE; 
} 
 
 
 
/*************************************************************************************** 
** 
** 
**                              Menu list Management Functions 
** 
** 
***************************************************************************************/ 
 
 
/************************************* 
* 
*  Add info for an menu to the list. 
*                   
**************************************/ 
static BOOL SaveMenuInfo( HWND hErrorWnd, HMENULIST * hMenuList, FPMENUINFO fpMenuInfo ) 
{ 
  HMENUINFO hNewMenuInfo; 
 
   
  /* Create new MENUINFO structure. */ 
  hNewMenuInfo = NewMenuInfo( hErrorWnd, fpMenuInfo ); 
  if( hNewMenuInfo == 0 ) return FALSE;  
   
  /* 
  ** Insert the MENUINFO structure into the menu list. 
  */ 
  InsertMenuInfo( hMenuList, hNewMenuInfo ); 
   
  /* Return success. */ 
  return TRUE; 
} 
 
 
 
/************************************* 
* 
*  Create a new menu info. structure. 
*                   
**************************************/ 
static HMENUINFO NewMenuInfo( HWND hErrorWnd, FPMENUINFO fpMenuInfo ) 
{ 
  HMENUINFO hNewMenuInfo; 
  FPMENUINFO fpNewMenuInfo; 
 
   
  /* Allocate the new menu info. */ 
  if( ! GlobalAllocMem( hErrorWnd, &hNewMenuInfo, sizeof(MENUINFO) ) ) return NULL; 
   
  /* Lock it. */ 
  fpNewMenuInfo = (FPMENUINFO) GlobalLock( hNewMenuInfo ) ; 
 
  /* Initialize general elements in the structure. */ 
  fpNewMenuInfo->MenuID       = fpMenuInfo->MenuID; 
  fpNewMenuInfo->hMenu        = fpMenuInfo->hMenu; 
  fpNewMenuInfo->hParentMenu  = fpMenuInfo->hParentMenu; 
  fpNewMenuInfo->hMacroString = fpMenuInfo->hMacroString; 
  fpNewMenuInfo->Next         = 0; 
 
  /* Unlock it. */ 
  GlobalUnlock( hNewMenuInfo ) ; 
 
  /* Return it. */ 
  return hNewMenuInfo; 
} 
 
 
/************************************* 
* 
*  Free an menu info. structure. 
*                   
**************************************/ 
static void FreeMenuInfo( HMENUINFO hMenuInfo ) 
{ 
  FPMENUINFO fpMenuInfo; 
   
  /* Lock it. */ 
  fpMenuInfo = (FPMENUINFO) GlobalLock( hMenuInfo ) ; 
 
  /* Free allocated macro string. */ 
  if( fpMenuInfo->hMacroString != 0 ) 
  { 
    MyGlobalFree( fpMenuInfo->hMacroString );  
  } 
 
  /* Delete the menu's ID atom. */ 
  DeleteAtom( fpMenuInfo->MenuID );  
 
  /* If this is a popup menu, destroy it. */ 
  if( fpMenuInfo->hMenu != NULL ) 
  { 
    DestroyMenu( fpMenuInfo->hMenu ); 
  } 
   
  /* Free it. */ 
  GlobalUnlock( hMenuInfo ) ; 
  MyGlobalFree( hMenuInfo ) ; 
} 
 
 
 
/************************************* 
* 
*  Insert a new menu info. structure 
*  at the top of the menu info. list. 
*                   
**************************************/ 
static void InsertMenuInfo( HMENULIST * hMenuList, HMENUINFO hNewMenuInfo ) 
{ 
  FPMENUINFO fpNew; 
   
  /* Already existing nodes. */ 
  if( *hMenuList != 0 )  
  { 
    /* Lock new node. */ 
    fpNew = (FPMENUINFO) GlobalLock( hNewMenuInfo ) ; 
     
    /* Next node is the old top node. */ 
    fpNew->Next = *hMenuList; 
 
    /* Unlock new node. */ 
    GlobalUnlock( hNewMenuInfo ) ; 
  } 
 
  /* New node is the top node. */ 
  *hMenuList = hNewMenuInfo; 
} 
 
 
 
/************************************* 
* 
*  Delete/Free menu info. list.  
*                   
**************************************/ 
static void FreeMenuList( HMENULIST * hMenuList ) 
{ 
  FPMENUINFO fpMenuInfo; 
  HMENUINFO  hTmpMenuInfo; 
 
  while( *hMenuList != 0 ) 
  { 
    /* Lock current node. */ 
    fpMenuInfo = (FPMENUINFO) GlobalLock( *hMenuList ) ; 
   
    /* Next node is to be new top node. */ 
    hTmpMenuInfo = fpMenuInfo->Next;  
     
    /* Unlock top handle. */ 
    GlobalUnlock( *hMenuList ); 
         
    /* Free top. */ 
    FreeMenuInfo( *hMenuList );  
 
    /* Assign new top. */ 
    *hMenuList = hTmpMenuInfo;  
  } 
} 
 
 
 
/************************************* 
* 
*  Get the next menu info. structure 
*  after the given hMenuInfo. 
*                   
**************************************/ 
static HMENUINFO GetNextMenuInfo( HMENUINFO hMenuInfo ) 
{ 
  HMENUINFO hNextMenuInfo; 
  FPMENUINFO fpMenuInfo; 
   
  /* Handle bad. */ 
  if( hMenuInfo == 0 ) return 0; 
 
  /* Lock it. */ 
  fpMenuInfo = (FPMENUINFO) GlobalLock( hMenuInfo ) ; 
   
  /* Point new node to existing top node. */ 
  hNextMenuInfo = fpMenuInfo->Next; 
 
  /* Unlock it. */ 
  GlobalUnlock( hMenuInfo ) ; 
 
  /* Return next menu info's handle. */ 
  return hNextMenuInfo; 
} 
 
 
 
/************************************* 
* 
*  Enumerates all MENUINFO structures 
*  contained in the menu info. list. 
*                   
**************************************/ 
static void EnumMenuInfo( HMENULIST hMenuList, MENUINFOENUMPROC MenuInfoEnumProc, LPARAM lParam ) 
{ 
  FPMENUINFO fpMenuInfo; 
  HMENUINFO hMenuInfo; 
  BOOL bReturn; 
   
   
  /* Get first menu info's handle. */ 
  hMenuInfo = hMenuList; 
   
  while( hMenuInfo != 0 ) 
  { 
    /* Lock it. */ 
    fpMenuInfo = (FPMENUINFO) GlobalLock( hMenuInfo ) ; 
   
    /* Call callback function. */ 
    bReturn = (*MenuInfoEnumProc)( fpMenuInfo, lParam ); 
     
    /* Stop enumerating. */ 
    if( bReturn == FALSE ) 
    { 
      /* Unlock it. */ 
      GlobalUnlock( hMenuInfo ); 
 
      /* Stop enumerating. */ 
      return; 
    } 
     
    /* Unlock it. */ 
    GlobalUnlock( hMenuInfo ); 
 
    /* Get the next in the list. */ 
    hMenuInfo = GetNextMenuInfo( hMenuInfo ); 
  } 
} 
 
 
 
/************************************* 
* 
*  Remove and free an menu info. 
*  from the menu info. list based on 
*  its wMenuID value. 
*                   
**************************************/ 
static BOOL DeleteMenuInfo( HMENULIST * hMenuList, FPMENUINFO fpDelMenuInfo ) 
{ 
  FPMENUINFO fpMenuInfo, fpTmpMenuInfo; 
  HMENUINFO hMenuInfo, hTmpMenuInfo; 
   
 
  /* Existing first node. */ 
  if( *hMenuList == 0 ) return FALSE; 
 
  /* Lock top handle. */ 
  fpMenuInfo = (FPMENUINFO) GlobalLock( *hMenuList ) ; 
   
  /* If deleting top node. */ 
  if( fpMenuInfo->MenuID == fpDelMenuInfo->MenuID ) 
  { 
    /* Next node is to be new top node. */ 
    hTmpMenuInfo = fpMenuInfo->Next;  
 
    /* Unlock top handle. */ 
    GlobalUnlock( *hMenuList ); 
     
    /* Free top. */ 
    FreeMenuInfo( *hMenuList );  
   
    /* Assign new top. */ 
    *hMenuList = hTmpMenuInfo; 
 
    /* Success. */ 
    return TRUE; 
  } 
 
  /* Unlock top handle. */ 
  GlobalUnlock( *hMenuList ); 
     
  /* Find correct node and remove. */ 
  hTmpMenuInfo = *hMenuList; 
  hMenuInfo = GetNextMenuInfo( *hMenuList ); 
 
  while( hMenuInfo != 0 ) 
  { 
    /* Lock current node. */ 
    fpMenuInfo = (FPMENUINFO) GlobalLock( hMenuInfo ) ; 
   
    /* If deleting top node. */ 
    if( fpMenuInfo->MenuID == fpDelMenuInfo->MenuID ) 
    { 
      /* Lock previous node. */ 
      fpTmpMenuInfo = (FPMENUINFO) GlobalLock( hTmpMenuInfo ) ; 
 
      /* Previous node's "next node" is deleted node's "next node". */ 
      fpTmpMenuInfo->Next = fpMenuInfo->Next;  
   
      /* Unlock previous node. */ 
      GlobalUnlock( hTmpMenuInfo ); 
 
      /* Unlock current node. */ 
      GlobalUnlock( hMenuInfo ); 
       
      /* Free top. */ 
      FreeMenuInfo( hMenuInfo );  
   
      /* Success. */ 
      return TRUE; 
    } 
     
    /* Unlock it. */ 
    GlobalUnlock( hMenuInfo ) ; 
 
    /* Get next node. */ 
    hTmpMenuInfo = hMenuInfo; 
    hMenuInfo = GetNextMenuInfo( hMenuInfo ); 
  } 
 
  /* Did not find menu. */ 
  return FALSE; 
}