/****************************************************************************
**
**  Name:  ERRTEXT.C
**
**  Description:
**      Entry points for errtext.dll.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_186/errtext/errtext.c_v  $
** 
**    Rev 1.0   16 Dec 1996 14:29:32   Judy
** Initial revision.
** 
**    Rev 1.38   10 Jun 1994 17:26:26   nghia
** Added check for reported error. Use E_NO_ERROR bit.
** 
**    Rev 1.37   06 Oct 1993 16:36:12   tom
** 8802, 8929: display memory verify info with memory verify error
** 
**    Rev 1.36   28 Jul 1993 13:37:28   ron
** fix for _getallErrors
** 
**    Rev 1.35   21 Jul 1993 11:23:42   ron
** ppr8450: make error numbers and error types consistent: use error numbers
** for either INTERNAL errors or when reportErrCodes is TRUE.
** 
**    Rev 1.34   19 Jul 1993 13:31:04   ron
** Needed to compare only the error id portion of the error code.
** 
**    Rev 1.33   16 Jul 1993 16:41:46   ernie
** Fixed bug in ErrDisplayString().  The upper bits of errCode were being
** stripped off too early--before the severity code was checked!
** 
**    Rev 1.32   16 Jul 1993 08:58:00   tom
** ppr 8368: remove timestamp on critical errors
** 
**    Rev 1.31   28 Jun 1993 14:55:38   ron
** Forgot to take the newlines out of the ErrErrNumberCLI strings (they made
** funny black boxes in the shell window).
** 
**    Rev 1.30   28 Jun 1993 10:42:34   ron
** changes to get help buttons for all server errors
**
**    Rev 1.29   28 Jun 1993 08:41:34   paul
** Change CHECK_ABORT to TskCheckAbort (esc key detection)
**
**    Rev 1.28   09 Jun 1993 17:01:26   ron
** PIP: translate error codes to rc offsets and help entry points
**
**    Rev 1.27   03 Jun 1993 17:28:42   ron
** actor error consolidation change -- another one needed once the server
** changes are done.
**
**    Rev 1.26   03 Jun 1993 16:34:08   ron
** actor error consolidation -- working checkpoint
**
**    Rev 1.25   25 May 1993 16:59:58   ron
** Checking in to get into build.  Changes for Actor Error Consolidation
** have not been approved through code review, but I did test these changes,
** so that we could get the revised error codes into this build.
**
**    Rev 1.24   25 May 1993 09:39:32   nghia
** Revised functions to use STR_TEMPLATE and DISPLAYSTR_TEMPLATE.
** Removed "Cancel" button from ErrDisplayString().
**
**    Rev 1.23   26 Apr 1993 15:43:10   tom
** Added CLIULibrary for UNIX filename support.
**
**    Rev 1.22   13 Apr 1993 16:52:00   nghia
** Revised ErrorText server to return correct error when cannot find an error
** code.  (return ER_ERRCODE_NOT_FOUND) - The ER_NOT_FOUND should only be used
** when cannot find a file.  Fixed "File not Found" bug.
** Cleanup for coding standard.
**
**    Rev 1.21   23 Mar 1993 17:26:56   nghia
** Fixed ppr7979 - "error msg" (####)"symbol" -> "error msg symbol" (####).
**
**    Rev 1.20   16 Dec 1992 12:31:26   doug
** put error number at the end of the line in parenthesis
**
**    Rev 1.19   02 Dec 1992 07:40:42   doug
** Caption box now says PowerViews, not the server string resource text
**
**    Rev 1.18   22 Oct 1992 16:53:46   courtney
** Check for alternate loader, if so then use generic loader
** string resource for error strings.
**
**    Rev 1.17   16 Oct 1992 17:05:00   courtney
** For ErrGetAllErrors, the error offset was not subtracted from
** the error number, when printed.  Fixed.
**
**    Rev 1.16   25 Sep 1992 18:12:38   courtney
** Cleanup timestamp code.
**
**    Rev 1.15   22 Sep 1992 16:54:38   courtney
** Add timestamp when severe error box is displayed.
**
**    Rev 1.14   30 Aug 1992 14:57:54   courtney
** Make message box system-modal for severe errors (so Animate mode
** will not continue).
**
**    Rev 1.13   29 Aug 1992 14:01:12   courtney
** Remember to free memory for each allocation!  Fixed ErrDisplayString -
** add box caption (server name), and add usual error text (and cat on
** user-specified text).  Try making ErrDisplay message box TASKMODAL
** (doesn't help).
**
**    Rev 1.12   27 Aug 1992 12:50:46   courtney
** Updated ErrGetAllErrors to display hex error code as well as text
** for each item.  ErrGetErrorText will strip off severity bits, so
** that documentation can be numericized (severity should already
** be indicated by appropriate icon displayed in message box).
**
**    Rev 1.11   24 Aug 1992 20:30:24   courtney
** Display error code in hex-upper case.
**
**    Rev 1.10   20 Aug 1992 17:14:50   courtney
** Consolidate code, remove gotos.
** Revise error text to final format.
** Add caption (from server resource file) to message box in ErrDisplayError.
** Increase MAX_ERRORS for sdserver resource file.
**
**    Rev 1.9   14 Aug 1992 17:20:04   courtney
** New entry point ErrGetAllErrors, for getting all errors from all
** servers from the CLI.  InitCServer has been updated to new style
** (tom forgot this one so I had to do it myself ;) ).
**
**    Rev 1.8   11 Aug 1992 18:06:48   courtney
** Added new entry points, ErrDisplayErrorEx, and ErrGetAllErrors.
**
**    Rev 1.7   30 Jul 1992 18:41:44   brucea
** Put back GlobalAlloc; adde GlobalUnlock and GlobalFree at end of each function
**
**    Rev 1.6   28 Jul 1992 11:45:54   brucea
** Removed: unused variables
** Removed: places where significance would be lost without explicit casting
**
**    Rev 1.5   28 Jul 1992 09:33:26   brucea
** Fixed bug: ErrGetErrorText was not freeing Global alloc'ed memory
** Changed: replaced GlobalAlloc with TMalloc and added TFree at closing of
**    function
** Changed: error output to first display DLL name, then message, then full
**    hex error number
**
**    Rev 1.4   18 May 1992 08:43:12   mindy
** a) GetModule was always failing.
** b) status was always returning ER_RESLOAD
**
**    Rev 1.3   14 May 1992 13:03:22   courtney
** Created errTable for server registration info (dllName, module ID
** (hosterrs.h style).
** ModuleID now kept as U32.
** No more calls to server xxxGetErrorText, rather the string resource
** of the indicated module is accessed directly.
** Added ErrInitDLL for server registration.
**
**    Rev 1.2   13 May 1992 17:20:46   courtney
** Nice formatting of return string with error code embedded,
** revised spelling of SdatGetErrorText.
**
**    Rev 1.1   13 May 1992 16:04:52   courtney
** Added ErrDisplayError routine.
**
**    Rev 1.0   12 May 1992 17:16:20   courtney
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/errtext/errtext.c_v   1.0   16 Dec 1996 14:29:32   Judy  $
**
**  Copyright (C) 1992 Microtek International.  All rights reserved.
**
*****************************************************************************/


                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _BASEWIND_
