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


/* 
  
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. 
 
*/ 
 
/************************************************************************* 
* 
* SECWND.C 
* Secondary help window routines.      
* 
* Author: Paul E. Kissel 
* 
**************************************************************************/ 
 
 
/*********************************** 
** 
**  System Includes 
** 
***********************************/ 
#include <string.h> 
 
 
/************************************* 
* 
*  App. Includes 
* 
**************************************/ 
#include "secwnd.h" 
#include "msgbox.h" 
#include "winmem.h" 
#include "hlpfile.h" 
#include "wnddata.h" 
#include "general.h" 
#include "globals.h" 
#include "twhlprc.h" 
#include "wndpos.h" 
#include "hlpmacro.h" 
 
 
/************************************* 
* 
*  Private Defines 
* 
**************************************/ 
 
/* 
** Secondary Window List Structure 
*/ 
typedef struct tagSECWNDINFO 
{ 
  WORD wSecWndNum; 
  char szSecWndName[MAX_SEC_NAME]; 
  char szHelpFilePath[MAX_HLPPATH]; 
  HWND hSecWnd; 
  HSECWNDINFO Next; 
} 
SECWNDINFO; 
typedef SECWNDINFO * FPSECWNDINFO; 
 
/* Enum. secondary window info. call-back function */ 
typedef BOOL ( CALLBACK * WNDINFOENUMPROC )( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
 
 
/* Function data for the IsSecWndHandle() function. */ 
typedef struct tagISSECWNDFUNCDATA 
{ 
  BOOL bFound;                    /* Did we find the search window? */ 
  HWND hSearchWnd;                /* The window we're looking for. */ 
} 
ISSECWNDFUNCDATA; 
typedef ISSECWNDFUNCDATA * ISSECWNDFUNCDATAPTR; 
 
 
/* Function data for the GetSecWndInfo() function. */ 
typedef struct tagGETSECWNDNAMEFUNCDATA 
{ 
  BOOL bFound;                      /* Did we find the search window? */ 
  HWND hSearchWnd;                  /* The sec. window we're looking for. */ 
  char SecWndName[MAX_SEC_NAME];    /* Buffer to store the name info. in. */ 
} 
GETSECWNDNAMEFUNCDATA; 
typedef GETSECWNDNAMEFUNCDATA * GETSECWNDNAMEFUNCDATAPTR; 
 
 
 
/************************************* 
* 
*  Private Function Prototypes 
* 
**************************************/ 
 
static BOOL CALLBACK SetAllSecWndOnTopProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
 
static BOOL CALLBACK SendCloseAllSecWndProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
static BOOL CALLBACK PostCloseAllSecWndProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
static HWND GetSecWndNumHandle 
(  
  HWND hDataWnd, 
  WORD wSecWndNum, 
  char * szHelpFilePath  
); 
static BOOL CALLBACK GetSecWndNumHandleProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
static HWND GetSecWndNameHandle 
(  
  HSECWNDINFO hFirstSecWndInfo, 
  char * szSecWndName, 
  char * szHelpFilePath  
); 
static BOOL CALLBACK GetSecWndNameHandleProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
static BOOL InsertSecWnd 
(  
  HWND hDataWnd, 
  HWND hErrorWnd,  
  WORD wSecWndNum, 
  HWND hSecWnd, 
  char * szHelpFilePath, 
  char * szSecWndName 
); 
static BOOL RemoveSecWndInfo 
(  
  HSECWNDINFO * hFirstSecWndInfo, 
  HWND hSecWnd 
); 
static void RemoveAllSecWndInfo( HSECWNDINFO hFirstSecWndInfo ); 
static HSECWNDINFO GetNextWndInfo( HSECWNDINFO hSecWndInfo ); 
static void EnumWndInfo 
(  
  WNDINFOENUMPROC WndInfoEnumProc,  
  HSECWNDINFO hFirstSecWndInfo,  
  LPARAM lParam  
); 
 
static BOOL CALLBACK SecWndExistsProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
 
static BOOL CALLBACK IsSecWndHandleProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
 
static BOOL CALLBACK GetSecWndNameProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ); 
 
 
/***********************************  Shared Functions  *********************************/ 
 
 
/**************************************************** 
* 
*  GetSecWndNameFromString() 
* 
*  If the given string contains a sec. wnd. name, 
*  the name is separated from the string and stored in 
*  the given name buffer.  The original string is 
*  terminated before the window name. 
* 
*  Returns: 
* 
*     TRUE  - Found secondary window info. 
*     FALSE - Did not found secondary window info.. 
* 
*****************************************************/ 
BOOL GetSecWndNameFromString 
( 
  char * szString, 
  char * szSecWndName 
) 
{ 
  short int nLength; 
  char * CharPtr; 
    
  /* Is there is no window name specified in the string. */ 
  CharPtr = strchr( szString, WINDOW_SEP_TOKEN_CHAR ); 
 
  /* Can't find token character. */ 
  if( CharPtr == NULL ) 
  { 
    /* No name in string. */ 
    return( FALSE ); 
  } 
 
  /* Skip blanks after token char. */ 
  CharPtr = CharPtr + 1; 
  while( *CharPtr == ' ' ) 
  { 
    CharPtr = CharPtr + 1; 
  } 
 
  /* Copy name string to name buffer. */ 
  strcpy( szSecWndName, CharPtr ); 
 
  /* Trim off spaces at the end of the window name. */ 
  CharPtr = szSecWndName; 
  nLength = strlen( szSecWndName ); 
  CharPtr = CharPtr + nLength - 1; 
  while( *CharPtr == ' ' ) 
  { 
    CharPtr = CharPtr - 1; 
  } 
  CharPtr = CharPtr + 1; 
  *CharPtr = '\0'; 
   
  /* Goto where window name specified in the string. */ 
  CharPtr = strchr( szString, WINDOW_SEP_TOKEN_CHAR ); 
 
  /* Trim off spaces at the end of the string. */ 
  CharPtr = CharPtr - 1; 
  while( *CharPtr == ' ' ) 
  { 
    CharPtr = CharPtr - 1; 
  } 
  CharPtr = CharPtr + 1; 
  *CharPtr = '\0'; 
   
  /* Was name in string. */ 
  return( TRUE ); 
}         
 
 
 
