home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.alaska-software.com
/
2014.06.ftp.alaska-software.com.tar
/
ftp.alaska-software.com
/
acsn
/
XPPTRIS11E.ZIP
/
XPPERROR.PRG
< prev
next >
Wrap
Text File
|
2007-08-11
|
19KB
|
617 lines
*+▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
*+
*+ Source Module => D:\ALASKA\1\XPPERROR.PRG
*+
*+ Functions: Procedure ErrorSys()
*+ Static Function StandardEH()
*+ Static Function ErrorMessage()
*+ Static Procedure ErrorLog()
*+ Function LineSplit()
*+ Procedure DLLLIST()
*+
*+ Reformatted by Click! 2.03a on Aug-11-2007 at 7:56 pm
*+
*+▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
//////////////////////////////////////////////////////////////////////
//
// ERRORSYS.PRG
//
// Copyright:
// Alaska Software, (c) 1997-2005. All rights reserved.
//
// Contents:
// Install default error code block
//
// Remarks:
// Function ErrorSys() is always called at program startup
//
//////////////////////////////////////////////////////////////////////
#include "Xbp.ch"
#include "Error.ch"
#include "OS.ch"
#include "Dmlb.ch"
#include "DbfDbe.ch"
#include "dll.ch"
#include "Directry.ch"
*#define DEBUG
***********************************
* Name of error log without extension
***********************************
#define EHS_ERRORLOG "XPPERROR"
/*
* language specific string constant which are used in the error handler
*/
#define EHS_CANCEL "Cancel"
#define EHS_EXIT_WITH_LOG "Exit with LOG file"
#define EHS_RETRY "Retry"
#define EHS_IGNORE "Ignore"
#define EHS_OS_ERROR ";Operating system error : "
#define EHS_CALLED_FROM "Called from"
#define EHS_XPP_ERROR_MESSAGE "Xbase++ Error Message"
#define EHS_ERROR "Error "
#define EHS_WARNING "Warning "
#define EHS_DESCRIPTION ";Description : "
#define EHS_FILE ";File : "
#define EHS_OPERATION ";Operation : "
#define EHS_LOG_OPEN_FAILED "Unable to open error log file"
#define EHS_ERROR_LOG_OF "ERROR LOG of "
#define EHS_DATE " Date:"
#define EHS_XPP_VERSION "Xbase++ version :"
#define EHS_OS_VERSION "Operating system :"
#define EHS_LOG_WRITTEN_TO(cFile) "Error log was written to the file "+ cFile
MEMVAR ZPATH
MEMVAR ID_USER
MEMVAR ID_VERSION
***********************************
* Install default error code block
***********************************
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
*+ Procedure ErrorSys()
*+
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
PROCEDURE ErrorSys()
ERRORBLOCK( { | o | StandardEH( o ) } )
RETURN
*************************************
* Default error handler function
*************************************
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
*+ Static Function StandardEH()
*+
*+ Called from ( xpperror.prg ) 1 - procedure errorsys()
*+
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
STATIC FUNCTION StandardEH( oError )
LOCAL i, cMessage, aOptions, nOption, nSeverity
LOCAL row, col
LOCAL oDacSession, oSession
/* Check if error is handled automatically */
DO CASE
/* Division by zero results in 0 */
CASE oError:genCode == XPP_ERR_ZERODIV
RETURN 0
/* Error opening a file on a network */
CASE oError:genCode == XPP_ERR_OPEN .AND. ;
oError:osCode == 32 .AND. ;
oError:canDefault
RETURN ( .F. )
/* No lock is set */
CASE oError:genCode == XPP_ERR_APPENDLOCK .AND. ;
oError:canDefault
RETURN ( .F. )
ENDCASE
oSession := DbSession()
IF oSession = NIL .AND. IsFunction( "DacSession", FUNC_CLASS )
oDacSession := &( "DacSession()" )
oSession := oDacSession:getDefault()
ENDIF
IF oSession != NIL
IF oSession:getLastError() != 0
oError:cargo := { oError:cargo, ;
oSession:getLastError(), ;
oSession:getLastMessage() }
ENDIF
ENDIF
/* No default handling defined: create error message */
cMessage := ErrorMessage( oError )
/* Array for selection */
*#ifdef DEBUG
aOptions := { EHS_CANCEL, EHS_EXIT_WITH_LOG }
*#else
* aOptions := { EHS_CANCEL }
*#endif
IF oError:canRetry
* AAdd( aOptions, EHS_RETRY )
ENDIF
IF oError:canDefault
* AAdd( aOptions, EHS_IGNORE )
ENDIF
IF !EMPTY( oError:osCode )
cMessage += EHS_OS_ERROR + LTRIM( STR( oError:osCode ) ) + ;
";" + DosErrorMessage( oError:osCode )
ENDIF
IF AppType() <> APPTYPE_PM
/* Display Alert() Box possible ? */
IF SetAppWindow() != NIL
i := 0
row := ROW()
col := COL()
DO WHILE i == 0
i := ALERT( cMessage, aOptions )
ENDDO
SETPOS( row, col )
/* Perform selected option */
IF !EMPTY( i )
DO CASE
CASE aOptions[ i ] == EHS_IGNORE
RETURN .F.
CASE aOptions[ i ] == EHS_RETRY
RETURN .T.
CASE aOptions[ i ] == EHS_CANCEL
BREAK( oError )
CASE aOptions[ i ] == EHS_EXIT_WITH_LOG
ErrorLog( oError, 2 )
ENDCASE
ENDIF
ELSE
/* There is no console window */
*#ifdef DEBUG
ErrorLog( oError, 2 )
*#endif
ENDIF
/*
* Program can not or should not be continued
* Set error level and terminate program !
*/
ERRORLEVEL( 1 )
QUIT
ENDIF
IF oError:canDefault .AND. oError:canRetry
nOption := XBPMB_ABORTRETRYIGNORE
ELSEIF oError:canRetry
nOption := XBPMB_RETRYCANCEL
ELSEIF oError:canDefault
nOption := XBPMB_OKCANCEL
ELSE
nOption := XBPMB_CANCEL
ENDIF
/*
* Get Callstack from error object or gather it together.
*/
IF IsMethod( oError, "getCallstack" )
cMessage += oError:getCallstack( ";" )
ELSE
i := 1
DO WHILE !EMPTY( PROCNAME( ++ i ) )
cMessage += ";"
cMessage += EHS_CALLED_FROM + " "
cMessage += TRIM( PROCNAME( i ) )
cMessage += "(" + LTRIM( STR( PROCLINE( i ) ) ) + ")"
ENDDO
ENDIF
i := 0
/* select icon for ConfirmBox() */
DO CASE
CASE oError:severity == XPP_ES_FATAL
nSeverity := XBPMB_CRITICAL
CASE oError:severity == XPP_ES_ERROR
nSeverity := XBPMB_CRITICAL
CASE oError:severity == XPP_ES_WARNING
nSeverity := XBPMB_WARNING
OTHERWISE
nSeverity := XBPMB_INFORMATION
ENDCASE
/* Display ConfirmBox() */
i := ConfirmBox(, STRTRAN( cMessage, ";", CHR( 13 ) ), ;
EHS_XPP_ERROR_MESSAGE, ;
nOption, ;
nSeverity + XBPMB_APPMODAL + XBPMB_MOVEABLE )
DO CASE
CASE i == XBPMB_RET_RETRY
RETURN ( .T. )
CASE i == XBPMB_RET_IGNORE
RETURN ( .F. )
CASE i == XBPMB_RET_CANCEL
*#ifdef DEBUG
* IF ConfirmBox(, EHS_EXIT_WITH_LOG, EHS_XPP_ERROR_MESSAGE, XBPMB_YESNO,;
* XBPMB_WARNING+XBPMB_APPMODAL+XBPMB_MOVEABLE ) != XBPMB_RET_YES
* Break( oError )
*
* ENDIF
*#else
* Break( oError )
*#endif
ENDCASE
*#ifdef DEBUG
ErrorLog( oError, 2 )
*#endif
/* Set error level and terminate program ! */
ERRORLEVEL( 1 )
QUIT
RETURN .F. /* The compiler expects a return value */
***************************************
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
*+ Static Function ErrorMessage()
*+
*+ Called from ( xpperror.prg ) 1 - static function standardeh()
*+
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
STATIC FUNCTION ErrorMessage( oError )
*
* Creates a string with the important Informations
* from the error object
***************************************
/* Check if this is an error or warning message */
LOCAL cMessage := ;
IIF( oError:severity > XPP_ES_WARNING, ;
EHS_ERROR, EHS_WARNING )
/* Add name of subsystem or 'unkown subsytem' */
IF VALTYPE( oError:subSystem ) == "C"
cMessage += oError:subSystem
ELSE
cMessage += "????"
ENDIF
/* Add error code of subsystem */
IF VALTYPE( oError:subCode ) == "N"
cMessage += "/" + LTRIM( STR( oError:subCode ) )
ELSE
cMessage += "/????"
ENDIF
/* Optional: Add error description */
IF VALTYPE( oError:description ) == "C"
cMessage += EHS_DESCRIPTION + ;
oError:description
ENDIF
/* Optional: Add name of the file which were the error occured */
IF !EMPTY( oError:fileName )
cMessage += EHS_FILE + oError:fileName
ENDIF
/* Optional: Add name of the operation which caused the error */
IF !EMPTY( oError:operation )
cMessage += EHS_OPERATION + oError:operation
ENDIF
/* Add Thread ID of the thread on which the error occured */
cMessage += ";Thread ID : " + ;
LTRIM( STR( oError:thread ) )
IF VALTYPE( oError:cargo ) = "A" .AND. LEN( oError:cargo ) == 3
IF VALTYPE( oError:cargo[ 1 ] ) == "C"
cMessage += ";" + LineSplit( oError:cargo[ 1 ], 50 )
ENDIF
cMessage += ";" + LineSplit( oError:cargo[ 3 ], 50 )
ENDIF
RETURN cMessage
************************************************
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
*+ Static Procedure ErrorLog()
*+
*+ Called from ( xpperror.prg ) 3 - static function standardeh()
*+
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
STATIC PROCEDURE ErrorLog( oError, nStackStart )
*
* Creates a string with the important Informations
* from the error object
************************************************
LOCAL i := 0, bError := ERRORBLOCK( { | e | BREAK( e ) } )
LOCAL cErrorLog
LOCAL cExtension := "LOG"
LOCAL lPrint, lConsole, cAlternate, lAlternate, lExtra
LOCAL aWsl, nWSL, j
LOCAL aLock, nLock, k
/* Save current printer related settings, turn printer off */
lPrint := SET( _SET_PRINTER )
lConsole := SET( _SET_CONSOLE )
cAlternate := SET( _SET_ALTFILE )
lAlternate := SET( _SET_ALTERNATE )
lExtra := SET( _SET_EXTRA, .F. )
SET PRINTER OFF
SET CONSOLE ON
IF SetAppWindow() == NIL ;
.OR. .NOT. SetAppWindow() :isDerivedFrom( RootCrt() )
SET CONSOLE OFF
ENDIF
/* Trap errors that might occur while opening the ALTERNATE file */
DO WHILE .T.
cErrorLog := ZPATH + EHS_ERRORLOG + "." + cExtension
BEGIN SEQUENCE
SET ALTERNATE TO ( cErrorLog ) ADDITIVE
SET ALTERNATE ON
RECOVER
/*
* ALTERNATE file could not be opened:
* try other filename
*/
cExtension := PADL( ++ i, 3, "0" )
IF i > 999
IF AppType() <> APPTYPE_PM
TONE( 660, 5 )
? EHS_LOG_OPEN_FAILED
IF !SET( _SET_CONSOLE )
OUTERR( CHR( 10 ) + CHR( 13 ) + EHS_LOG_OPEN_FAILED )
ENDIF
ELSE
MsgBox( EHS_LOG_OPEN_FAILED )
ENDIF
ERRORLEVEL( 1 )
QUIT
ENDIF
LOOP
END SEQUENCE
EXIT
ENDDO
ERRORBLOCK( bError )
? REPLICATE( "-", 78 )
? EHS_ERROR_LOG_OF + ID_USER + " Ver." + ID_VERSION + ' "' + appName( .T. ) + '"' + EHS_DATE, DATE(), TIME()
?
? EHS_XPP_VERSION, VERSION() + "." + VERSION( 3 )
? EHS_OS_VERSION, OS()
? "Memory (RAM_AVAIL) :", LTRIM( STR( MEMORY( MEM_RAM_AVAIL ) / 1000 ) ) + " of " + LTRIM( STR( MEMORY( MEM_RAM_TOTAL ) / 1000 ) ) + " MB"
? "DiskSpace " + CurDrive() + ": :", LTRIM( STR( DISKSPACE( CurDrive() + ":" ) / 1000000 ) ) + " MB"
? "Alias() :", IF( USED(), ALIAS(), "leer" )
? "Recno() :", IF( USED(), LTRIM( STR( RECNO() ) ), "leer" )
? "Found() :", IF( FOUND(), "YES", "NO" )
? "NetError() :", IF( NETERR(), "YES !!!", "NO" )
? "Select() :", LTRIM( STR( SELECT() ) )
? "IndexOrd() :", LTRIM( STR( ORDNUMBER() ) )
IF ORDNUMBER() > 0
? "Indexfocus() :", ORDSETFOCUS()
? "Indexname() :", ORDNAME()
? "Indexkey() :", ORDKEY()
ENDIF
IF USED()
? "DBO_ALIAS :", DbInfo( DBO_ALIAS )
? "DBO_FILENAME :", DbInfo( DBO_FILENAME )
? "DBO_ORDERS :", LTRIM( STR( DbInfo( DBO_ORDERS ) ) )
? "DBO_RELATIONS :", LTRIM( STR( DbInfo( DBO_RELATIONS ) ) )
? "DBO_SHARED :", IF( DbInfo( DBO_SHARED ), "YES", "NO" )
? "DBO_REMOTE :", IF( DbInfo( DBO_REMOTE ), "YES", "NO" )
? "DBO_SERVER :", IF( DbInfo( DBO_SERVER ), "YES", "NO" )
? "DBO_DBENAME :", DbInfo( DBO_DBENAME )
? "BOF() :", IF( BOF(), "YES", "NO" )
? "EOF() :", IF( EOF(), "YES", "NO" )
ENDIF
aWSL := WorkSpaceList()
nWSL := LEN( aWSL )
? "WorkSpaceList :", ""
FOR j = 1 TO nWSL
? aWSL[ j ]
aLock := ( aWSL[ j ] )->( DBRLOCKLIST() )
nLock := LEN( aLock )
IF nLock > 0
FOR k = 1 TO nLock
IF k = 1
?? " : Record No. " + LTRIM( STR( aLock[ k ] ) )
ELSE
?? "," + LTRIM( STR( aLock[ k ] ) )
ENDIF
NEXT
?? " locked"
ELSE
?? " : NO Record locked"
ENDIF
NEXT
? REPLICATE( "-", 78 )
? ""
DLLLIST()
? ""
? REPLICATE( "-", 78 )
? "oError:args :"
IF VALTYPE( oError:Args ) == "A"
AEVAL( oError:Args, ;
{ | x, y | QOUT( SPACE( 9 ), "-> VALTYPE:", y := VALTYPE( x ) ), ;
IIF( y == "O", QQOUT( " CLASS:", x:className() ), ;
QQOUT( " VALUE:", Var2Char( x ) ) ) } )
ELSE
QOUT( SPACE( 10 ), "-> NIL" )
ENDIF
? "oError:canDefault :", oError:canDefault
? "oError:canRetry :", oError:canRetry
? "oError:canSubstitute:", oError:canSubstitute
? "oError:cargo :", oError:cargo
? "oError:description :", oError:description
? "oError:filename :", oError:filename
? "oError:genCode :", oError:genCode
? "oError:operation :", oError:operation
? "oError:osCode :", oError:osCode
? "oError:severity :", oError:severity
? "oError:subCode :", oError:subCode
? "oError:subSystem :", oError:subSystem
? "oError:thread :", oError:thread
? "oError:tries :", oError:tries
? REPLICATE( "-", 78 )
? "CALLSTACK:"
? REPLICATE( "-", 78 )
i := nStackStart
IF IsMethod( oError, "getCallstack" )
? oError:getCallstack( CHR( 13 ) + CHR( 10 ) )
ELSE
DO WHILE !EMPTY( PROCNAME( ++ i ) )
? EHS_CALLED_FROM, TRIM( PROCNAME( i ) ) + "(" + ;
LTRIM( STR( PROCLINE( i ) ) ) + ")"
ENDDO
ENDIF
?
SET ALTERNATE TO
SET ALTERNATE OFF
IF AppType() <> APPTYPE_PM
TONE( 660, 5 )
? EHS_LOG_WRITTEN_TO( cErrorLog )
IF !SET( _SET_CONSOLE )
OUTERR( CHR( 10 ) + CHR( 13 ) + EHS_LOG_WRITTEN_TO( cErrorLog ) )
ENDIF
ELSE
MsgBox( EHS_LOG_WRITTEN_TO( cErrorLog ) )
ENDIF
/* Restore previous settings */
SET( _SET_PRINTER, lPrint )
SET( _SET_CONSOLE, lConsole )
SET( _SET_ALTFILE, cAlternate )
SET( _SET_ALTERNATE, lAlternate )
SET( _SET_EXTRA, lExtra )
RETURN
/* Split large line for Alert()-box output */
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
*+ Function LineSplit()
*+
*+ Called from ( xpperror.prg ) 2 - static function errormessage()
*+
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
FUNCTION LineSplit( cMessage, nMaxCol )
LOCAL i
LOCAL cLines := ""
LOCAL nLines
nLines := MLCOUNT( cMessage, nMaxCol,, .T. )
FOR i := 1 TO nLines
cLines += RTRIM( MEMOLINE( cMessage, nMaxCol, i,, .T. ) ) + ";"
NEXT
IF cLines[ - 1 ] == ";"
cLines := LEFT( cLines, LEN( cLines ) - 1 )
ENDIF
RETURN cLines
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
*+ Procedure DLLLIST()
*+
*+ Called from ( xpperror.prg ) 1 - static procedure errorlog()
*+
*+▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
*+
PROCEDURE DLLLIST()
LOCAL I, J, DllName, hDll, aVersion, fVersion
LOCAL aDLLFiles := DIRECTORY( "*.DLL" )
LOCAL nCount := LEN( aDLLFiles )
LOCAL n, nSum, cTest
LOCAL DllList := {}
FOR n := 1 TO nCount
AADD( DllList, aDLLFiles[ n, F_NAME ] )
NEXT
FOR I := 1 TO LEN( DllList )
DllName := DllList[ I ]
IF DllInfo( DllName, DLL_INFO_LOADED )
hDll := DllInfo( DllName, DLL_INFO_HANDLE )
fVersion := LoadResource( 1, hDll, RES_VERSIONFIXED )
aVersion := LoadResource( 1, hDll, RES_VERSION )
* ? ""
* ? Replicate( "-", 78 )
* ? ""
* ? DllName
IF LEN( fVersion ) > 0
* ? "Product Version: "+ltrim(str(fVersion[RES_PRODVER_MS ]))+ltrim(str(fVersion[RES_PRODVER_LS ]))
* ? " File Version: "+ltrim(str(fVersion[RES_FILEVER_MS ]))+ltrim(str(fVersion[RES_FILEVER_LS ]))
* ? " File Time: "+ltrim(str(fVersion[RES_FILETIME_MS]))+ltrim(str(fVersion[RES_FILETIME_LS]))
ELSE
ENDIF
IF LEN( aVersion ) > 0
FOR J := 1 TO LEN( aVersion )
cTest := aVersion[ J ] [ RES_VERSION_KEY ]
DO CASE
CASE cTest = "CompanyName"
CASE cTest = "InternalName"
CASE cTest = "LegalCopyright"
CASE cTest = "OriginalFilename"
CASE cTest = "ProductName"
CASE cTest = "ProductVersion"
CASE cTest = "Comment"
CASE cTest = "FileVersion"
OTHERWISE
// FileDescription
* ? aVersion[J][RES_VERSION_KEY]+": "+aVersion[J][RES_VERSION_VALUE]
? DllName + ": " + aVersion[ J ] [ RES_VERSION_VALUE ]
ENDCASE
NEXT
ELSE
ENDIF
ENDIF
NEXT
RETURN
*+ EOF: XPPERROR.PRG