#include "basewind.h"
#endif
#include <stdio.h>
#include <string.h>

#ifndef _CLISRV_
#include "clisrv.h"
#endif
#ifndef _CLIULIB_
#include "cliulib.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _ERRTEXT_
#include "errtext.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _ERRCODEC_
#include "errcodec.h"
#endif
#ifndef _ERRTRANS_
#include "errtrans.h"
#endif

#ifndef _PVTASK_
#include "pvtask.h"
#endif


                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/


HANDLE cliServerHandle;
HANDLE dllServerHandle;
BOOL   reportErrCodes = FALSE;

/* Static array of module information for error text.  Each element
   is constructed when ErrInitDLL is called for that component */
typedef struct {
    S8 dllName[FILELEN];  /* no path */
    U32 moduleID;         /* upper bits from hosterrs.h */
}  ERR_INFO;


ERR_INFO errTable[MAX_MODULES];

/* these values serve as indices to errTable */
enum MODTYPE {MOD_LOCAL, MOD_HEAP, MOD_SYM, MOD_ADDR, MOD_BREAK, MOD_CPU,
    MOD_DASM, MOD_EVENT, MOD_TEMPLATE, MOD_LDR, MOD_LDROMF, MOD_MEM, MOD_SDS,
    MOD_STACK, MOD_SWAT, MOD_TRACE, MOD_TRIG, MOD_VAR, MOD_LDRSREC, MOD_LDRTEK,
    MOD_MAP, MOD_ENLIB, MOD_WSCOM, MOD_BKROOT, MOD_CLIULIB
} modtype;

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
S16 ErrSendMessageToCLI(CHAR *);
PRIVATE S16 GetModule(U32);
HANDLE ErrLookupModule(U16 moduleID);
                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/* Note on memory allocation.  All error text retrieved is loaded into
   a newly globally allocated buffer.  By being global, it can be passed
   to the CLI.  A single static buffer won't work because it will get
   overwritten when more than a single message box is up (and probably
   crash Windows).
*/


