/****************************************************************************
**
**  Name:  ldrprog.cpp
**
**  Description:
**     This is the source code to support the Loader Progress Indicator
**     and Load Information dialogs.  It uses "generic" progress indicator
**     code in gauge.c and g3d.c, which originally came from the Microsoft
**     Developer's Network CD under the name "zYzgauge".  
**
**  $Log:   S:/tbird/mt2_186/loader/ldrprog.cpv  $
** 
**    Rev 1.2   13 Feb 1998 14:50:12   hera
** Fix for ID2
** 
**    Rev 1.1   26 Feb 1997 11:49:48   Judy
** 
**    Rev 1.0   14 Jun 1996 17:25:36   Judy
** Initial revision.
** 
**    Rev 1.6   28 Sep 1994 11:51:16   nghia
** Added a global loadErr to save the error returned from specific loader.
** 
**    Rev 1.5   27 Sep 1994 18:00:40   nghia
** Revised the percentage of progress indicator to preserve the last 10%
** Added SymGetLdrStat() to load info dialog to get the latest symbol loading
** information.  Also, initialize the LdrStatus block to 0 before hands it
** to the specific loaders.
** 
**    Rev 1.4   14 Jul 1994 10:44:50   nghia
** Added load address space to call back for the Progress Indicator dialog.
** 
**    Rev 1.3   17 Jun 1994 11:37:32   nghia
** Fixed compiler warning.
** 
**    Rev 1.2   15 Jun 1994 12:49:58   nghia
** Fixed progress indicator report PC and Stack Information.
** 
**    Rev 1.1   20 May 1994 10:56:22   nghia
** Revised StatusBlock: StartPC,StackBase, and StackSize to be string type
** to support Intel processor.
** 
**    Rev 1.0   18 May 1994 16:58:58   nghia
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_186/loader/ldrprog.cpv   1.2   13 Feb 1998 14:50:12   hera  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <stdio.h>
#include <mem.h>
#include <io.h>
#include <sys\timeb.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _HLPENTRY_
#include "hlpentry.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#include "gauge.h"

#ifndef __LDRPROG__
#include "ldrprog.h"
#endif

#ifndef _LOADER_
#include "loader.h"
#endif

#ifndef __LDROBJ__
#include "ldrobj.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
PRIVATE BOOLEAN inDialog = FALSE;
PRIVATE HANDLE hProgressDlg = 0;
PRIVATE FP_LOADPROC callBackFn = NULL;  // Specific Loader Load Function
PRIVATE BOOLEAN loadComplete = 0; 
PRIVATE WORD wCount = 0; 
PRIVATE LONG lCount = 0L;
PRIVATE char buf1[128];
PRIVATE BOOLEAN inThere = FALSE;
PRIVATE BOOLEAN cancelButtonPressed = FALSE;
PRIVATE HANDLE hCancelButton; // handle of cancel button subwindow 
PRIVATE HANDLE hHelpButton;   // handle of help button subwindow 
PRIVATE RETCODE loadErr;      // load error return from load dialog box

// Progress reporting status block - To be used by specific loaders
LDRSTATBLOCK LdrStatus;

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern HANDLE  hLib;                 
extern PTLdrLauncher LoaderServer;   

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
PRIVATE RETCODE LdrProgressDialogStep(VOID);
PRIVATE RETCODE LdrProgressDialogDone(BOOLEAN);
PRIVATE VOID SetControlParams(HANDLE, WORD, WORD, WORD, WORD, LONG, LONG);
PRIVATE RETCODE MakeProgressDialog(HWND);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/****************************************************************************
**
**  LdrInfoDialog
**
*****************************************************************************/
RETCODE EXPORT LdrInfoDialog(U32 parentHwnd) {
   FARPROC lpfnDlgProc;

   if (!LoaderServer || (LoaderServer->Status() != GOOD))
      return ER_LDR_INVALID_SERVER;
   if (LoaderServer->IsLoading())
      return ER_LDR_IN_PROGRESS;
   
   if ((lpfnDlgProc = MakeProcInstance((FARPROC)LdrInfoDlgProc, hLib))
       != NULL) {
      DialogBox(hLib, DLG_LDRINFO, (HWND)parentHwnd, lpfnDlgProc);
      FreeProcInstance(lpfnDlgProc);
      return GOOD;
   }
   return ER_CANNOT_OPEN_DIALOG;
}