/**************************************************** 
* 
*  IsSecWindowName() 
* 
*  Does the string contain a valid secondary 
*  window name? 
* 
*  Returns: 
* 
*     FALSE - Failure. 
*      TRUE - Success. 
* 
*****************************************************/ 
BOOL IsSecWindowName 
(  
  HWND hDataWnd,  
  HGLOBAL hHelpFileInfo,  
  char * szWndName  
) 
{ 
  WORD wSecWndNum; 
  char szCaption[MAX_SEC_CAPTION]; 
  WINDOWPLACEMENT WndPlace; 
  COLORREF ScrollColor; 
  COLORREF NonScrollColor; 
  BOOL bSecHlpOnTop; 
   
  BOOL bFound; 
   
 
  /*  
  ** Secondary window name is main window.  
  */  
  if( stricmp( szWndName, MAIN_WINDOW_NAME ) == 0 ) 
  { 
    return TRUE; 
  } 
 
  /* Get info. for secondary window. */ 
  bFound = GetSecWndNameFileData( hDataWnd, hHelpFileInfo, szWndName,  
                                  &wSecWndNum, szCaption, &WndPlace, &ScrollColor,  
                                  &NonScrollColor, &bSecHlpOnTop ); 
 
  /* Success/Failure. */ 
  return( bFound ); 
} 
 
 
/**************************************************** 
* 
*  ShowTopicSecWndNum() 
* 
*  Given the number of a secondary window, 
*  find its window name. 
* 
*  Returns: 
* 
*     FALSE - Failure. 
*      TRUE - Success. 
* 
*****************************************************/ 
BOOL GetWindowNumbersName 
(  
  HWND hDataWnd,  
  HGLOBAL hHelpFileInfo, 
  WORD wSecWndNum, 
  char * szSaveWndName  
) 
{ 
  char szWndName[MAX_SEC_NAME]; 
  char szCaption[MAX_SEC_CAPTION]; 
  WINDOWPLACEMENT WndPlace; 
  COLORREF ScrollColor; 
  COLORREF NonScrollColor; 
  BOOL bSecHlpOnTop; 
   
  BOOL bFound, bMainWnd; 
   
 
  /* Get info. for secondary window. */ 
  bFound = GetSecWndNumFileData( hDataWnd, hHelpFileInfo, wSecWndNum,  
                                 szWndName, szCaption, &WndPlace, &ScrollColor,  
                                 &NonScrollColor, &bSecHlpOnTop, &bMainWnd ); 
 
  /* If we did found info for this window. */ 
  if( bFound ) 
  { 
    /* Save name. */ 
    strcpy( szSaveWndName, szWndName ); 
     
    /* Success. */ 
    return( TRUE ); 
  } 
 
  /* Failure. */ 
  return( FALSE ); 
}  
 
 
 