/****************************************************************************
**
** GetErrorComponents
**
*****************************************************************************/
RETCODE GetErrorComponents(RETCODE *errorCode, LPSTR lperrStr) {
    U32 moduleID;
    U16 errorID;
    HANDLE hModule;
    U16 localErrorID;
    U16 transOffset;
    U16 maxTransOffset;

    /* range check on module ID now extends to dynamically created
       module ID's */
    /* We check only those known to the system */
    if (!errorCode)
        return (ER_ERCODE_NOT_FOUND);
    if ((errorCode != NULL) && !(IS_VALIDMODULE(*errorCode)))
        return (ER_ERCODE_NOT_FOUND);
    errorID = E_ERRORID(*errorCode);
    moduleID = E_MODULEID(*errorCode);

    /* these two are both found locally in this dll */
    if (moduleID == (MODULE_GENERIC >> 16))
        moduleID = MODULE_SYSTEM;

    /* All system loaders take their messages from the 695 loader (aka
       generic loader)'s string resource.  They do retain their own
       unique caption, however.  Check here for alternate loaders.
    */
    if (IS_LOADERID(moduleID)) {
        moduleID = MODULE_GENERIC_LDR >> 16;
        /* patch in documented error code (module ID) */
        *errorCode &= ~E_COMPONENT_MASK;
        *errorCode |= MODULE_GENERIC_LDR;
    }
    lperrStr[0] = '\0';

    /* get error text from indicated module */
    /* now goes directly to resource for indicated module */
    /* generic and system module errors are found here, in our string resource */
    if ((hModule = ErrLookupModule(moduleID)) == NULL) {
       return (ER_ERCODE_NOT_FOUND);
    }
    /* The automatically generated header file "errtrans.h" includes an
     * array of structs that translate error codes to offsets in errtext.rc
     */
    maxTransOffset = MAX_ERR_TRANS;
    for (transOffset = 0; transOffset < maxTransOffset; transOffset++) {
       if (E_ERRORID(ErrTranslation[transOffset].errcode) == errorID) {
          localErrorID = ErrTranslation[transOffset].offset;
          break;
       }
    }
    /* TEMPORARY PATCH!! (THE "ELSE" WILL BE REMOVED WHEN ALL SERVER ERRORS
     * ARE MOVED HERE!!) */
    if (transOffset < maxTransOffset) { /* found in errtext.rc */
       if (LoadString(hModule, localErrorID, lperrStr, E_ERRSIZE) == 0) {
          return (ER_RESLOAD);
       }
    }
    else if (LoadString(hModule, errorID+E_ERRTEXT_OFFSET, lperrStr, E_ERRSIZE) == 0) {
       return (ER_RESLOAD);
    }
    /* strip off leading severity bits, so that codes can be numericized
       for documentation. */
    *errorCode &= ~E_SEVERITY_MASK;
    return (GOOD);
} /* GetErrorComponents */

/*****************************************************************************
** ErrGetErrorText
**
**  Retrieve error text.  The *caller* is expected to have allocated
**  storage for the return string of size E_ERRSIZE.
*****************************************************************************/
RETCODE EXPORT ErrGetErrorText(RETCODE errorCode, LPSTR lperrString) {

   return(ErrGetFormattedErrorText(errorCode, lperrString,
      (LPSTR)"none", (LPSTR)"none", (LPSTR)"none"));
}  /* ErrGetErrorText */