/******************************************************************************
**
**  LdrProgressInc
**
******************************************************************************/
RETCODE EXPORT LdrProgressInc(VOID) {
   PRIVATE struct timeb last_time;
   PRIVATE struct timeb this_time;
   PRIVATE BOOLEAN called = FALSE;
   S32 timedif;
   RETCODE err;
   U32 tmpLocation;
   S16 buttonID;

   // First, make sure that we don't update more than twice per second,
   // to avoid performance penalties and annoyingly-active displays.
   if (!called) {
      ftime(&last_time);
      called = TRUE;
   }
   else {
      ftime(&this_time);
      timedif = ((this_time.time * 1000) + this_time.millitm)
                - ((last_time.time * 1000) + last_time.millitm);
      if (timedif < 0) {
         last_time = this_time;
      }
      if (timedif < 500) return (GOOD);
      last_time = this_time;
   }

   // collect stats whether we are interactive or batch...
   //
   // Only check symbol statistic if LOAD_SYM is TRUE.  We don't want to
   // get any old information.
   if (IsLoadSymbol(LoaderServer->LastLoadOptions()))
      SymGetLdrStats((LPSTR)&(LdrStatus.curModule),
                     (U32 FAR *)(&LdrStatus.numSymbols),
                     (U16 FAR *)(&LdrStatus.numModules),
                     (U32 FAR *)(&LdrStatus.numTypes));
   //
   // But only display them if we are interactive
   //
   if (inDialog) {
      // Don't back up 
      if (LdrStatus.curLocation < LdrStatus.lastLocation) {
         LdrStatus.curLocation = LdrStatus.lastLocation;
      }
      // initialize percentInc once
      if (LdrStatus.percentInc < 5) {
         // Don't bump it more than 1 percentInc in one jump, where
         // percentInc is based on loadfile size and the current file pointer.
         //
         if (LdrStatus.loadFileSize < 1000L) {
            LdrStatus.percentInc = 20; // max 20% per increment 
         }
         else if (LdrStatus.loadFileSize < 10000L) {
            LdrStatus.percentInc = 10; // max 10% per increment 
         }
         else {
            LdrStatus.percentInc = 5; // max 5% per increment 
         }
      }
      
      tmpLocation = LdrStatus.lastLocation +
                    (LdrStatus.loadFileSize / (100 / LdrStatus.percentInc));
      if (tmpLocation > LdrStatus.loadFileSize)
         tmpLocation = LdrStatus.loadFileSize;
      if (LdrStatus.curLocation > tmpLocation)
         LdrStatus.curLocation = tmpLocation;
      // 
      // If loading both code and symbols, don't pass the 90% mark
      // until the number of symbols exceeds the number of modules.
      //
      if (IsLoadCode(LoaderServer->LastLoadOptions()) &&
          IsLoadSymbol(LoaderServer->LastLoadOptions()) &&
          (LdrStatus.numSymbols < LdrStatus.numModules + 1)) {
         if (LdrStatus.curLocation > (9 * LdrStatus.loadFileSize / 10)) {
            LdrStatus.curLocation = (9 * LdrStatus.loadFileSize / 10);
         }
      }

      // only update display when something significant happenned
      if ((LdrStatus.numModules  > LdrStatus.lastNumModules) || 
          (LdrStatus.numSymbols  > LdrStatus.lastNumSymbols + 10) ||
          (LdrStatus.curLocation > LdrStatus.lastLocation + 100) ||
          (LdrStatus.curLocation < LdrStatus.lastLocation - 100) ||
          (LdrStatus.numBytes    > LdrStatus.lastNumBytes + 100)) {
         if ((err = LdrProgressDialogStep()) != GOOD) {
            if (err == ER_LDR_ABORT) {
               err = ErrMessageBox((LPSTR) "PowerViews", 
                     (LPSTR) "Really Cancel the Load?", 
                     MB_ICONQUESTION | MB_YESNO,
                     HE_CANCEL_LOAD, (S16 FAR *) &buttonID);
               if (err != GOOD) {
                  return (err);
               }
               if (buttonID == IDYES) {
                  return (ER_LDR_ABORT);
               }
            }
            else {
               return (err);
            }
         }
      }
      LdrStatus.lastNumModules = LdrStatus.numModules;
      LdrStatus.lastNumSymbols = LdrStatus.numSymbols;
      LdrStatus.lastNumBytes = LdrStatus.numBytes;
      LdrStatus.lastLocation = LdrStatus.curLocation;
   }
   return GOOD;
} /* LdrProgressInc */