/**************************************************** 
* 
*  ShowTopicSecWndName() 
* 
*  Given the name of a secondary window, 
*  find the correct secondary help window  
*  or create one if one doesn't exist. 
* 
*  Tell the window to show the specified topic. 
* 
*  Returns: 
* 
*     0 - Failure. 
*     HWND - Success. 
* 
*****************************************************/ 
void ShowTopicSecWndName 
( 
  HWND hDataWnd,  
  HTOPICDATA hNewTopicsData, 
  char * szWndName  
) 
{ 
  HWND hSecWnd, hTopicWnd; 
 
  FPTOPICDATA TopicDataPtr; 
 
  WORD wSecWndNum; 
  char szCaption[MAX_SEC_CAPTION]; 
  WINDOWPLACEMENT WndPlace; 
  COLORREF ScrollColor; 
  COLORREF NonScrollColor; 
 
  BOOL bSecHlpOnTop; 
  BOOL bHelpOnTopFlag; 
   
  NEWTOPICSTRUCT NewTopicStruct; 
   
  BOOL bFound; 
   
   
   
  /*  
  ** Secondary window is main window.  
  */  
  if( stricmp( szWndName, MAIN_WINDOW_NAME ) == 0 ) 
  { 
    /* Get the window handle for the main topic window. */ 
    hTopicWnd = (HWND) WndData( hDataWnd, WDM_GETMAINTOPICHWND, 0, NULL ); 
            
    /* Tell main topic window to show topic. */ 
    SendShowNewTopicMsg( hTopicWnd, hNewTopicsData, TRUE, FALSE, 0 ); 
 
    /* Set active window. */ 
    SetActiveWindow( hDataWnd ); 
 
    return; 
  } 
 
   
  /*  
  ** Secondary window is not main window.  
  */  
 
  /* Lock the topic data. */ 
  TopicDataPtr = (FPTOPICDATA) GlobalLock( hNewTopicsData ); 
 
  /* Get desired size and position for secondary window. */ 
  bFound = GetSecWndNameFileData( hDataWnd, TopicDataPtr->hHelpFileInfo, szWndName,  
                                  &wSecWndNum, szCaption, &WndPlace, &ScrollColor,  
                                  &NonScrollColor, &bSecHlpOnTop ); 
 
  /* If we did not find any info for this window. */ 
  if( !bFound ) 
  { 
    /* Release the buffer lock on the new topic's data. */ 
    UnlockTopicData( hDataWnd, hNewTopicsData ); 
 
    /* Unlock the topic data. */ 
    GlobalUnlock( hNewTopicsData ); 
    
    return; 
  } 
 
  /* Check to see if the secondary help window is already open. */ 
  hSecWnd = GetSecWndNumHandle( hDataWnd, wSecWndNum, TopicDataPtr->szHelpFile ); 
   
  /*  
  ** No existing secondary help window of that number.   
  ** Create a new secondary window. 
  */ 
  if( hSecWnd == 0 ) 
  { 
    /*  
    ** For now, there will only ever be one secondary window  
    ** created at any one time.  Therefore, there will only be 
    ** one window in the window list at a time. 
    ** 
    ** If we didn't find in the sec. window that we want 
    ** in the search above, we will close any sec. window 
    ** that is already open before opening the new sec. window. 
    ** Thats the current restriction imposed by Microsoft.  Only one 
    ** secondary window open at a time. 
    ** 
    ** I used a list concept right now so that if one day the 
    ** rules change and we CAN have more than one secondary  
    ** window open at a time, the code will have not have to change 
    ** except for this next line. 
    */ 
    CloseAllSecWnd( hDataWnd, FALSE ); 
 
    /* Create a help window. */ 
    hSecWnd = CreateWindow  
                ( 
                  (LPSTR) MAINSEC_CLASS, 
                  (LPSTR) szCaption, 
                  WS_OVERLAPPEDWINDOW, 
                  WndPlace.rcNormalPosition.left,  
                  WndPlace.rcNormalPosition.top,  
                  WndPlace.rcNormalPosition.right,  
                  WndPlace.rcNormalPosition.bottom, 
                  NULL,  
                  NULL,  
                  GetLibInst(),  
                  (void *) (HWND *) &hDataWnd 
                ); 
   
    if( !hSecWnd ) 
    { 
      /* Cannot create the help window. */  
      MsgBox( GetLibInst(), hDataWnd, IDS_ERRORTITLE, IDS_WINDOWCREATE, MB_ICONHAND | MB_OK ); 
    
      /* Unlock the topic data. */ 
      GlobalUnlock( hNewTopicsData ); 
    } 
   
    /*  
    ** Save secondary window #/HWND pair to window list.  
    */ 
    InsertSecWnd( hDataWnd, hDataWnd, wSecWndNum, hSecWnd,  
                  TopicDataPtr->szHelpFile, szWndName ); 
   
    /* Get general "On Top" flag value. */ 
    bHelpOnTopFlag = (BOOL) WndData( hDataWnd, WDM_GETHELPONTOP, 0, NULL ); 
         
    /* Should window be on top? */ 
    if( bSecHlpOnTop == TRUE || bHelpOnTopFlag == TRUE ) 
    { 
      SetWindowPos( hSecWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); 
    } 
 
    /* Show window. */ 
    ShowWindow ( hSecWnd, WndPlace.showCmd ) ; 
    UpdateWindow ( hSecWnd ) ; 
  } 
 
  /* Existing secondary help window. */ 
  else 
  { 
    /* If its minimized, restore it. */ 
    if( IsIconic( hSecWnd ) ) 
    { 
      ShowWindow( hSecWnd, SW_RESTORE ); 
    } 
  } 
     
  /* Unlock the topic data. */ 
  GlobalUnlock( hNewTopicsData ); 
      
 
  /*  
  ** Build message data structure.  
  */ 
  NewTopicStruct.hNewTopicsData  = hNewTopicsData; 
  NewTopicStruct.bUpdateBackList = FALSE; 
  NewTopicStruct.wVertPos        = 0; 
  NewTopicStruct.ScrollColor     = ScrollColor; 
  NewTopicStruct.NonScrollColor  = NonScrollColor; 
   
  /* Send the message. */ 
  SendMessage( hSecWnd, PRIVMSG_SHOWNEWTOPIC, 0, (LPARAM)(FPNEWTOPICSTRUCT) &NewTopicStruct ); 
   
  /* Set active window. */ 
  SetActiveWindow( hSecWnd ); 
}  
 
 
/**************************************************** 
* 
*  ShowTopicSecWndNum() 
* 
*  Given the number of a secondary window, 
*  find the correct secondary help window  
*  or create one if one doesn't exist. 
* 
*  Tell the window to show the specified topic. 
* 
*  Returns: 
* 
*     0 - Failure. 
*     HWND - Success. 
* 
*****************************************************/ 
void ShowTopicSecWndNum 
( 
  HWND hDataWnd,  
  HTOPICDATA hNewTopicsData, 
  WORD wSecWndNum  
) 
{ 
  HWND hSecWnd, hTopicWnd; 
 
  FPTOPICDATA TopicDataPtr; 
 
  char szWndName[MAX_SEC_NAME]; 
  char szCaption[MAX_SEC_CAPTION]; 
  WINDOWPLACEMENT WndPlace; 
  COLORREF ScrollColor; 
  COLORREF NonScrollColor; 
 
  BOOL bSecHlpOnTop; 
  BOOL bHelpOnTopFlag; 
   
  NEWTOPICSTRUCT NewTopicStruct; 
   
  BOOL bFound, 
       bMainWnd; 
   
   
  /* Lock the topic data. */ 
  TopicDataPtr = (FPTOPICDATA) GlobalLock( hNewTopicsData ); 
 
  /* Get desired size and position for secondary window. */ 
  bFound = GetSecWndNumFileData( hDataWnd, TopicDataPtr->hHelpFileInfo, wSecWndNum,  
                                 szWndName, szCaption, &WndPlace, &ScrollColor,  
                                 &NonScrollColor, &bSecHlpOnTop, &bMainWnd ); 
 
  /* If we did not find any info for this window. */ 
  if( !bFound ) 
  { 
    /* Release the buffer lock on the new topic's data. */ 
    UnlockTopicData( hDataWnd, hNewTopicsData ); 
 
    /* Unlock the topic data. */ 
    GlobalUnlock( hNewTopicsData ); 
    
    return; 
  } 
 
  /* Is the secondary window is not the main help window. */ 
  if( !bMainWnd ) 
  { 
    /* Check to see if the secondary help window is already open. */ 
    hSecWnd = GetSecWndNumHandle( hDataWnd, wSecWndNum, TopicDataPtr->szHelpFile ); 
   
    /*  
    ** No existing secondary help window of that number.   
    ** Create a new secondary window. 
    */ 
    if( hSecWnd == 0 ) 
    { 
      /*  
      ** For now, there will only ever be one secondary window  
      ** created at any one time.  Therefore, there will only be 
      ** one window in the window list at a time. 
      ** 
      ** If we didn't find in the sec. window that we want 
      ** in the search above, we will close any sec. window 
      ** that is already open before opening the new sec. window. 
      ** Thats the current restriction imposed by Microsoft.  Only one 
      ** secondary window open at a time. 
      ** 
      ** I used a list concept right now so that if one day the 
      ** rules change and we CAN have more than one secondary  
      ** window open at a time, the code will have not have to change 
      ** except for this next line. 
      */ 
      CloseAllSecWnd( hDataWnd, FALSE ); 
 
      /* Create a help window. */ 
      hSecWnd = CreateWindow  
                  ( 
                    (LPSTR) MAINSEC_CLASS, 
                    (LPSTR) szCaption, 
                    WS_OVERLAPPEDWINDOW, 
                    WndPlace.rcNormalPosition.left,  
                    WndPlace.rcNormalPosition.top,  
                    WndPlace.rcNormalPosition.right,  
                    WndPlace.rcNormalPosition.bottom, 
                    NULL,  
                    NULL,  
                    GetLibInst(),  
                    (void *) (HWND *) &hDataWnd 
                  ); 
   
      if( !hSecWnd ) 
      { 
        /* Cannot create the help window. */  
        MsgBox( GetLibInst(), hDataWnd, IDS_ERRORTITLE, IDS_WINDOWCREATE, MB_ICONHAND | MB_OK ); 
    
        /* Unlock the topic data. */ 
        GlobalUnlock( hNewTopicsData ); 
      } 
   
      /*  
      ** Save secondary window #/HWND pair to window list.  
      */ 
      InsertSecWnd( hDataWnd, hDataWnd, wSecWndNum, hSecWnd,  
                    TopicDataPtr->szHelpFile, szWndName ); 
   
       
      /* Get general "On Top" flag value. */ 
      bHelpOnTopFlag = (BOOL) WndData( hDataWnd, WDM_GETHELPONTOP, 0, NULL ); 
       
      /* Should window be on top? */ 
      if( bSecHlpOnTop == TRUE || bHelpOnTopFlag == TRUE ) 
      { 
        SetWindowPos( hSecWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); 
      } 
 
      /* Show window. */ 
      ShowWindow ( hSecWnd, WndPlace.showCmd ) ; 
      UpdateWindow ( hSecWnd ) ; 
 
    } 
 
    /* Existing secondary help window. */ 
    else 
    { 
      /* If its minimized, restore it. */ 
      if( IsIconic( hSecWnd ) ) 
      { 
        ShowWindow( hSecWnd, SW_RESTORE ); 
      } 
    } 
     
    /* Unlock the topic data. */ 
    GlobalUnlock( hNewTopicsData ); 
      
    /*  
    ** Build message data structure.  
    */ 
    NewTopicStruct.hNewTopicsData  = hNewTopicsData; 
    NewTopicStruct.bUpdateBackList = FALSE; 
    NewTopicStruct.wVertPos        = 0; 
    NewTopicStruct.ScrollColor     = ScrollColor; 
    NewTopicStruct.NonScrollColor  = NonScrollColor; 
   
    /* Send the message. */ 
    SendMessage( hSecWnd, PRIVMSG_SHOWNEWTOPIC, 0, (LPARAM)(FPNEWTOPICSTRUCT) &NewTopicStruct ); 
   
    /* Set active window. */ 
    SetActiveWindow( hSecWnd ); 
  } 
   
  /* Secondary window is main window. */  
  else 
  { 
    /* Unlock the topic data. */ 
    GlobalUnlock( hNewTopicsData ); 
      
    /* Is hidden, make window visble. */ 
    if( !IsWindowVisible( hDataWnd ) ) 
    { 
      ShowWindow( hDataWnd, SW_SHOW ); 
    } 
     
    /* If its minimized, restore it. */ 
    if( IsIconic( hDataWnd ) ) 
    { 
      ShowWindow( hDataWnd, SW_RESTORE ); 
    } 
 
    /* Get the window handle for the main topic window. */ 
    hTopicWnd = (HWND) WndData( hDataWnd, WDM_GETMAINTOPICHWND, 0, NULL ); 
            
    /* Tell main topic window to show topic. */ 
    SendShowNewTopicMsg( hTopicWnd, hNewTopicsData, TRUE, FALSE, 0 ); 
 
    /* Set active window. */ 
    SetActiveWindow( hDataWnd ); 
  } 
}  
 
 
/**************************************************** 
* 
*  ProcessMainWndAttrib() 
* 
*  If there is window info. for the 
*  main window, we position the main window and 
*  retrieve the colors and on-top data.  
* 
*  Tell the window to show the specified topic. 
* 
*  Returns: 
* 
*     FALSE - No secondary info. for main window. 
*      TRUE - Secondary info. for main window. 
* 
*****************************************************/ 
BOOL ProcessMainWndAttrib 
( 
  HWND hMainWnd,  
  HTOPICDATA hNewTopicsData, 
  COLORREF * ScrollColor, 
  COLORREF * NonScrollColor 
) 
{ 
  FPTOPICDATA TopicDataPtr; 
 
  BOOL bUseSecWndCaption; 
  char szCaption[MAX_SEC_CAPTION]; 
  WINDOWPLACEMENT WndPlace; 
 
  BOOL bSecHlpOnTop; 
  BOOL bHelpOnTopFlag; 
   
  BOOL bFoundEntry; 
   
  
  /* Lock the topic data. */ 
  TopicDataPtr = (FPTOPICDATA) GlobalLock( hNewTopicsData ); 
 
  /* Get desired size and position for secondary window. */ 
  bFoundEntry = GetMainSecWndFileData( hMainWnd, TopicDataPtr->hHelpFileInfo, &bUseSecWndCaption, 
                                       szCaption, &WndPlace, ScrollColor, NonScrollColor, 
                                       &bSecHlpOnTop ); 
  /* Unlock the topic data. */ 
  GlobalUnlock( hNewTopicsData ); 
 
  /* No secondary window data for the main window. */ 
  if( bFoundEntry == FALSE ) return( FALSE ); 
 
  /* Set the window's caption. */ 
  if( bUseSecWndCaption ) 
  { 
    /* Set window's caption. */ 
    SetWindowText( hMainWnd, (LPCSTR) szCaption ); 
  } 
  else 
  { 
    /* Set title from .HLP file TITLE= field. */ 
    SetMainWindowTitle( hMainWnd, hNewTopicsData ); 
  } 
 
  /* If window should be maximized. */ 
  if( WndPlace.showCmd == SW_SHOWMAXIMIZED ) 
  { 
      ShowWindow( hMainWnd, SW_SHOWMAXIMIZED ); 
      UpdateWindow ( hMainWnd ) ; 
  } 
  else 
  {  
    /* If we have position and size info. */ 
    if( WndPlace.rcNormalPosition.left != CW_USEDEFAULT && 
        WndPlace.rcNormalPosition.top != CW_USEDEFAULT && 
        WndPlace.rcNormalPosition.right != CW_USEDEFAULT && 
        WndPlace.rcNormalPosition.bottom != CW_USEDEFAULT ) 
    { 
      /* Move and size the window. */ 
      SetWindowPos( hMainWnd, NULL,  
                    WndPlace.rcNormalPosition.left,  
                    WndPlace.rcNormalPosition.top,  
                    WndPlace.rcNormalPosition.right,  
                    WndPlace.rcNormalPosition.bottom, 
                    SWP_NOZORDER ); 
      UpdateWindow ( hMainWnd ) ; 
    } 
  } 
   
  /* Get general "On Top" flag value. */ 
  bHelpOnTopFlag = (BOOL) WndData( hMainWnd, WDM_GETHELPONTOP, 0, NULL ); 
       
  /* Should window be on top? */ 
  if( bSecHlpOnTop == TRUE || bHelpOnTopFlag == TRUE ) 
  { 
    /* Execute the HelpOnTop() macro for the main window. */ 
    RunHelpMacro( hMainWnd, hMainWnd, "HelpOnTop()" ); 
  } 
 
  /* Found secondary window info. */ 
  return( TRUE );   
}  
 
 
 