/*****************************************************************************
**
** GetModule
**
** Given a module ID, return the index in errTable for it,
**    returns -1 if not found
**
*****************************************************************************/
PRIVATE S16 GetModule(U32 moduleID) {
    if( E_MODULEID(errTable[(U16)moduleID].moduleID) == moduleID )
       return (moduleID);
    return (-1);
}  /* GetModule */

/*****************************************************************************
**
** ErrLookupModule
**
** Given a module ID, return the handle for it,
**
*****************************************************************************/
HANDLE ErrLookupModule(U16 moduleID) {
    S16 errTableIndex;
    HANDLE hModule;

    if (moduleID == (MODULE_GENERIC >> 16))
        moduleID = MODULE_SYSTEM;
    if ((errTableIndex = GetModule(moduleID)) == -1)
        return (NULL);
    if ((hModule = GetModuleHandle(errTable[errTableIndex].dllName)) == NULL)
        return (NULL);

    return (hModule);
}  /* ErrLookupModule */

/*****************************************************************************
**
** ErrDisplayString -- OBSOLETE -- Use ErrDisplayFormattedError
**
** Add on caller-formatted string via display mode, along with usual
**   error text retrieved - allows caller to add additional information.
**
*****************************************************************************/
RETCODE EXPORT ErrDisplayString(RETCODE errCode, LPSTR lpErrMore,
                                                HANDLE_ERROR errDisplay) {
    HANDLE hErrText, hErrStr;
    LPSTR lpErrText, lpErrStr;
    HANDLE hCLIModule;
    U16 msgIcon;
    U32 severityID;
    U32 moduleID;
    DWORD helpEntry;
    S16 buttonID;
    RETCODE errNumber;

    /* 06/10/94 - Nghia
    ** If error code is already reported, just return
    ** Detect reported error
    */
    if (E_SEVERITYID(errCode) == E_NO_ERROR)
       return GOOD;
/*--------------------------------------------------------------------
** NOTE: GlobalAlloc used because of TMalloc load dependency problems
----------------------------------------------------------------------*/  
    if ((hErrText = GlobalAlloc(GHND, E_ERRSIZE)) == NULL)
        return (ER_OUT_OF_MEMORY);
    if ((lpErrText = (LPSTR)GlobalLock(hErrText)) == NULL) {
       GlobalFree(hErrText);
       return (ER_WINDOWS_MEMLOCK);
    }
    errNumber = errCode;
    if (GetErrorComponents(&errNumber, lpErrText) != GOOD) {
        GlobalFree(hErrText);
        return (ER_ERCODE_NOT_FOUND);
    }
    /* Allocate the second buffer */
    if ((hErrStr = GlobalAlloc(GHND, E_ERRSIZE)) == NULL) {
       GlobalFree(hErrText);
       return(ER_OUT_OF_MEMORY);
    }
    if ((lpErrStr = (LPSTR)GlobalLock(hErrStr)) == NULL) {
       GlobalFree(hErrText); GlobalFree(hErrStr);
       return(ER_WINDOWS_MEMLOCK);
    }
    ErrErrorToHelp(errNumber, &helpEntry);

    severityID = errCode & E_SEVERITY_MASK;
    /* now decide where to display */
    if (errDisplay == CHECK_MODE)
        CLIGetActive(&hCLIModule);
    if (errDisplay == FORCE_POPUP ||
        (errDisplay == CHECK_MODE && hCLIModule == NULL)) {
       /* Format Error message - Select template */
       if (INTERNAL_ERROR(errCode)) {
          sprintf(lpErrStr, I_DISPLAYSTR_TEMPLATE, lpErrText, lpErrMore, errCode);
       }
       else if (reportErrCodes) {
          sprintf(lpErrStr, DISPLAYSTR_TEMPLATE_WITH_CODE, lpErrText, lpErrMore, errCode);
       }
       else {
          sprintf(lpErrStr, DISPLAYSTR_TEMPLATE, lpErrText, lpErrMore);
       }
       /* decide which cute icon to use if message box */
       msgIcon = MB_OK;
       if (severityID == E_WARNING)
          msgIcon |= MB_ICONEXCLAMATION;
       else  /* severe/fatal/catastrophic */
          msgIcon |= MB_ICONSTOP;
       /* get module ID for caption */
       moduleID = E_MODULEID(errCode);
       if (ErrLookupModule(moduleID) == NULL) {
          GlobalFree(hErrText); GlobalFree(hErrStr);
          return (ER_ERCODE_NOT_FOUND);
       }
       ErrMessageBox(ERROR_CAPTION, lpErrStr, msgIcon,
                             helpEntry, (S16 FAR *) &buttonID);
    } else {
       if (INTERNAL_ERROR(errCode)) {
          sprintf(lpErrStr, I_DISPLAYSTR_TEMPLATE, lpErrText, lpErrMore, errCode);
       }
       else if (reportErrCodes) {
          sprintf(lpErrStr, DISPLAYSTR_TEMPLATE_WITH_CODE, lpErrText, lpErrMore, errCode);
       }
       else {
          sprintf(lpErrStr, DISPLAYSTR_TEMPLATE, lpErrText, lpErrMore);
       }
       ErrSendMessageToCLI(lpErrStr);
    }
    GlobalFree(hErrText); GlobalFree(hErrStr);
    return (GOOD);
}  /* ErrDisplayString */