/******************************************************************************
**
**  LdrProgressDone
**
******************************************************************************/
RETCODE EXPORT LdrProgressDone(RETCODE loadErr) {
   RETCODE err;
   BOOLEAN keepDialog = FALSE;

   // Only check symbol statistic if load symbol is TRUE.
   // We don't want to get any old information.
   if (inDialog) {
      if (IsLoadSymbol(LoaderServer->LastLoadOptions()))
         SymGetLdrStats((LPSTR)&(LdrStatus.curModule),
                     (U32 FAR *)(&LdrStatus.numSymbols),
                     (U16 FAR *)(&LdrStatus.numModules),
                     (U32 FAR *)(&LdrStatus.numTypes));
      if (loadErr == GOOD) keepDialog = TRUE;
      if ((err = LdrProgressDialogDone(keepDialog)) != GOOD) 
         return err;
      
      if (!keepDialog && (loadErr != ER_LDR_ABORT)) 
	 return ErrDisplayError(loadErr, CHECK_MODE);
      return GOOD;//Hera 2/13/98
   }
   else
      return loadErr;//Hera 2/13/98
} /* LdrProgressDone */

/*****************************************************************************
**
**  LdrGetStatBlock
**
*****************************************************************************/
RETCODE EXPORT LdrGetStatBlock(LPLDRSTATBLOCK FAR *lpstb) {
   
   if (!LoaderServer || (LoaderServer->Status() != GOOD))
      return ER_LDR_INVALID_SERVER;
   // Only if there is a loading operation is going 
   if (!LoaderServer->IsLoading())
      return ER_LDR_IN_PROGRESS;
   // initialize LdrStatus block to 0
   memset(&LdrStatus, 0, sizeof(LDRSTATBLOCK));
   // return the pointer to the local LdrStatus block
   *lpstb = (LPLDRSTATBLOCK)&LdrStatus; 
   return GOOD;
}

/****************************** LOCAL FUNCTIONS *****************************/

/*************************************************************************--
**
**  LdrProgressDialog
**
**  Purpose:
**     Create the Progress Dialog for PowerViews, and wait until
**     the Cancel/OK button is pressed.
**
**  Input:
**     parent:  The parent window handle.
**     callBack:  The function to be call to handle loading.
**
**  Output:
**     None.  
*****************************************************************************/
RETCODE LdrProgressDialog(HWND parent, FP_LOADPROC callBack) {
   RETCODE err;

   callBackFn  = callBack;
   // clear out old information in status block
   memset(&LdrStatus, 0, sizeof(LdrStatus));
   LdrStatus.percentInc =  1;  // avoid divide by 0 
   err = MakeProgressDialog(parent);
   callBackFn = NULL;
   return err;
}

/****************************************************************************
**
**  LdrProgressDialogStep
**
*****************************************************************************/
PRIVATE RETCODE LdrProgressDialogStep(VOID) {  
   SendMessage(hProgressDlg, WM_COMMAND, ID_PROGRESS_INC, 0);
   if (cancelButtonPressed) {
      cancelButtonPressed = FALSE;
      return ER_LDR_ABORT;
   }
   return GOOD;
}

/*************************************************************************--
**
**  LdrProgressDialogDone
**
**  Purpose:
**     Update the load progress dialog status to final values, based on
**  values in the loader status block.
**
**  Input:
**     normal: if true, update and keep dialog up until OK is pressed.
**             Otherwise remove the dialog immediately.
**
**  Output:
***************************************************************************-*/
PRIVATE RETCODE LdrProgressDialogDone(BOOLEAN normal) {
   
   // If this isn't a normal quit, the user pressed the cancel button... 
   if (!normal) {
      SendMessage(hProgressDlg, WM_CLOSE, 0, 0);
      return (GOOD);
   }
   cancelButtonPressed = FALSE;
   SendMessage(hProgressDlg, WM_COMMAND, ID_PROGRESS_DONE, 0);
   return GOOD;
}