/**************************************************** 
* 
*  Sets the size and position of either the main 
*  window or a secondary window. 
* 
*  Returns:  None. 
* 
*****************************************************/ 
void PositionWindow 
( 
  HWND hMainWnd, 
  char * szWindowName, 
  short int XPos,  
  short int YPos,  
  short int Width,  
  short int Height,  
  WORD wShowCmd 
) 
{ 
  HGLOBAL hTopicData;                    /* Handle to the topic's elements list. */                 
  FPTOPICDATA fpTopicData; 
 
  char szHelpFilePath[ MAX_HLPPATH ]; 
 
  HWND hPosWnd; 
   
  RECT PosRect; 
   
   
  /* Get the main topic window's topic data. */ 
  hTopicData = (HTOPICDATA) WndData( hMainWnd, WDM_GETTOPICDATA, 0, NULL ); 
               
  /* If there is no main window topic being displayed (window can be hidden). */ 
  if( hTopicData == 0 ) return; 
 
  /* Lock topic data. */ 
  fpTopicData = ( FPTOPICDATA ) GlobalLock( hTopicData ); 
     
  /* Copy path into temp area. */ 
  strcpy( szHelpFilePath, fpTopicData->szHelpFile ); 
       
  /* Unlock topic data. */ 
  GlobalUnlock( hTopicData ); 
   
  /* Get the handle of the window with the given name. */ 
  hPosWnd = GetWindowNamesHandle( hMainWnd, szWindowName, szHelpFilePath ); 
 
  /* No window found. */ 
  if( hPosWnd == 0 ) return; 
 
  /* Size and position window. */ 
  switch( wShowCmd ) 
  { 
    case SW_MINIMIZE: 
    case SW_SHOWMINIMIZED: 
    case SW_SHOWMAXIMIZED: 
    case SW_SHOWMINNOACTIVE: 
    case SW_SHOWNORMAL: 
    case SW_RESTORE: 
    { 
      ShowWindow( hPosWnd, wShowCmd ); 
      break; 
    } 
   
    case SW_SHOWNA: 
    case SW_HIDE: 
    case SW_SHOW: 
    case SW_SHOWNOACTIVATE: 
    {  
      /* Store values in rect. */ 
      PosRect.left   = XPos; 
      PosRect.top    = YPos; 
      PosRect.right  = Width; 
      PosRect.bottom = Height; 
       
      /* Convert virtual position to physical coords. */ 
      VirtualPosToScrnPos( hMainWnd, &PosRect ); 
   
      ShowWindow( hPosWnd, wShowCmd ); 
 
      SetWindowPos( hPosWnd, NULL,  
                    PosRect.left,  
                    PosRect.top,  
                    PosRect.right,  
                    PosRect.bottom, 
                    SWP_NOZORDER ); 
    } 
  } 
}  
 
 
/************************************* 
* 
*  Get name of the secondary window. 
*                   
**************************************/ 
BOOL GetSecWndName( HWND hDataWnd, HWND hSecWnd, char * SecWndNamePtr ) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
  GETSECWNDNAMEFUNCDATA FuncData; 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Init. data. */ 
  FuncData.bFound     = FALSE; 
  FuncData.hSearchWnd = hSecWnd; 
 
  /* Search thru each library. */ 
  EnumWndInfo( GetSecWndNameProc, hFirstSecWndInfo, (LPARAM) (GETSECWNDNAMEFUNCDATAPTR) &FuncData ); 
 
  /* If found. */ 
  if( FuncData.bFound == TRUE ) 
  {  
    /* Copy the window name found. */ 
    strcpy( SecWndNamePtr, FuncData.SecWndName ); 
  } 
   
  /* Return result. */ 
  return( FuncData.bFound ); 
} 
 
 
/************************************* 
* 
*  Find the secondary window's  
*  window name and compare it to the 
*  name given. 
*                   
**************************************/ 
BOOL IsSecWindowsName( HWND hDataWnd, HWND hSecWnd, char * SecWndNamePtr ) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
  GETSECWNDNAMEFUNCDATA FuncData; 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Init. data. */ 
  FuncData.bFound     = FALSE; 
  FuncData.hSearchWnd = hSecWnd; 
 
  /* Search thru each library. */ 
  EnumWndInfo( GetSecWndNameProc, hFirstSecWndInfo, (LPARAM) (GETSECWNDNAMEFUNCDATAPTR) &FuncData ); 
 
  /* If found. */ 
  if( FuncData.bFound == TRUE ) 
  {  
    /* Compare names. */ 
    if( stricmp( SecWndNamePtr, FuncData.SecWndName ) == 0 ) 
    { 
      /* Same name. */ 
      return( TRUE ); 
    } 
  } 
   
  /* The name isn't be the window's name. */ 
  return( FALSE ); 
} 
 
 
 