/*****************************************************************************
**
** ErrDisplayError -- NOW OBSOLETE -- use ErrDisplayFormattedError
**
*****************************************************************************/
RETCODE EXPORT ErrDisplayError(RETCODE errCode, HANDLE_ERROR errDisplay) {
   S16 buttonID;

   return (ErrDisplayFormattedError(errCode, errDisplay, 
      (LPSTR) "(none)", (LPSTR) "(none)", (LPSTR) "(none)",
      MB_OK, (S16 FAR *) &buttonID));

}  /* ErrDisplayError */

/*****************************************************************************
**
** ErrDisplayErrorEx -- NOW OBSOLETE -- Use ErrDisplayFormattedError
**
*****************************************************************************/
RETCODE EXPORT ErrDisplayErrorEx(RETCODE errCode, HANDLE_ERROR errDisplay,
   MB_TYPE msgBoxStyle, S16 FAR *buttonID) {

   return (ErrDisplayFormattedError(errCode, errDisplay, 
      (LPSTR) "(none)", (LPSTR) "(none)", (LPSTR) "(none)",
      msgBoxStyle, buttonID));

}  /* ErrDisplayErrorEx */


/****************************************************************************
**
** LocalGetErrorText
**
** Description:
**    Retrieve the error text for generic messages
**
** Parameters:
**    input:
**       errorID:  error portion of return code.
**    output:
**       errText:  error text retrieved (allocated by caller)
**
******************************************************************************/
RETCODE LocalGetErrorText(RETCODE errorID, LPSTR errText) {
    HANDLE hModule;
    U16 nbytes;

    /* note: cli has not necessarily been initialized, so we need to explicitly
       retrieve the dll handle */
    hModule = GetModuleHandle("errtext.dll");
    nbytes = LoadString(hModule, (U16)(errorID + E_ERRTEXT_OFFSET),
                        errText, (S16)E_ERRSIZE);
    if (nbytes == 0)
        return (ER_RESLOAD);

    return(GOOD);
}  /* LocalGetErrorText */