/***************************************************************************
**
**  SetControlParams
**
**  Purpose:
**     Set up the appearance of the "gauge" progress indicator.
**
**  Input:
**     hwnd:       The window handle.
**     wOrient:    The orientation (vertical/horizontal).
**     wFace:      The width of the bezel face.
**     wEdge:      The width of the bezel edge.
**     rgbBkColor: The background color of the gauge.
**     rgbFgColor: The foreground color of the gauge.
**
**  Output:
**     None.
*****************************************************************************/
PRIVATE VOID SetControlParams(HANDLE hwnd, WORD wOrient, WORD wRange,
                                 WORD wFace, WORD wEdge, LONG rgbBkColor,
                                 LONG rgbFgColor) {
    // set the orientation according to lParam value 
    SendMessage(hwnd, G_SETORIENTATION, wOrient, 0);

    // set the range to some oddball value (demo) 
    SendMessage(hwnd, G_SETRANGE, wRange, 0);

    // set the bezel face to some reasonable width 
    SendMessage(hwnd, G_SETBEZELFACE, wFace, 0);

    // set the bezel edge to some width 
    SendMessage(hwnd, G_SETWIDTH3D, wEdge, 0);

    // set the fore and back colors to cool values 
    SendMessage(hwnd, G_SETBKCOLOR, 0, rgbBkColor);
    SendMessage(hwnd, G_SETFGCOLOR, 0, rgbFgColor);
} /* SetControlParams */

/***************************************************************************
**
**  MakeProgressDialog
**
**  Purpose:
**     Just a wrapper around the call to make the dialog box -- basically
**  just to make sure that the Gauge class initializes correctly.
**
**  Input:
**     none
**  Output:
**     none
***************************************************************************-*/
PRIVATE RETCODE MakeProgressDialog(HWND parentHwnd) {
    FARPROC lpfnDlgProc;

    /* initialize the Gauge class */
    if (!gaugeInit(hLib))
        return ER_CANNOT_OPEN_DIALOG;
    
    if ((lpfnDlgProc = MakeProcInstance((FARPROC)LdrProgressDlgProc,
                                        hLib)) != NULL) {
       inDialog = TRUE; loadErr = GOOD;
       // Run a MODAL progress loading dialog box
       // will not return until done
       DialogBox(hLib, DLG_PROGRESS, parentHwnd, lpfnDlgProc);
       inDialog = FALSE;
       FreeProcInstance(lpfnDlgProc);
       // LoadErr was save by the DlgProc after call the callbackFn.
       return loadErr;
    }
    return ER_CANNOT_OPEN_DIALOG;
} /* MakeProgressDialog */