/************************************* 
* 
*  This function is called by each 
*  secondary window as it closes. 
*                   
**************************************/ 
void SecondaryWindowClosing( HWND hDataWnd, HWND hSecWnd ) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Remove window from the list. */ 
  RemoveSecWndInfo( &hFirstSecWndInfo, hSecWnd ); 
 
  /* Get handle of secondary window data. */ 
  WndData( hDataWnd, WDM_SETSECWNDDATA, (DWORD) hFirstSecWndInfo, NULL ); 
 
  /* If main window is hidden. */ 
  if( !IsWindowVisible( hDataWnd ) && !SecWndExists( hDataWnd ) ) 
  { 
    /* Close main window. */ 
    SendMessage( hDataWnd, WM_CLOSE, 0, 0L ); 
  } 
} 
 
 
/************************************* 
* 
*  This function is called by each 
*  secondary window as it closes. 
*                   
**************************************/ 
BOOL SecWndExists( HWND hDataWnd ) 
{ 
  BOOL bExists; 
  HSECWNDINFO hFirstSecWndInfo; 
 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* No windows. */ 
  bExists = FALSE; 
 
  /* Search thru each library. */ 
  EnumWndInfo( SecWndExistsProc, hFirstSecWndInfo, (LPARAM) (BOOL *) &bExists ); 
 
  /* Return result. */ 
  return( bExists ); 
} 
 
 
/************************************* 
* 
*  Close all secondary windows. 
*                   
**************************************/ 
void CloseAllSecWnd( HWND hDataWnd, BOOL bSendMessage ) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Close each window. */ 
  if( bSendMessage ) 
  { 
    EnumWndInfo( SendCloseAllSecWndProc, hFirstSecWndInfo, 0 ); 
  } 
  else 
  { 
    EnumWndInfo( PostCloseAllSecWndProc, hFirstSecWndInfo, 0 ); 
  } 
   
  /* Remove all data from the window list. */ 
  RemoveAllSecWndInfo( hFirstSecWndInfo ); 
 
  /* Reset saved handle. */ 
  WndData( hDataWnd, WDM_SETSECWNDDATA, (DWORD) NULL, NULL ); 
} 
 
 
/************************************* 
* 
*  Changes all secondary window's. 
*  "On Top" settings. 
*                   
**************************************/ 
void SetAllSecWndOnTop( HWND hDataWnd, BOOL bSecHlpOnTop ) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  EnumWndInfo( SetAllSecWndOnTopProc, hFirstSecWndInfo, (LPARAM)(BOOL *) &bSecHlpOnTop ); 
} 
 
 
/************************************* 
* 
*  Determines if the window handle 
*  belongs to an open secondary window. 
* 
**************************************/ 
BOOL IsSecWndHandle( HWND hDataWnd, HWND hSearchWnd ) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
  ISSECWNDFUNCDATA FuncData; 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Init. data. */ 
  FuncData.bFound     = FALSE; 
  FuncData.hSearchWnd = hSearchWnd; 
 
  /* Search thru each library. */ 
  EnumWndInfo( IsSecWndHandleProc, hFirstSecWndInfo, (LPARAM) (ISSECWNDFUNCDATAPTR) &FuncData ); 
 
  /* Return result. */ 
  return( FuncData.bFound ); 
} 
 
 
/************************************* 
* 
*  Returns the window handle 
*  belonging to a secondary window. 
* 
**************************************/ 
HWND GetWindowNamesHandle 
(  
  HWND hDataWnd,  
  char * szWndName,  
  char * szHelpFilePath  
) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
  HWND hSecWnd; 
   
   
  /*  
  ** Is main window.  
  */  
  if( stricmp( szWndName, MAIN_WINDOW_NAME ) == 0 ) 
  { 
    return( hDataWnd ); 
  } 
 
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Check to see if the secondary help window is already open. */ 
  hSecWnd = GetSecWndNameHandle( hFirstSecWndInfo, szWndName, szHelpFilePath ); 
 
  /* Return what we found. */ 
  return( hSecWnd ); 
} 
 
 
/***********************************  Private Functions  *********************************/ 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in SetAllSecWndOnTop(). 
* 
*  Changes the "On Top" status of 
*  the given secondary window. 
*                   
**************************************/ 
static BOOL CALLBACK SetAllSecWndOnTopProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  BOOL * OnTopPtr; 
   
  /* Get "On Top" setting. */ 
  OnTopPtr = (BOOL *) lParam; 
   
  /* If should be "On Top". */ 
  if( *OnTopPtr == TRUE ) 
  { 
    /* Set main window. */ 
    SetWindowPos( SecWndInfoPtr->hSecWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); 
  } 
  else 
  { 
    /* Set main window. */ 
    SetWindowPos( SecWndInfoPtr->hSecWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); 
  } 
 
  /* Keep enumerating. */ 
  return( TRUE ); 
} 
 
 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in GetSecWndNam(). 