/*****************************************************************************
**
** ErrGetAllErrors
**
** Dump all errors to CLI (for all Servers registered with Error Text Server)
**
*****************************************************************************/
RETCODE EXPORT ErrGetAllErrors(VOID) {
   /* have parm indicating route to CLI or print to file */
   /* is there a way to 'silently log' to the CLI (without updating the display,
      but just write to a logfile?) */
   /* may also want parm to just dump errors for a particular module (for
    internal use) */
    U16 errorID;
    HANDLE hErrBuf;
    LPSTR lperrBuf;
    HANDLE hModule;
    S16 index;
    static char errbuf[E_ERRSIZE];
    RETCODE errorCode;
    RETCODE err;
    BOOLEAN   abortFromEsc;


    if ((hErrBuf = GlobalAlloc(GHND, E_ERRSIZE)) == NULL)
        return (ER_OUT_OF_MEMORY);
    if ((lperrBuf = (LPSTR)GlobalLock(hErrBuf)) == NULL)
        return (ER_WINDOWS_MEMLOCK);

   /* set initial state for user-abort checking */
      err = TskCheckAbort(&abortFromEsc);
      if(err!=GOOD) return err;


    hModule = GetModuleHandle("errtext.dll");
    for (index = 0; index < MAX_ERR_TRANS; index++) {
        errorID = ErrTranslation[index].offset;
        errorCode = ErrTranslation[index].errcode;
        if (LoadString(hModule, errorID, lperrBuf, E_ERRSIZE) == 0) {
           continue;
        }
        if (INTERNAL_ERROR(errorCode)) {
           sprintf(errbuf, "%s (%lX) [INTERNAL]", lperrBuf, errorCode);
        } else {
           sprintf(errbuf, "%s (%lX)", lperrBuf, errorCode);
        }
        /* need to copy into global-alloced buffer for CLI */
        lstrcpy((LPSTR)lperrBuf, (LPSTR)errbuf);
        ErrSendMessageToCLI(lperrBuf);

        err = TskCheckAbort(&abortFromEsc);
        if(err!=GOOD) return err;
        if (abortFromEsc!=0)
           break;
     }
    GlobalFree(hErrBuf);

    return (GOOD);
}  /* ErrGetAllErrors */


/**************************************************************************
**
** InitCServer
**
***************************************************************************/
RETCODE EXPORT InitCServer(HANDLE cliHandle, HANDLE dllHandle) {
   HANDLE hmsgBuf;
   CSERVER_NEW_REGISTRATION FAR * msgBufPtr;

   cliServerHandle = cliHandle;
   dllServerHandle = dllHandle;
   hmsgBuf = GlobalAlloc(GHND, sizeof(CSERVER_VARIABLE_VALUE));
   if (hmsgBuf == NULL)
        return (ER_OUT_OF_MEMORY);
   if ((msgBufPtr = (CSERVER_NEW_REGISTRATION FAR *)GlobalLock(hmsgBuf)) == NULL)
        return (ER_WINDOWS_MEMLOCK);

   msgBufPtr->stringResourceHandle = dllHandle;

   msgBufPtr->serverNameIndex = 30;
   msgBufPtr->dllNameIndex = 31;
   msgBufPtr->numberOfCommandsIndex = 32;
   msgBufPtr->commandStartIndex = 33;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);

   return(GOOD);
}  /* InitCServer */


/*****************************************************************************
**
** ErrSendMessageToCLI
**
*****************************************************************************/
S16 ErrSendMessageToCLI(CHAR *s) {
   GLOBALHANDLE hmsgBuf;
   CSERVER_RESULTS FAR *lpmsgBuf;
   U16 msgLength;
   U32 err;
    LOOP_VAR i;

/* it certainly does seem redundant to already have a global-alloced buffer,
   then have to copy it into *another* global-alloc'ed buffer just so it
   is contiguous with the rest of this structure!!
*/
   msgLength = lstrlen(s);
   if ((hmsgBuf = GlobalAlloc(GHND, sizeof(CSERVER_RESULTS)+msgLength+1)) == NULL) {
      return (ER_OUT_OF_MEMORY);
   }
   lpmsgBuf = (CSERVER_RESULTS FAR *)GlobalLock(hmsgBuf);

   lpmsgBuf->target = 0;
   lpmsgBuf->variantCode = CLI_SERVER_RESULTS;
   lpmsgBuf->resultTextLength = msgLength;
   for (i=0; i<msgLength; i++)
      lpmsgBuf->messageText[i] = *s++;
   lpmsgBuf->messageText[i] = '\0';

   err = SendMessage(cliServerHandle, CLI_SERVER_RESULTS, hmsgBuf,
      (DWORD)CLI_SERVER_RESULTS);

   return (err);
}  /* ErrSendMessageToCLI */