/***************************************************************************
**
**  LdrProgressDlgProc
**
**  Purpose:
**     Load Progress dialog procedure for PowerViews.  The tricky part is
**  that we can't let Windows do a task swap during the load, so we have
**  to set up the dialog, post a message to ourselves (PROGRESS_GO), handle
**  the initial painting (etc), and then in the processing of PROGRESS_GO
**  we call the loader, which uses SendMessage to increment the progress
**  indicator.  We change the Cancel button to an OK button when it is
**  done, and we enable Help only when it's done.  We use PeekMessage to
**  check for a message to the Cancel button during processing, and the
**  loader code will confirm the cancel operation with by calling the
**  ErrMessageBox() function.
**
**  Input:
**     hDlg:  The window handle.
**     uMsg:  The current message.
**     wParam:  The word message param.
**     lParam:  The long message param.
**
**  Output:
**     None.
****************************************************************************/
#pragma argsused
BOOL FAR PASCAL LdrProgressDlgProc(HANDLE hdlg, WORD uMsg, WORD wParam,
                                   LONG lParam) {
    MSG msg;
    switch (uMsg) {
        case WM_INITDIALOG:
            if (inThere) 
               break;           
            cancelButtonPressed = FALSE;
            hProgressDlg = hdlg;
            // set up all of the gauges 
            SetControlParams(GetDlgItem(hdlg, IDD_GAUGE),
                    G_ORIENT_LEFTTORIGHT, TG_RANGE, 2, 2,
                    RGB(128, 128, 255), RGB(0, 0, 255));

            // I want the focus on the cancel button 
            hCancelButton = GetDlgItem(hdlg, IDCANCEL);
            hHelpButton = GetDlgItem(hdlg, IDHELP);
            EnableWindow(hHelpButton, FALSE);
            SetFocus(hCancelButton);
            SetDlgItemText(hdlg, DLGMODULES, (LPSTR) "Modules:");
            SetDlgItemText(hdlg, DLGBYTES,   (LPSTR) "Bytes:");
            SetDlgItemText(hdlg, DLGSYMBOLS, (LPSTR) "Symbols:");
            SetDlgItemText(hdlg, DLGLINES,   (LPSTR) "Lines:");
            loadComplete = FALSE;
            /* call back (args saved in ldr.c) */
            SendMessage(hdlg, WM_COMMAND, ID_PROGRESS_INC, 0);
            InvalidateRect(hdlg, NULL, 0);
            UpdateWindow(hdlg);
            // IMPORTANT
            // Activate the Load function to load
            //
            PostMessage(hdlg, WM_COMMAND, ID_PROGRESS_GO, 0);
            break;

        case WM_COMMAND:
            if ((wParam == IDOK) || (wParam == IDCANCEL)) {
                EndDialog(hdlg, (wParam == IDOK));
                return (TRUE);
            }
            else if (wParam == IDHELP) {
               WinHelp(hdlg, "PWRVIEWS.HLP",
                  HELP_CONTEXT, HE_LOAD_PROGRESS);
               return (TRUE);
            } 
            else if ((wParam == ID_PROGRESS_INC) || 
                   (wParam == ID_PROGRESS_DONE)) {
               if (wParam == ID_PROGRESS_DONE) {
                  loadComplete = TRUE;
               }
               SetFocus(GetDlgItem(hdlg, IDCANCEL));
               lCount = 0L;
               if (LdrStatus.loadFileSize > 0) {
                  lCount = (100L * LdrStatus.curLocation) /
                              LdrStatus.loadFileSize;
               }
               if (lCount >= 100 || loadComplete) {
                  wCount = 100;
               }
               else {
                  wCount = (WORD) lCount;
               }
               /* set the position to +1 of the previous value */
               if (lstrlen(LdrStatus.curLoadFile) > 0) {
                  sprintf(buf1, "%s", LdrStatus.curLoadFile);
                  SetDlgItemText(hdlg, DLGLOADFILE, (LPSTR) buf1);
               }
               SendMessage(GetDlgItem(hdlg, IDD_GAUGE),
                                G_SETPOSITION, wCount, 0);
               if (lstrlen(LdrStatus.curModule) > 0) {
                  sprintf(buf1, "%s", LdrStatus.curModule);
                  SetDlgItemText(hdlg, DLGMODULE, (LPSTR) buf1);
               }
               else {
                  SetDlgItemText(hdlg, DLGMODULE, (LPSTR) " ");
               }
               sprintf(buf1, "%d", LdrStatus.numModules);
               SetDlgItemText(hdlg, DLGMODULESLOADED, (LPSTR) buf1);
               sprintf(buf1, "%ld", LdrStatus.numBytes);
               SetDlgItemText(hdlg, DLGBYTESLOADED, (LPSTR) buf1);
               sprintf(buf1, "%ld", LdrStatus.numSymbols);
               SetDlgItemText(hdlg, DLGSYMBOLSLOADED, (LPSTR) buf1);
               sprintf(buf1, "%ld", LdrStatus.numTypes);
               SetDlgItemText(hdlg, DLGTYPESLOADED, (LPSTR) buf1);
               sprintf(buf1, "%ld", LdrStatus.numFunctions);
               SetDlgItemText(hdlg, DLGFUNCSLOADED, (LPSTR) buf1);
               sprintf(buf1, "%ld", LdrStatus.numLines);
               SetDlgItemText(hdlg, DLGLINESLOADED, (LPSTR) buf1);

               if (wParam == ID_PROGRESS_DONE) {
                  SetWindowText(hdlg, (LPSTR) "Load Complete");
                  SetDlgItemText(hdlg, DLGSTARTPC, (LPSTR) "PC:");
                  if (LdrStatus.startPC[0] != NULL) {
                     SetDlgItemText(hdlg, DLGSTARTPCNUM,
                                    (LPSTR) LdrStatus.startPC);
                  }
                  else {
                     SetDlgItemText(hdlg, DLGSTARTPCNUM, (LPSTR) "Unknown");
                  }
                  
                  SetDlgItemText(hdlg, DLGSTACKBASE, (LPSTR) "Stack Base:");
                  if (LdrStatus.stackBase[0] != NULL) {
                     SetDlgItemText(hdlg, DLGSTACKBASENUM,
                                    (LPSTR) LdrStatus.stackBase);
                  }
                  else {
                     SetDlgItemText(hdlg, DLGSTACKBASENUM, (LPSTR) "Unknown");
                  }
                  
                  SetDlgItemText(hdlg, DLGSTACKSIZE, (LPSTR) "Stack Size:");
                  if (LdrStatus.stackSize[0] != NULL) {
                     SetDlgItemText(hdlg, DLGSTACKSIZENUM,
                                    (LPSTR) LdrStatus.stackSize);
                  }
                  else {
                     SetDlgItemText(hdlg, DLGSTACKSIZENUM, (LPSTR) "Unknown");
                  }
                  SetDlgItemText(hdlg, DLGMODULE, (LPSTR) " ");
                  SetDlgItemText(hdlg, IDCANCEL, (LPSTR) "&OK");
                  EnableWindow(hHelpButton, TRUE);
               }
               else {
                  /* See if the Cancel button has been sent a buttondown */
                  if (PeekMessage((LPMSG) &msg, hCancelButton, WM_LBUTTONDOWN, 
                        WM_LBUTTONUP, PM_REMOVE | PM_NOYIELD)) {
                     cancelButtonPressed = TRUE;
                  }
                  else if (PeekMessage((LPMSG) &msg, hCancelButton,
                                       WM_SYSKEYDOWN, WM_SYSKEYDOWN,
                                       PM_REMOVE | PM_NOYIELD)) {
                     /*
                      * The reason for using WM_SYSKEYDOWN rather than
                      * WM_SYSCHAR is that I don't think WM_SYSCHAR is
                      * generated under these circumstances.  (Doesn't
                      * happen under tdw, at least.)
                      */
                     if(msg.wParam == VK_MENU) {
                        cancelButtonPressed = TRUE;
                     }
                  }
                  if (PeekMessage((LPMSG) &msg, hCancelButton, WM_KEYDOWN, 
                        WM_KEYDOWN, PM_REMOVE | PM_NOYIELD)) {
                     if (msg.wParam == VK_RETURN) {
                        cancelButtonPressed = TRUE;
                     }
                  }
               }
            }
            else if (wParam == ID_PROGRESS_GO) {
               /* prevent re-entrancy (firewall) */
               if (!inThere) {
                  inThere = TRUE;
                  /*
                  ** Call the Specific Loader to load and save the return
                  ** error code for reporting.
                  */
                  if (LoaderServer && callBackFn)
                     loadErr = callBackFn(
                                (LPSTR)LoaderServer->LastLoadFileName(),
                                LoaderServer->LastLoadOptions(),
                                LoaderServer->LastParentHwnd(),
                                LoaderServer->LastLoadSpace());
                  inThere = FALSE;
               }
            }
            break;
    }
    return (FALSE);
} /* LdrProgressDlgProc() */