*                   
**************************************/ 
static BOOL CALLBACK GetSecWndNameProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  GETSECWNDNAMEFUNCDATAPTR FuncDataPtr; 
   
  /* Get function data. */ 
  FuncDataPtr = ( GETSECWNDNAMEFUNCDATAPTR ) lParam; 
   
  /* Same window handle? */ 
  if( SecWndInfoPtr->hSecWnd == FuncDataPtr->hSearchWnd ) 
  { 
    /* Is a secondary window! */ 
    FuncDataPtr->bFound = TRUE; 
     
    /* Copy window's name. */ 
    strcpy( FuncDataPtr->SecWndName, SecWndInfoPtr->szSecWndName ); 
 
    /* Stop enumerating. */ 
    return( FALSE ); 
  } 
   
  /* Keep enumerating. */ 
  return( TRUE ); 
} 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in IsSecWndHandle(). 
*                   
**************************************/ 
static BOOL CALLBACK IsSecWndHandleProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  ISSECWNDFUNCDATAPTR FuncDataPtr; 
   
  /* Get function data. */ 
  FuncDataPtr = ( ISSECWNDFUNCDATAPTR ) lParam; 
   
  /* Same window handle? */ 
  if( SecWndInfoPtr->hSecWnd == FuncDataPtr->hSearchWnd ) 
  { 
    /* Is a secondary window! */ 
    FuncDataPtr->bFound = TRUE; 
     
    /* Stop enumerating. */ 
    return( FALSE ); 
  } 
   
  /* Keep enumerating. */ 
  return( TRUE ); 
} 
 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in CloseAllSecWnd(). 