/*****************************************************************************
**
** ErrInitDLL
**
** Each server component will call this routine when it is loaded (LibMain).
** As new components may be added dynamically to extend the system without
** an entire rebuild, they should take module ID's that sequentially follow
** those defined in hosterrs.h
**
*****************************************************************************/
RETCODE EXPORT ErrInitDLL(U32 moduleID, LPSTR dllName) {
    U16 i;  /* index to errTable */

    if ((i = E_MODULEID(moduleID)) > MAX_MODULES) {
        ErrDisplayError(ER_BADMODULE, FORCE_POPUP);
        return (ER_BADMODULE);
    }
    /* capture dllName and moduleID into static table */
    lstrcpy((LPSTR)errTable[i].dllName, dllName);
    /* full moduleID as in hosterrs.h */
    errTable[i].moduleID = moduleID;

    return (GOOD);
}  /* ErrInitDLL */

/***************************************************************************
**
**  ErrGetErrorCLI
**
**  Status:  TESTED
**
**  description:
**     _geterror code to print description of an error code.
**
**  input:
**     cmdString:  input text
**     argc:  argument count
**     argv:  offsets into cmdString where arguments start
**
**  output:
**     none
**
*****************************************************************************/
RETCODE EXPORT  ErrGetErrorCLI(LPSTR cmdString, U32 argc, U32 argv[]) {
   LPSTR errCodeStr;
   RETCODE errorCode;
   HANDLE hErrText;
   LPSTR lpErrText;
   U16 ind;

   if (argc != 2)
      return (ER_ERCODE_NOT_FOUND);
   ind = (U16) argv[1];
   errCodeStr = (LPSTR) &(cmdString[ind]);
   if ((sscanf(errCodeStr,"0x%lX", &errorCode) != 1) &&
       (sscanf(errCodeStr,"%ld", &errorCode) != 1))
      return (ER_ERCODE_NOT_FOUND);
   if ((hErrText = GlobalAlloc(GHND, E_ERRSIZE)) == NULL)
      return (ER_OUT_OF_MEMORY);
   if ((lpErrText = (LPSTR)GlobalLock(hErrText)) == NULL) {
      GlobalFree(hErrText);
      return (ER_WINDOWS_MEMLOCK);
   }
   if (ErrGetErrorText(errorCode, lpErrText) != GOOD) {
      return (ER_ERCODE_NOT_FOUND);
   }
   ErrSendMessageToCLI(lpErrText);
   GlobalUnlock(hErrText);
   GlobalFree(hErrText);
   return (GOOD);
}

/***************************************************************************
**
**  ErrErrNumberCLI
**
**  Status:  TESTED
**
**  description:
**     _errnumber [on|off] to display (no parameters) or set error
**     numbers as part of error messages on or off.
**
**  input:
**     cmdString:  input text
**     argc:  argument count
**     argv:  offsets into cmdString where arguments start
**
**  output:
**     none
**
*****************************************************************************/
RETCODE EXPORT  ErrErrNumberCLI(LPSTR cmdString, U32 argc, U32 argv[]) {
   HANDLE hErrText;
   LPSTR lpErrText;

   if (argc > 2)
      return (ER_ERCODE_NOT_FOUND);
   if ((hErrText = GlobalAlloc(GHND, E_ERRSIZE)) == NULL)
      return (ER_OUT_OF_MEMORY);
   if ((lpErrText = (LPSTR)GlobalLock(hErrText)) == NULL) {
      GlobalFree(hErrText);
      return (ER_WINDOWS_MEMLOCK);
   }
   if (argc == 1) { /* just print out the current state */
      if (reportErrCodes) {
         lstrcpy(lpErrText, (LPSTR)"Error code reporting is ON.");
      }
      else {
         lstrcpy(lpErrText, (LPSTR)"Error code reporting is OFF.");
      }
   }
   else {
      if(strncmpi(&cmdString[(int)argv[1]], "on",
            strlen(&cmdString[(int)argv[1]]))==0) {
         reportErrCodes = TRUE;
         lstrcpy(lpErrText, (LPSTR)"Error code reporting turned ON.");
      }
      else {
         reportErrCodes = FALSE;
         lstrcpy(lpErrText, (LPSTR)"Error code reporting turned OFF.");
      }
   }
   ErrSendMessageToCLI(lpErrText);
   GlobalUnlock(hErrText);
   GlobalFree(hErrText);
   return (GOOD);
}

/************************************EOF************************************/