/*************************************************************************--
**  LdrInfoDlgProc
**
**  Purpose:
**     Load Information dialog procedure for PowerViews.  This is a much
**  simplified version of the above -- the only difference in the dialogs
**  is that this one doesn't have a gauge control and doesn't have a
**  current module.
**
**  Input:
**     hDlg:  The window handle.
**     uMsg:  The current message.
**     wParam:  The word message param.
**     lParam:  The long message param.
**
**  Output:
**     none.
***************************************************************************-*/
#pragma argsused
BOOL FAR PASCAL LdrInfoDlgProc(HANDLE hdlg, WORD uMsg, WORD wParam,
                               LONG lParam) {
    switch (uMsg) {
        case WM_INITDIALOG:
           if (IsLoadSymbol(LoaderServer->LastLoadOptions()))
              SymGetLdrStats((LPSTR)&(LdrStatus.curModule),
                     (U32 FAR *)(&LdrStatus.numSymbols),
                     (U16 FAR *)(&LdrStatus.numModules),
                     (U32 FAR *)(&LdrStatus.numTypes));
            SetDlgItemText(hdlg, DLGMODULES, (LPSTR) "Modules:");
            SetDlgItemText(hdlg, DLGBYTES,   (LPSTR) "Bytes:");
            SetDlgItemText(hdlg, DLGSYMBOLS, (LPSTR) "Symbols:");
            SetDlgItemText(hdlg, DLGLINES,   (LPSTR) "Lines:");
            if (lstrlen(LdrStatus.curLoadFile) > 0) {
               sprintf(buf1, "%s", LdrStatus.curLoadFile);
               SetDlgItemText(hdlg, DLGLOADFILE, (LPSTR) buf1);
            }
            sprintf(buf1, "%d", LdrStatus.numModules);
            SetDlgItemText(hdlg, DLGMODULESLOADED, (LPSTR) buf1);
            sprintf(buf1, "%ld", LdrStatus.numBytes);
            SetDlgItemText(hdlg, DLGBYTESLOADED, (LPSTR) buf1);
            sprintf(buf1, "%ld", LdrStatus.numSymbols);
            SetDlgItemText(hdlg, DLGSYMBOLSLOADED, (LPSTR) buf1);
            sprintf(buf1, "%ld", LdrStatus.numTypes);
            SetDlgItemText(hdlg, DLGTYPESLOADED, (LPSTR) buf1);
            sprintf(buf1, "%ld", LdrStatus.numFunctions);
            SetDlgItemText(hdlg, DLGFUNCSLOADED, (LPSTR) buf1);
            sprintf(buf1, "%ld", LdrStatus.numLines);
            SetDlgItemText(hdlg, DLGLINESLOADED, (LPSTR) buf1);
            SetDlgItemText(hdlg, DLGSTARTPC, (LPSTR) "PC:");
            if (LdrStatus.startPC[0] != NULL) {
               SetDlgItemText(hdlg, DLGSTARTPCNUM,
                              (LPSTR) LdrStatus.startPC);
            }
            else {
               SetDlgItemText(hdlg, DLGSTARTPCNUM, (LPSTR) "Unknown");
            }
            SetDlgItemText(hdlg, DLGSTACKBASE, (LPSTR) "Stack Base:");
            if (LdrStatus.stackBase[0] != NULL) {
               SetDlgItemText(hdlg, DLGSTACKBASENUM,
                              (LPSTR) LdrStatus.stackBase);
            }
            else {
               SetDlgItemText(hdlg, DLGSTACKBASENUM, (LPSTR) "Unknown");
            }
            SetDlgItemText(hdlg, DLGSTACKSIZE, (LPSTR) "Stack Size:");
            if (LdrStatus.stackSize[0] != NULL) {
               SetDlgItemText(hdlg, DLGSTACKSIZENUM,
                              (LPSTR) LdrStatus.stackSize);
            }
            else {
               SetDlgItemText(hdlg, DLGSTACKSIZENUM, (LPSTR) "Unknown");
            }
            SetDlgItemText(hdlg, DLGMODULE, (LPSTR) " ");
            SetDlgItemText(hdlg, IDCANCEL, (LPSTR) "&OK");

            break;

        case WM_COMMAND:
            if ((wParam == IDOK) || (wParam == IDCANCEL)) {
                EndDialog(hdlg, (wParam == IDOK));
                return (TRUE);
            }
            else if (wParam == IDHELP) {
               WinHelp(hdlg, "PWRVIEWS.HLP",
                  HELP_CONTEXT, HE_LOAD_INFO);
               return (TRUE);
            } 
            break;
    }
    return (FALSE);
} /* LdrInfoDlgProc() */

/******************************** E O F *************************************/