* 
*  Closes the window passed to it by 
*  "sending" a WM_CLOSE message. 
*                   
**************************************/ 
static BOOL CALLBACK SendCloseAllSecWndProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  /* Close all windows. */ 
  SendMessage( SecWndInfoPtr->hSecWnd, WM_CLOSE, DONT_REPORT_CLOSING, 0L ); 
       
  /* Keep enumerating. */ 
  return( TRUE ); 
} 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in CloseAllSecWnd(). 
* 
*  Closes the window passed to it by 
*  "posting" a WM_CLOSE message. 
*                   
**************************************/ 
static BOOL CALLBACK PostCloseAllSecWndProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  /* Close all windows. */ 
  PostMessage( SecWndInfoPtr->hSecWnd, WM_CLOSE, DONT_REPORT_CLOSING, 0L ); 
       
  /* Keep enumerating. */ 
  return( TRUE ); 
} 
 
 
/******************************************* 
**  
** Set title of help window. 
** 
********************************************/ 
void SetMainWindowTitle( HWND hWnd, HTOPICDATA hTopicData ) 
{ 
  char szTitleText[ MAX_SEC_CAPTION ]; 
   
  HGLOBAL      hUserTitleText; 
  char * fpUserTitleText; 
   
  FPTOPICDATA  fpTopicData; 
   
  /* Lock topic data. */ 
  fpTopicData = ( FPTOPICDATA ) GlobalLock( hTopicData ); 
   
  /* Use the user define title. */ 
  hUserTitleText = GetTitleText( fpTopicData->hHelpFileInfo ); 
 
  /* Unlock topic data. */ 
  GlobalUnlock( hTopicData ); 
   
  /* If there is a title. */ 
  if( hUserTitleText != NULL ) 
  {    
    /* Lock the user's title text data. */ 
    fpUserTitleText = (char *) GlobalLock( hUserTitleText ); 
 
    /* Empty string? */ 
    if( *fpUserTitleText == '\0' ) 
    { 
      /* Unlock the user's title text data. */ 
      GlobalUnlock( hUserTitleText ); 
 
      /* Load the default title string. */ 
      LoadString( GetLibInst(), IDS_DEFAULTTITLE, szTitleText, sizeof( szTitleText ) - 1 ); 
        
      /* Set window's text to default title string. */ 
      SetWindowText( hWnd, (LPCSTR) szTitleText ); 
 
      /* Done. */ 
      return; 
    } 
     
    /* Set window's text to user defined title. */ 
    SetWindowText( hWnd, fpUserTitleText ); 
   
    /* Unlock the user's title text data. */ 
    GlobalUnlock( hUserTitleText ); 
     
    /* Done. */ 
    return; 
  } 
 
  /* Use the default title. */ 
  else 
  { 
    /* Load the caption string. */ 
    LoadString( GetLibInst(), IDS_DEFAULTTITLE, szTitleText, sizeof( szTitleText ) - 1 ); 
      
    /* Set window's text. */ 
    SetWindowText( hWnd, (LPCSTR) szTitleText ); 
  } 
} 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in SecWndExist(). 
*                   
**************************************/ 
static BOOL CALLBACK SecWndExistsProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  BOOL * bExistsPtr; 
   
  /* Get pointer to data. */ 
  bExistsPtr = (BOOL *) lParam; 
          
  /* Found a secondary window. */ 
  *bExistsPtr = TRUE; 
       
  /* No more enumerating. */ 
  return( FALSE ); 
} 
 
 
/************************************* 
* 
*  Get a secondary window number's  
*  handle. 
*                   
**************************************/ 
static HWND GetSecWndNumHandle 
(  
  HWND hDataWnd, 
  WORD wSecWndNum, 
  char * szHelpFilePath  
) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
  SECWNDINFO SecWndInfo; 
 
  /* Get handle of secondary window data. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
   
  /* Initialize private data. */ 
  SecWndInfo.wSecWndNum = wSecWndNum; 
  strcpy( SecWndInfo.szHelpFilePath, szHelpFilePath );  
  SecWndInfo.hSecWnd    = 0; 
              
  /* Search thru each library. */ 
  EnumWndInfo( GetSecWndNumHandleProc, hFirstSecWndInfo, (LPARAM) (FPSECWNDINFO) &SecWndInfo ); 
 
  /* Return found value. */ 
  return( SecWndInfo.hSecWnd ); 
} 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in GetSecWndNumHandle(). 
*                   
**************************************/ 
static BOOL CALLBACK GetSecWndNumHandleProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  FPSECWNDINFO SearchInfoPtr; 
   
  /* Get pointer to search data. */ 
  SearchInfoPtr = (FPSECWNDINFO) lParam; 
          
  /* Correct secondary window? */ 
  if( SearchInfoPtr->wSecWndNum == SecWndInfoPtr->wSecWndNum ) 
  { 
    if( stricmp( SearchInfoPtr->szHelpFilePath, SecWndInfoPtr->szHelpFilePath ) == 0 ) 
    { 
      /* Save window handle. */  
      SearchInfoPtr->hSecWnd = SecWndInfoPtr->hSecWnd; 
       
      /* No more enumerating. */ 
      return( FALSE ); 
    } 
  } 
     
  /* Keep enumerating. */ 
  return TRUE; 
} 
 
 
 
/************************************* 
* 
*  Get a secondary window name's  
*  handle. 
*                   
**************************************/ 
static HWND GetSecWndNameHandle 
(  
  HSECWNDINFO hFirstSecWndInfo, 
  char * szSecWndName, 
  char * szHelpFilePath  
) 
{ 
  SECWNDINFO SecWndInfo; 
 
  /* Initialize private data. */ 
  strcpy( SecWndInfo.szSecWndName, szSecWndName );  
  strcpy( SecWndInfo.szHelpFilePath, szHelpFilePath );  
  SecWndInfo.hSecWnd = 0; 
              
  /* Search thru each library. */ 
  EnumWndInfo( GetSecWndNameHandleProc, hFirstSecWndInfo, (LPARAM) (FPSECWNDINFO) &SecWndInfo ); 
 
  /* Return found value. */ 
  return( SecWndInfo.hSecWnd ); 
} 
 
 
/************************************* 
* 
*  EnumWndInfo() callback function  
*  used in GetSecWndNameHandle(). 
*                   
**************************************/ 
static BOOL CALLBACK GetSecWndNameHandleProc( FPSECWNDINFO SecWndInfoPtr, LPARAM lParam ) 
{ 
  FPSECWNDINFO SearchInfoPtr; 
   
  /* Get pointer to search data. */ 
  SearchInfoPtr = (FPSECWNDINFO) lParam; 
          
  /* Correct secondary window? */ 
  if( stricmp( SearchInfoPtr->szSecWndName, SecWndInfoPtr->szSecWndName ) == 0 ) 
  { 
    if( stricmp( SearchInfoPtr->szHelpFilePath, SecWndInfoPtr->szHelpFilePath ) == 0 ) 
    { 
      /* Save window handle. */  
      SearchInfoPtr->hSecWnd = SecWndInfoPtr->hSecWnd; 
       
      /* No more enumerating. */ 
      return( FALSE ); 
    } 
  } 
     
  /* Keep enumerating. */ 
  return TRUE; 
} 
 
 
 
/************************************* 
* 
*  A new secondary window has been opened. 
*  Insert the new window's info into  
*  a the window info. list. 
*                   
**************************************/ 
static BOOL InsertSecWnd 
(  
  HWND hDataWnd, 
  HWND hErrorWnd,  
  WORD wSecWndNum, 
  HWND hSecWnd, 
  char * szHelpFilePath, 
  char * szSecWndName 
) 
{ 
  HSECWNDINFO hFirstSecWndInfo; 
  FPSECWNDINFO SecWndInfoPtr; 
  HSECWNDINFO  hNewSecWndInfo; 
   
 
  /* Allocate a new node. */ 
  if( ! GlobalAllocMem( hErrorWnd, &hNewSecWndInfo, sizeof(SECWNDINFO) ) ) return FALSE; 
   
  /* Lock it. */ 
  SecWndInfoPtr = (FPSECWNDINFO) GlobalLock( hNewSecWndInfo ) ; 
 
  /* Initialize structure. */ 
  SecWndInfoPtr->wSecWndNum  = wSecWndNum; 
  SecWndInfoPtr->hSecWnd     = hSecWnd; 
  strcpy( SecWndInfoPtr->szHelpFilePath, szHelpFilePath ); 
  strcpy( SecWndInfoPtr->szSecWndName, szSecWndName ); 
    
  /* Get the handle of info. structure. */ 
  hFirstSecWndInfo = (HGLOBAL) WndData( hDataWnd, WDM_GETSECWNDDATA, 0L, NULL ); 
 
  /* Existing first node. */ 
  if( hFirstSecWndInfo != 0 )  
  { 
    /* Point new node to existing top node. */ 
    SecWndInfoPtr->Next = hFirstSecWndInfo; 
  } 
  else 
  { 
    /* Point new node to existing top node. */ 
    SecWndInfoPtr->Next = 0; 
  } 
 
  /* Unlock it. */ 
  GlobalUnlock( hNewSecWndInfo ) ; 
 
  /* Save handle to new top. */ 
  WndData( hDataWnd, WDM_SETSECWNDDATA, (DWORD) hNewSecWndInfo, NULL ); 
   
  /* Return success. */ 
  return TRUE; 
} 
 
 
/************************************* 
* 
*  Remove and frees a secondary 
*  window's info. from the list. 
*                   
**************************************/ 
static BOOL RemoveSecWndInfo 
(  
  HSECWNDINFO * hFirstSecWndInfo, 
  HWND hSecWnd 
) 
{ 
  FPSECWNDINFO SecWndInfoPtr, TmpSecWndInfoPtr; 
  HSECWNDINFO  hSecWndInfo, hTmpSecWndInfo; 
   
 
  /* Existing first node. */ 
  if( *hFirstSecWndInfo == 0 ) return FALSE; 
 
  /* Lock top handle. */ 
  SecWndInfoPtr = (FPSECWNDINFO) GlobalLock( *hFirstSecWndInfo ) ; 
   
  /* If deleting top node. */ 
  if( SecWndInfoPtr->hSecWnd == hSecWnd ) 
  { 
    /* Next node is to be new top node. */ 
    hTmpSecWndInfo = SecWndInfoPtr->Next;  
 
    /* Unlock top handle. */ 
    GlobalUnlock( *hFirstSecWndInfo ); 
     
    /* Free top. */ 
    MyGlobalFree( *hFirstSecWndInfo );  
   
    /* Assign new top. */ 
    *hFirstSecWndInfo = hTmpSecWndInfo; 
 
    /* Success. */ 
    return TRUE; 
  } 
 
  /* Unlock top handle. */ 
  GlobalUnlock( *hFirstSecWndInfo ); 
     
  /* Find correct node and remove. */ 
  hTmpSecWndInfo = *hFirstSecWndInfo; 
  hSecWndInfo = GetNextWndInfo( *hFirstSecWndInfo ); 
 
  while( hSecWndInfo != 0 ) 
  { 
    /* Lock current node. */ 
    SecWndInfoPtr = (FPSECWNDINFO) GlobalLock( hSecWndInfo ) ; 
   
    /* If deleting current node. */ 
    if( SecWndInfoPtr->hSecWnd == hSecWnd ) 
    { 
      /* Lock previous node. */ 
      TmpSecWndInfoPtr = (FPSECWNDINFO) GlobalLock( hTmpSecWndInfo ) ; 
 
      /* Previous node's "next node" is deleted node's "next node". */ 
      TmpSecWndInfoPtr->Next = SecWndInfoPtr->Next;  
   
      /* Unlock previous node. */ 
      GlobalUnlock( hTmpSecWndInfo ); 
 
      /* Unlock current node. */ 
      GlobalUnlock( hSecWndInfo ); 
       
      /* Free top. */ 
      MyGlobalFree( hSecWndInfo );  
   
      /* Success. */ 
      return TRUE; 
    } 
     
    /* Unlock it. */ 
    GlobalUnlock( hSecWndInfo ) ; 
 
    /* Get next node. */ 
    hTmpSecWndInfo = hSecWndInfo; 
    hSecWndInfo = GetNextWndInfo( hSecWndInfo ); 
  } 
 
  /* Did not find window. */ 
  return FALSE; 
} 
 
 
/************************************* 
* 
*  Remove and frees a secondary 
*  window's info. from the list. 
*                   
**************************************/ 
static void RemoveAllSecWndInfo 
(  
  HSECWNDINFO hFirstSecWndInfo 
) 
{ 
  HSECWNDINFO  hSecWndInfo, hNextSecWndInfo; 
   
 
  /* Existing first node. */ 
  if( hFirstSecWndInfo == 0 ) return; 
 
  /* Get handle to the first window's info. */ 
  hSecWndInfo = hFirstSecWndInfo; 
 
  while( hSecWndInfo != 0 ) 
  { 
    /* Get the handle to the next window info. */ 
    hNextSecWndInfo = GetNextWndInfo( hSecWndInfo ); 
       
    /* Free current window's info. */ 
    MyGlobalFree( hSecWndInfo );  
   
    /* Next is current. */ 
    hSecWndInfo = hNextSecWndInfo; 
  } 
} 
 
 
/************************************* 
* 
*  Get the next window info. structure 
*  after the given hSecWndInfo. 
*                   
**************************************/ 
static HSECWNDINFO GetNextWndInfo( HSECWNDINFO hSecWndInfo ) 
{ 
  HSECWNDINFO hNextWndInfo; 
  FPSECWNDINFO SecWndInfoPtr; 
   
  /* Handle bad. */ 
  if( hSecWndInfo == 0 ) return 0; 
 
  /* Lock it. */ 
  SecWndInfoPtr = (FPSECWNDINFO) GlobalLock( hSecWndInfo ) ; 
   
  /* Point new node to existing top node. */ 
  hNextWndInfo = SecWndInfoPtr->Next; 
 
  /* Unlock it. */ 
  GlobalUnlock( hSecWndInfo ) ; 
 
  /* Return next window info's handle. */ 
  return hNextWndInfo; 
} 
 
 
 
/************************************* 
* 
*  Enumerate all SECWNDINFO structures 
*  contained in the given list. 
*                   
**************************************/ 
static void EnumWndInfo 
(  
  WNDINFOENUMPROC WndInfoEnumProc,  
  HSECWNDINFO hFirstSecWndInfo,  
  LPARAM lParam  
) 
{ 
  FPSECWNDINFO SecWndInfoPtr; 
  HSECWNDINFO hSecWndInfo; 
   
  BOOL bReturn; 
   
  /* Get first window info's handle. */ 
  hSecWndInfo = hFirstSecWndInfo; 
   
  /* Stop when we run out of windows in the list. */ 
  while( hSecWndInfo != 0 ) 
  { 
    /* Lock it. */ 
    SecWndInfoPtr = (FPSECWNDINFO) GlobalLock( hSecWndInfo ) ; 
   
    /* Call callback function. */ 
    bReturn = (*WndInfoEnumProc)( SecWndInfoPtr, lParam ); 
     
    /* Stop enumerating. */ 
    if( bReturn == FALSE ) 
    { 
      /* Unlock it. */ 
      GlobalUnlock( hSecWndInfo ); 
      return; 
    } 
     
    /* Unlock it. */ 
    GlobalUnlock( hSecWndInfo ) ; 
 
    hSecWndInfo = GetNextWndInfo( hSecWndInfo ); 
  } 
}