WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

Samples from Users
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Software Metering Example

Keywords:   software metering

Question:

Does anyone have an example of using Winbatch for Software Metering?

Answer:

Here's an app to meter applications that are offerred from an NT Server. Enjoy!
;----------------------------------------------------------------------
; SECTION: PdcMeter
;
; Written by Brad Adkins
; badkins@ix.netcom.com
;
; Language: WIL - Windows Interface Language
; Compiler: WinBatch Compiler, Version 97D (2.4dbp)
;
; Setup:
;
; For each application to be metered, install PdcMeter in the application
; directory on your server. Configure PdcMeter support files for the 
; application. Schedule the periodic "METER" task using your favorite 
; scheduler, (AT probably won't cut it.)
;
; PdcMeter Support Files:
; 
;   Create Directories:
;     appdir\License                Permissions (RX)
;     appdir\Log                    Permissions (RWX)
;     appdir\Lock                   Permissions (RWXD)
;   Create Files:
;     appdir\pdcmeter.ini           (see SAMPLE INI FILE below)
;     appdir\License\license.dat    one line text file, contains # of licenses
;     appdir\License\current.dat    one line text file, can be empty to start
;     appdir\License\exception.dat  one line text file, can be empty to start
;     appdir\Log\license.log        use "LOG_RESET" option to create this file
;     appdir\Log\error.log          use "LOG_RESET" option to create this file
; 
; Description:
;
; Provides an application metering process. When executed with the "RUN" 
; option will launch the target application, if the current license count 
; is below the maximum threshold. The metering process is periodically 
; executed using the "METER" option to update the current count and list 
; of current users (every 10 minutes is adequate). This information is
; accessed by the "RUN" option. The "STATS" option will generate usage
; statistics. The "SERVICE" option will start the automatic "METER" 
; mode. For the "SERVICE" option to work properly, it must be installed 
; with the NT SRVANY utility first.
;
; Notes:
;
; The "SERVICE" capability is still in development and testing, so expect
; that you'll have to do some work here, but have fun if you choose to 
; finish it. I currently use SmartBatch to schedule the "METER" task to 
; run every 10 minutes for each application that is being metered.
;
; ErrorLevel:
;   0 = Success
;   1 = Initialization Error
;   2 = Param File Error
;   3 = File Locking Error
;   4 = License count exceeds maximum licenses allowed*
;
;   *this can occur if someone executes the metered app without using
;    pdcmeter to launch it
;
; Program Initialization Calling Sequence:
;
;   Task 1                Task 2-7              Task 20-21
;   --------------------- --------------------- ---------------------
;   ReadParamApplication  ReadParamApplication  ReadParamService
;   ReadParamClient       ReadParamServer       ReadParamNotification
;   ReadParamNotification ReadParamNotification ParamDerived
;   ReadDerived           ParamDerived          
;
;----------------------------------------------------------------------/

PNAME = "PdcMeter"
PVERSION = "Version 1.0  June 8, 1998"
COPYRIGHT = "Copyright 1998"
AUTHOR = "Brad Adkins, badkins@ix.netcom.com"

;----------------------------------------------------------------------
; SECTION: Global
;----------------------------------------------------------------------/

;string formatting constants
C1 = "%@CRLF%"
C2 = "%@CRLF%%@CRLF%"

;project version information
s = StrFill(" ", 5)
VERINFO = StrCat(s, PVERSION, "|", s, COPYRIGHT, @CRLF, s, AUTHOR)

;constants
APP_RUN = "APP_RUN"
APP_METER = "APP_METER"
APP_MOFF = "APP_MOFF"
LOG_RESET = "LOG_RESET"
LOG_OPEN = "LOG_OPEN"
LOG_CLOSE = "LOG_CLOSE"
LOG_STATS = "LOG_STATS"
LOG_SHOW = "LOG_SHOW"
SRV_START = "SRV_START"
SRV_STOP = "SRV_STOP"

LOCK_ATTEMPTS = 3
LOCK_DELAY = 0.5

;variables
LicenseLock = "A_Lock.lok"
LogLock = "B_Lock.lok"
ErrLock = "C_Lock.lok"

;----------------------------------------------------------------------
; SECTION: Environment
;----------------------------------------------------------------------/

WinHide("")
WinTitle("", PNAME)

TestMode = @FALSE
ProductionMode = @TRUE

;#12 - supress critical error dialog when being forceably shutdown
IntControl(12,5,0,0,0)

;#50 - no "go to web page" button on WIL critical error boxes
IntControl(50, 0, 0, 0, 0) 

;#33 - listbox control allows only single items to be selected
IntControl(33, 0, 0, 0, 0) 


;#1000 - application return code on exit using value in ErrorLevel
ErrorLevel = 0

;----------------------------------------------------------------------
; SECTION: Main
;----------------------------------------------------------------------/
gosub Initialize

select Task
    case 1
        ;APP_RUN
        gosub RunApp
        break
    case 2
        ;APP_METER
        gosub MeterApp
        break
    case 3
        ;LOG_STATS
        gosub RunStats
        break
    case 4
        ;LOG_SHOW
        gosub ShowStats
        break
    case 5
        ;LOG_RESET
        gosub CreateLogFiles
        break
    case 6
        ;LOG_OPEN
        gosub LogOpen
        break
    case 7
        ;LOG_CLOSE
        gosub LogClose
        break
    case 20
        ;SRV_START
        gosub StartService
        break
    case 21
        ;SRV_STOP
        gosub StopService
        break
endselect

gosub ProgramExit

;----------------------------------------------------------------------
; SUBROUTINE: Initialize
;----------------------------------------------------------------------/
:Initialize
    gosub IsWinNT
    if Result
        ;Windows NT
        OS = 2
    else
        ;Windows 95
        OS = 1
    endif
    
    Task = 1
    
    if ProductionMode    
        HomeDir = DirHome()
    else
        HomeDir = "C:\Projects\wbt\PdcMeter\"
    endif  

    IniFile = "%HomeDir%pdcmeter.ini"
    if !FileExist(IniFile)
        MsgTxt = "Program initialization file not found"
        ErrorLevel = 1
        gosub ErrorExit
    endif

    ;holding down the shift key at startup reveals version information
    keycheck=IsKeyDown(@SHIFT)
    if keycheck == @YES
        gosub DisplayVerInfo
        gosub ProgramExit
    endif

    wildll = StrCat(HomeDir, "wbdbp32i.dll")
    net95dll = StrCat(HomeDir, "www9532i.dll")
    netntdll = StrCat(HomeDir, "wwwnt32i.dll")
    inetdll = StrCat(HomeDir, "wwwsk32i.dll")
        
    MsgTxt = "Required application file not found"
    if ProductionMode
        if !FileExist(wildll) 
            ErrorLevel = 1
            gosub ErrorExit
        endif
        if !FileExist(net95dll)
            ErrorLevel = 1
            gosub ErrorExit
        endif
        if !FileExist(netntdll)
            ErrorLevel = 1
            gosub ErrorExit
        endif
        if !FileExist(inetdll)
            ErrorLevel = 1
            gosub ErrorExit
        endif
    endif
    
    AddExtender(inetdll)
    if OS == 1
        AddExtender(net95dll)
        UserName = StrLower(w95GetUser(@default))
    endif
    if OS == 2
        AddExtender(netntdll)
        UserName = StrLower(wNTGetUser(@default))
    endif
    ComputerName = RegQueryValue(@REGMACHINE,"System\CurrentControlSet\control\ComputerName\ComputerName[ComputerName]")

    ;process the command line
    
    if Param0 > 1
        MsgTxt = "Invalid command line"
        ErrorLevel = 1
        gosub ErrorExit
    endif
    
    if Param0 == 0
        Param0 = 1
        Param1 = "APP_RUN"
    endif
        
    goodparam = @FALSE
    if Param1 == APP_RUN
        goodparam = @TRUE
        Task = 1
    endif
    if Param1 == APP_METER
        goodparam = @TRUE
        Task = 2
    endif
    if Param1 == LOG_STATS 
        goodparam = @TRUE
        Task = 3
    endif
    if Param1 == LOG_SHOW
        goodparam = @TRUE
        Task = 4
    endif
    if Param1 == LOG_RESET
        goodparam = @TRUE
        Task = 5
    endif
    if Param1 == LOG_OPEN
        goodparam = @TRUE
        Task = 6
    endif
    if Param1 == LOG_CLOSE
        goodparam = @TRUE
        Task = 7
    endif
    if Param1 == SRV_START 
        goodparam = @TRUE
        Task = 20
    endif
    if Param1 == SRV_STOP
        goodparam = @TRUE
        Task = 21
    endif

    AppParm = ""
    if !goodparam
        ;assume thing passed is a filname
        ;this will override the value in the ini file if one is given there 
        AppParm = Param1
    endif

    if Task > 1
        if OS <> 2
            MsgTxt = "Requested task only runs under Windows NT"
            ErrorLevel = 1
            gosub ErrorExit
        endif
    endif
return

;----------------------------------------------------------------------
; SUBROUTINE: StartService
;----------------------------------------------------------------------/
:StartService
    ;start metering and loop forever or until service stop request is received
    ;when installed as a service, the service stop request will unload this app
    ;based on the window title which is modified below for uniqueness

    ;read pdcmeter.ini file
    gosub ReadParamService
    gosub ParamDerived
    
    wtitle = "%PNAME%Service"
    if WinExist(wtitle)
        ErrorLevel = 2
        MsgTxt = "Service is already started"
        goto ErrorExit
    endif    
    
    WinTitle("", wtitle)
    
    ;must write to each application log file!!!
    a =StrFix(SRV_START, " ", 9)
    LogTxt = "%a%|%AppName%"
    gosub WriteLogFile

    if OpenLogOnStart
        ;must write to each application log file!!!
        gosub LogOpen
    endif

    while @TRUE
        ;meter all configured applications on each pass
        ;mechanism provided to return here if ErrorExit is called by any one application
        
        ;is it metering time
        p1 = MeterFrom
        p2 = MeterTo
        gosub QualifyTime
        if result
            ;meter away
            for meterc = 1 to MeterCount
                ErrorLevel = 0
                ;open application metering definition file
                IniFile = ItemExtract(meterc, ApplicationList, "|")
                gosub ParamSetup
                gosub ReadParamApplication
                gosub ReadParamServer
                gosub ParamFinish
                Yield()
            
                ;perform metering
                if ErrorLevel == 0
                    gosub MeterApp
                endif
                Yield()
            next
        else
            ;probably don't want to to this!!!
            a =StrFix(APP_MOFF, " ", 9)
            LogTxt = "%a%|%AppName%"
            gosub WriteLogFile
        endif                   
        
        ;wait
        TimeDelay(MeterInterval)
    endwhile

    ErrorLevel = 0
return

;----------------------------------------------------------------------
; SUBROUTINE: StopService
;----------------------------------------------------------------------/
:StopService
    ;read pdcmeter.ini file
    gosub ReadParamService
    gosub ParamDerived
    
    result = @FALSE    
    wtitle = "%PNAME%Service"
    
    if WinExist(wtitle)
        IntControl(47, wtitle, 0, 0, 0)
        result = @TRUE
    
        a =StrFix(SRV_STOP, " ", 9)
        ;probably want to do this to all logs!!!
        LogTxt = "%a%|%AppName%"
        gosub WriteLogFile
        
        if CloseLogOnStop
            ;probably want to do this to all logs!!!
            gosub LogClose
        endif
    endif
    
    if !result
        ErrorLevel = 2
        MsgTxt = "Unable to stop Service"
        gosub ErrorExit
    endif        
return

;----------------------------------------------------------------------
; SUBROUTINE: RunApp
;----------------------------------------------------------------------/
:RunApp    
    ; step 1 - get license count (maximum users)
    ; step 2 - get count of current users
    ; step 3 - run or abort based on count

    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamClient
    gosub ReadParamNotification
    gosub ParamDerived
    
    gosub ReadLicenseData
    
    if CurrentCount < MaxCount
        a =StrFix(APP_RUN, " ", 9)
        LogTxt = "%a%|%AppName%|username=%UserName%"
        gosub WriteLogFile

        LastError()
        ErrorMode(@OFF)
        Run(AppFileName, AppParm)
        ErrorMode(@CANCEL)
        return
    endif
    
    ;we are at or over the limit
    
    if CurrentCount == MaxCount
        MsgTxt = "Maximum number of licenses is currently in use for|%AppName%|Please try again later or contact your System Administrator"
        gosub DisplayMessage
        return
    endif

    if CurrentCount > MaxCount
        MsgTxt = "Maximum number of licenses has been exceeded for|%AppName%|Please contact your System Administrator"
        ErrorLevel = 4
        gosub ErrorExit
    endif        
return

;----------------------------------------------------------------------
; SUBROUTINE: MeterApp
;----------------------------------------------------------------------/
:MeterApp
    ;NET FILE sample output
    ;---------+---------+---------+---------+---------+---------+---------+----
    ;833931     C:\NTRESKIT\WINSCL.EXE                  ADKINSB               0     

    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamServer
    gosub ReadParamNotification
    gosub ParamDerived
    
    ;step 1 - read current license info to get MaxCount and ExceptionList
    gosub ReadLicenseData
    
    ;step 2 - run NET FILE command and write output to license directory
    RunWait("cmd.exe", "/c net file > %LicenseDirectory%netfile.txt")
    
    ;step 3 - parse netfile output looking for CheckString
    CurrentCount = 0
    UserList = ""
    hf = FileOpen("%LicenseDirectory%netfile.txt", "READ")
    while @TRUE
        s = FileRead(hf)
        if s == "*EOF*" then break
        p = StrIndexNc(s, CheckString, 1, @FWDSCAN)
        if p > 0
            CurrentCount = CurrentCount + 1
            UserList = StrCat(UserList, StrTrim(StrSub(s, 52, 20)), "|")
        endif
    endwhile
    FileClose(hf)
    
    ;step 4 - parse log in binary buffer rebuilding the user exception list
    gosub ReadLogFile
    ;for each name in UserList (netfile)
    ;if name is not in the buffer (license log contents)
    ;we have a user that has not used the wrapper to launch the app
    ic = ItemCount(UserList, "|")
    for i = 1 to ic
        ulname = StrCat("username=", StrLower(ItemExtract(i, UserList, "|")))
        ;Message("", ulname) 
        if BinaryIndexNc(binbuf, 1, ulname, @FWDSCAN) == 0
            ;bingo name from netfile is not in the license log
            ulname = StrReplace(ulname, "username=", "")
            ExceptionList = StrCat(ExceptionList, ulname, "|")
        endif
    next
    BinaryFree(binbuf)
    
    ;step 5 - write current user count & current user list
    gosub WriteLicenseData

    ;step 6 - append a metering record to Log File
    a =StrFix(APP_METER, " ", 9)
    LogTxt = "%a%|%AppName%|%CurrentCount%|%MaxCount%"
    gosub WriteLogFile    
return

;----------------------------------------------------------------------
; SUBROUTINE: RunStats
;----------------------------------------------------------------------/
:RunStats
    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamServer
    gosub ReadParamNotification
    gosub ParamDerived
    
    Output = "FILE"
    gosub SetupLogFiles
    
    ;compile summary information
    gosub BuildSummary
    if SendStats
        thelog = SummaryLog
        gosub SendReport
    endif    
return

;----------------------------------------------------------------------
; SUBROUTINE: ShowStats
;----------------------------------------------------------------------/
:ShowStats
    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamServer
    gosub ReadParamNotification
    gosub ParamDerived
    
    Output = "TEMP"
    gosub SetupLogFiles
    
    ;compile summary information
    gosub BuildSummary
    Run("notepad.exe", TmpSum)
    if SendShow
        thelog = TmpSum
        gosub SendReport
    endif    
return

;----------------------------------------------------------------------
; SUBROUTINE: CreateLogFiles
;----------------------------------------------------------------------/
:CreateLogFiles
    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamServer
    gosub ReadParamNotification
    gosub ParamDerived
    
    a =StrFix(LOG_RESET, " ", 9)
    header = StrCat(TimeYmdHms(), "|%a%|%AppName%")
    
    hf = FileOpen(LogFile, "WRITE")
    FileWrite(hf, header)
    FileClose(hf)
    
    hf = FileOpen(ErrorLog, "WRITE")
    FileWrite(hf, header)
    FileClose(hf)
    
    hf = FileOpen(CurrentDataFile, "WRITE")
    FileWrite(hf, header)
    FileWrite(hf, "0")
    FileWrite(hf, "")
    FileClose(hf)
    
    hf = FileOpen(ExceptionDataFile, "WRITE")
    FileWrite(hf, header)
    FileWrite(hf, "")
    FileClose(hf)
    
    Drop(header)    
return

;----------------------------------------------------------------------
; SUBROUTINE: LogOpen
;----------------------------------------------------------------------/
:LogOpen
    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamServer
    gosub ReadParamNotification
    gosub ParamDerived
    
    a =StrFix(LOG_OPEN, " ", 9)
    
    LogTxt = "%a%|%AppName%"
    gosub WriteLogFile

    ErrTxt = "%a%|%AppName%"
    gosub WriteErrorFile
return

;----------------------------------------------------------------------
; SUBROUTINE: LogClose
;----------------------------------------------------------------------/
:LogClose
    ;read pdcmeter.ini file
    gosub ReadParamApplication
    gosub ReadParamServer
    gosub ReadParamNotification
    gosub ParamDerived
    
    a =StrFix(LOG_CLOSE, " ", 9)
    
    LogTxt = "%a%|%AppName%"
    gosub WriteLogFile

    ErrTxt = "%a%|%AppName%"
    gosub WriteErrorFile
return

;----------------------------------------------------------------------
; SUBROUTINE: WriteLicenseData
;----------------------------------------------------------------------/
:WriteLicenseData
    if StrSub(UserList, StrLen(UserList), 1) == "|"
        UserList = StrSub(UserList, 1, StrLen(UserList) - 1)
    endif
    if StrSub(ExceptionList, StrLen(ExceptionList), 1) == "|"
        ExceptionList = StrSub(ExceptionList, 1, StrLen(ExceptionList) - 1)
    endif

    a =StrFix(LOG_RESET, " ", 9)
    header = StrCat(TimeYmdHms(), "|%a%|%AppName%")
    
    ;lock the license files
    LockFile = LicenseLockFile
    gosub LockFiles
    
    hf = FileOpen(CurrentDataFile, "WRITE")
    FileWrite(hf, header)
    FileWrite(hf, CurrentCount)
    FileWrite(hf, UserList)
    FileClose(hf)

    hf = FileOpen(ExceptionDataFile, "WRITE")
    FileWrite(hf, header)
    FileWrite(hf, ExceptionList)
    FileClose(hf)

    ;unlock the license files
    gosub UnLockFiles
    
    Drop(header)                                                                              
return

;----------------------------------------------------------------------
; SUBROUTINE: ReadLicenseData
;----------------------------------------------------------------------/
:ReadLicenseData
    ;lock the license files
    LockFile = LicenseLockFile
    gosub LockFiles
    
    ;read maximum user count
    hf = FileOpen(LicenseDataFile, "READ")
    MaxCount = FileRead(hf)
    FileClose(hf)

    ;read current data
    hf = FileOpen(CurrentDataFile, "READ")
    header = FileRead(hf)
    CurrentCount = FileRead(hf)
    UserList = FileRead(hf)
    FileClose(hf)
    
    ;read exception list
    hf = FileOpen(ExceptionDataFile, "READ")
    header = FileRead(hf)        
    ExceptionList = FileRead(hf)
    FileClose(hf)
                  
    ;unlock the license files
    gosub UnLockFiles
          
    Drop(header)                                                                        
return

;----------------------------------------------------------------------
; SUBROUTINE: ReadLogFile
;----------------------------------------------------------------------/
:ReadLogFile
    ;lock the log files
    LockFile = LogLockFile
    gosub LockFiles
    
    ;read log file into a binary buffer
    fs = FileSize(LogFile)
    binbuf = BinaryAlloc(fs)
    if binbuf == 0
        MsgTxt = "Critical Error: BinaryAlloc Failed"
        ErrorLevel = 2
        gosub ErrorExit
    else
        ;read the file into the buffer
        BinaryRead(binbuf, LogFile)
    endif    
    
    ;unlock the log files
    gosub UnLockFiles
return

;----------------------------------------------------------------------
; SUBROUTINE: WriteLogFile
;----------------------------------------------------------------------/
:WriteLogFile
    ;lock the log files
    LockFile = LogLockFile
    gosub LockFiles
    
    hf = FileOpen(LogFile, "APPEND")
    FileWrite(hf, StrCat(TimeYmdHms(), "|", LogTxt))
    FileClose(hf)
    
    ;unlock the log files
    gosub UnLockFiles                                                                              
return

;----------------------------------------------------------------------
; SUBROUTINE: WriteErrorFile
;----------------------------------------------------------------------/
:WriteErrorFile
    ;do not call LockFiles or loop might occur
    LockFile = ErrLockFile

    i = 0
    while @TRUE
        if FileExist(LockFile)
            TimeDelay(LOCK_DELAY)
            i = i + 1
            if i > LOCK_ATTEMPTS
                ;unable to get a lock, out of luck
                ;this should never happen :-)
                if Task > 19 then return
                exit
            endif
        else
            break
        endif
    endwhile
    
    ;create the requested lock file
    hf = FileOpen(LockFile, "WRITE")
    FileWrite(hf, "LOCKED")
    FileClose(hf)
    
    ;write to the error log    
    hf = FileOpen(ErrorLog, "APPEND")
    FileWrite(hf, StrCat(TimeYmdHms(), "|", ErrTxt))
    FileClose(hf)
    
    ;unlock the error log
    gosub UnLockFiles                                                                              
return

;----------------------------------------------------------------------
; SUBROUTINE: SetupLogFiles
;----------------------------------------------------------------------/
:SetupLogFiles
    ;lock the log file
    LockFile = LogLockFile
    gosub LockFiles
    
    ;rename the log file and  error log in preparation for statistical processing
    if Output == "FILE"
        FileRename(LogFile, BackupLog)
        FileRename(ErrorLog, BackupErr)
        gosub CreateLogFiles
    endif
    if Output == "TEMP"
        if FileExist(TmpLog) then FileDelete(TmpLog)
        FileCopy(LogFile, TmpLog, @FALSE)
        if FileExist(TmpErr) then FileDelete(TmpErr)
        FileCopy(ErrorLog, TmpErr, @FALSE)
    endif
                          
    ;unlock the log file
    gosub UnLockFiles                                                                                  
return

;----------------------------------------------------------------------
; SUBROUTINE: BuildSummary
;----------------------------------------------------------------------/
:BuildSummary
    ;first load up the current licensing information
    gosub ReadLicenseData
    
    ;get current service status
    LastError()
    ErrorMode(@OFF)
    cstate = wntSvcStatus("", "PdcMeter", 0, 2)
    ErrorMode(@CANCEL)
    if LastError() == 0
        switch cstate
            case 1   
                currentstate = "SERVICE_STOPPED"
                break
            case 2   
                currentstate = "SERVICE_START_PENDING"
                break
            case 3   
                currentstate = "SERVICE_STOP PENDING"
                break
            case 4   
                currentstate = "SERVICE_RUNNING"
                break
            case 5   
                currentstate = "SERVICE_CONTINUE_PENDING"
                break
            case 6   
                currentstate = "SERVICE_PAUSE_PENDING"
                break
            case 7   
                currentstate = "SERVICE_PAUSED"
                break
        endswitch
    else
        currentstate = "SERVICE_NOT_INSTALLED"    
    endif
    
    ms = ""
    me = ""
    md = ""
    ma = ""
    mc = 0
    ec = 0
    ul = ""
    ilm = 0
    iem = 0
    igm = 0

    if Output == "FILE"
        fn_log = BackupLog
        fn_err = BackupErr
        fn_sum = SummaryLog
    endif
    if Output == "TEMP"
        fn_log = TmpLog
        fn_err = TmpErr
        fn_sum = TmpSum
    endif
    
    hf = FileOpen(fn_log, "READ")
    s = FileRead(hf)
    ms = StrSub(s, 1, 19)
    FileClose(hf)

    ReadingLog = @FALSE
    hf = FileOpen(fn_log, "READ")
    while @TRUE
        s = FileRead(hf)
        if StrIndex(s, LOG_OPEN, 1, @FWDSCAN) > 0 then ReadingLog = @TRUE
        if StrIndex(s, LOG_CLOSE, 1, @FWDSCAN) > 0 then s = "*EOF*"
        if s == "*EOF*" then break
        if ReadingLog
            me = StrSub(s, 1, 19)
            ;process this line
            if StrIndex(s, "|%APP_METER%", 1, @FWDSCAN) > 0
                mc = mc + 1
                icc = ItemExtract(4, s, "|")
                if icc < MaxCount then ilm = ilm + 1
                if icc == MaxCount then iem = iem + 1
                if icc > MaxCount then igm =igm + 1
            endif
            if StrIndex(s, "|%APP_RUN%", 1, @FWDSCAN) > 0
                ec = ec + 1
                un = ItemExtract(4, s, "|")
                un = StrReplace(un, "username=", "")
                if StrIndex(ul, un, 1, @FWDSCAN) < 1
                    ul = StrCat(ul, un, "|")
                endif
            endif
        endif
    endwhile    
    FileClose(hf)

    md = TimeDiffSecs(me, ms)
    p1 = md
    p2 = mc
    gosub TimeDiffFormat
    md = retval1
    ma = retval2
    uc = ItemCount(ul, "|")    

    ;setup notification temporary varibles
    nof = "OFF"
    nom = "NO"
    nop = "NO"
    noe = "NO"
    if Notification then nof = "ON"
    if SendEmail then nom = "YES"
    if SendPage then nop = "YES"
    if EventLog then noe = "YES"

    ExceptionCount = ItemCount(ExceptionList, "|")
    
    hf = FileOpen(fn_sum, "WRITE")
    FileWrite(hf, "")
    FileWrite(hf, "PDCMETER")
    FileWrite(hf, StrCat(StrFix("  REPORT DATE", " ", 22), "= ", TimeYmdHms()))
    FileWrite(hf, StrCat(StrFix("  GENERATED BY", " ", 22), "= ", ComputerName, " ", UserName))

    FileWrite(hf, "")
    FileWrite(hf, "APPLICATION")
    FileWrite(hf, StrCat(StrFix("  NAME", " ", 22), "= %AppName%"))
    FileWrite(hf, StrCat(StrFix("  LICENSES", " ", 22), "= %MaxCount%"))
    FileWrite(hf, StrCat(StrFix("  FILE", " ", 22), "= ", StrLower(AppFile)))
    FileWrite(hf, StrCat(StrFix("  PARAMETERS", " ", 22), "= %AppParm%"))

    FileWrite(hf, "")
    FileWrite(hf, "NOTIFICATION")
    FileWrite(hf, StrCat(StrFix("  CURRENT STATE", " ", 22), "= %nof%"))
    FileWrite(hf, StrCat(StrFix("  EVENT LOG", " ", 22), "= %noe%"))
    FileWrite(hf, StrCat(StrFix("  PAGER", " ", 22), "= %nop%"))
    FileWrite(hf, StrCat(StrFix("  EMAIL", " ", 22), "= %nom%"))

    FileWrite(hf, "")
    FileWrite(hf, "CURRENT INTERVAL")
    FileWrite(hf, StrCat(StrFix("  USERS", " ", 22), "= %CurrentCount%"))
    j = ItemCount(UserList, "|")
    for i = 1 to j
        FileWrite(hf, StrCat("  ===> ", ItemExtract(i, UserList, "|")))
    next

    FileWrite(hf, "")
    FileWrite(hf, "METERING")
    FileWrite(hf, StrCat(StrFix("  START", " ", 22), "= %ms%"))
    FileWrite(hf, StrCat(StrFix("  LAST", " ", 22), "= %me%"))
    FileWrite(hf, StrCat(StrFix("  ELAPSED", " ", 22), "= %md%"))
    FileWrite(hf, StrCat(StrFix("  INTERVAL (AVG)", " ", 22), "= %ma%"))
    FileWrite(hf, StrCat(StrFix("  NUMBER OF INTERVALS", " ", 22), "= %mc%"))
    FileWrite(hf, StrCat(StrFix("  INTERVALS LT MAX LC", " ", 22), "= %ilm%"))
    FileWrite(hf, StrCat(StrFix("  INTERVALS EQ MAX LC", " ", 22), "= %iem%"))
    FileWrite(hf, StrCat(StrFix("  INTERVALS GT MAX LC", " ", 22), "= %igm%"))
    FileWrite(hf, StrCat(StrFix("  INVOCATIONS", " ", 22), "= %ec%"))
    FileWrite(hf, StrCat(StrFix("  LICENSE EXCEPTIONS", " ", 22), "= %ExceptionCount%"))
    for i = 1 to ExceptionCount
        FileWrite(hf, StrCat("  ===> ", ItemExtract(i, ExceptionList, "|")))
    next
    FileWrite(hf, StrCat(StrFix("  UNIQUE USER COUNT", " ", 22), "= %uc%"))
    for i = 1 to uc
        FileWrite(hf, StrCat("  ===> ", ItemExtract(i, ul, "|")))
    next

    FileWrite(hf, "")
    FileWrite(hf, "SERVICE")
    FileWrite(hf, StrCat(StrFix("  SERVICE NAME", " ", 22), "= PdcMeter"))
    FileWrite(hf, StrCat(StrFix("  CURRENT STATE", " ", 22), "= %currentstate%"))
    FileWrite(hf, StrCat(StrFix("  METER INTERVAL", " ", 22), "= <-registry"))
    FileWrite(hf, StrCat(StrFix("  METER FROM", " ", 22), "= <-registry"))
    FileWrite(hf, StrCat(StrFix("  METER TO", " ", 22), "= <-registry"))
    FileWrite(hf, StrCat(StrFix("  APPLICATIONS", " ", 22), "= <-registry"))
    ;for i = 1 to al
    ;    FileWrite(hf, StrCat("  ===> ", ItemExtract(i, al, "|")))
    ;next

    FileWrite(hf, "")
    FileWrite(hf, "ERROR LOG")
    FileWrite(hf, "  RESPONSE=0 (WAITING RESPONSE)")
    ReadingLog = @FALSE
    hf2 = FileOpen(fn_err, "READ")
    while @TRUE
        s = FileRead(hf2)
        if StrIndex(s, LOG_OPEN, 1, @FWDSCAN) > 0 then ReadingLog = @TRUE
        if StrIndex(s, LOG_CLOSE, 1, @FWDSCAN) > 0 then s = "*EOF*"
        if s == "*EOF*" then break        
        if StrIndex(s, "RESPONSE=0", 1, @FWDSCAN) > 0
            FileWrite(hf, StrCat("  ===> ", s))
        endif
    endwhile    
    FileClose(hf2)
    
    FileWrite(hf, "")
    FileWrite(hf, "ERROR LOG")
    FileWrite(hf, "  RESPONSE=1 (RESPONDED)")
    ReadingLog = @FALSE
    hf2 = FileOpen(fn_err, "READ")
    while @TRUE
        s = FileRead(hf2)
        if StrIndex(s, LOG_OPEN, 1, @FWDSCAN) > 0 then ReadingLog = @TRUE
        if StrIndex(s, LOG_CLOSE, 1, @FWDSCAN) > 0 then s = "*EOF*"
        if s == "*EOF*" then break
        if StrIndex(s, "RESPONSE=1", 1, @FWDSCAN) > 0
            FileWrite(hf, StrCat("  ===> ", s))
        endif
    endwhile
    FileWrite(hf, "")
    FileClose(hf2)

    FileClose(hf)

    ;this is ug-ly
    Drop(nof, nom, noe, nop, ul, uc, ec, mc, md, ma, me, ms, fn_log, fn_err, fn_sum, ilm, iem, igm, retval1, retval2)        
return

;----------------------------------------------------------------------
; SUBROUTINE: LockFiles
;----------------------------------------------------------------------/
:LockFiles
    ;see if somebody else has a lock already
    i = 0
    while @TRUE
        if FileExist(LockFile)
            TimeDelay(LOCK_DELAY)
            i = i + 1
            if i > LOCK_ATTEMPTS
                ;unable to grab a lock
                MsgTxt = "Unable to obtain file lock|Please contact your System Administrator"
                ErrorLevel = 3
                gosub ErrorExit
            endif
        else
            break
        endif
    endwhile
    
    ;create the requested lock file
    hf = FileOpen(LockFile, "WRITE")
    FileWrite(hf, "LOCKED")
    FileClose(hf)
return

;----------------------------------------------------------------------
; SUBROUTINE: UnLockFiles
;----------------------------------------------------------------------/
:UnLockFiles
    if FileExist(LockFile) then FileDelete(LockFile)       
return

;----------------------------------------------------------------------
; SUBROUTINE: ParamSetup
;----------------------------------------------------------------------/
:ParamSetup
    e1 = "Entry invalid"
    e2 = "Directory not found"
    e3 = "File not found"
    e4 = "Notification entry invalid"
    e5 = "Service entry invalid"
return

;----------------------------------------------------------------------
; SUBROUTINE: ParamClean
;----------------------------------------------------------------------/
:ParamClean
    Drop(en, e1, e2, e3, e4, en)    
return

;----------------------------------------------------------------------
; SUBROUTINE: ReadParamApplication
;----------------------------------------------------------------------/
:ReadParamApplication
    gosub ParamSetup
    Section = "Application"
    
    AppName = IniReadPvt(Section, "AppName", "", IniFile)        
    AppFile = IniReadPvt(Section, "AppFile", "", IniFile)
    if StrLen(AppParm) < 1
        AppParm = IniReadPvt(Section, "AppParm", "", IniFile)        
    endif

    en = 0
    if StrLen(AppName) < 1 then en = en + 1 
    if StrLen(AppFile) < 1 then en = en + 1 
    if en > 0
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e1%"
        gosub ErrorExit
    endif

    gosub ParamClean    
return

;----------------------------------------------------------------------
; SUBROUTINE: ReadParamClient
;----------------------------------------------------------------------/
:ReadParamClient
    gosub ParamSetup
    Section = "Run"
    
    AppPath = IniReadPvt(Section, "AppPath", "", IniFile)
    LicensePath = IniReadPvt(Section, "LicensePath", "", IniFile)
    
    gosub ParamValidateDf    
    gosub ParamClean    
return
    
;----------------------------------------------------------------------
; SUBROUTINE: ReadParamServer
;----------------------------------------------------------------------/
:ReadParamServer
    gosub ParamSetup
    Section = "Meter"
    
    AppPath = IniReadPvt(Section, "AppPath", "", IniFile)
    LicensePath = IniReadPvt(Section, "LicensePath", "", IniFile)
    LogEventPath = IniReadPvt(Section, "LogEventPath", "", IniFile)

    gosub ParamValidateLe
    gosub ParamValidateDf
    
    gosub ParamClean    
return

;----------------------------------------------------------------------
; SUBROUTINE: ParamValidateLe
;----------------------------------------------------------------------/
:ParamValidateLe
    ;validate logevent path
    if StrSub(StrLen(LogEventPath), 1, 1) <> "\"
        LogEventPath = "%LogEventPath%\"
    endif    
    LogEventPath = StrUpper(StrCat(LogEventPath, "logevent.exe"))
    if !FileExist(LogEventPath) 
        ErrorLevel = 2
        MsgTxt = "File not found|%LogEventPath%"
        gosub ErrorExit
    endif
return    

;----------------------------------------------------------------------
; SUBROUTINE: ParamValidateDf
;----------------------------------------------------------------------/
:ParamValidateDf
    ;validate required entries have been made
    en = 16
    if StrLen(AppPath) < 1 then en = en + 1 
    if StrLen(LicensePath) < 1 then en = en + 1 
    if en > 16
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e1%"
        gosub ErrorExit
    endif

    ;fix-up path strings
    if StrSub(StrLen(AppPath), 1, 1) <> "\"
        AppPath = "%AppPath%\"
    endif    
    if StrSub(StrLen(LicensePath), 1, 1) <> "\"
        LicensePath = "%LicensePath%\"
    endif    

    ;set derived values
    AppFileName = StrUpper(StrCat(AppPath, AppFile))
    CheckString = AppFile
    LogDirectory = StrUpper(StrCat(LicensePath, "log\"))
    LockDirectory = StrUpper(StrCat(LicensePath, "lock\"))
    LicenseDirectory = StrUpper(StrCat(LicensePath, "license\"))
    LicenseDataFile = StrUpper(StrCat(LicenseDirectory, "license.dat"))
    CurrentDataFile = StrUpper(StrCat(LicenseDirectory, "current.dat"))
    ExceptionDataFile = StrUpper(StrCat(LicenseDirectory, "exception.dat"))
    LogFile = StrUpper(StrCat(LogDirectory, "license.log"))
    ErrorLog = StrUpper(StrCat(LogDirectory, "error.log"))
                
    ;check directories
    en = 32
    if !DirExist(LogDirectory) then en = en + 1
    if !DirExist(LockDirectory) then en = en + 1
    if !DirExist(LicenseDirectory) then en = en + 1
    if en > 32
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e2%"
        gosub ErrorExit
    endif

    ;check files
    en = 48
    if !FileExist(AppFileName) then en = en + 1
    if !FileExist(LicenseDataFile) then en = en + 1
    if !FileExist(CurrentDataFile) then en = en + 1
    if !FileExist(ExceptionDataFile) then en = en + 1
    if !FileExist(LogFile) then en = en + 1
    if !FileExist(ErrorLog) then en = en + 1
    if en > 48
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e3%"
        gosub ErrorExit
    endif
return

;----------------------------------------------------------------------
; SUBROUTINE: ReadParamNotification
;----------------------------------------------------------------------/
:ReadParamNotification
    gosub ParamSetup
    Section = "Notification"

    Notification = IniReadPvt(Section, "Notification", "", IniFile)
    EventLog = IniReadPvt(Section, "EventLog", "", IniFile)
    AlertList = IniReadPvt(Section, "AlertList", "", IniFile)
    FromAddress = IniReadPvt(Section, "FromAddress", "", IniFile)
    ReportAddress = IniReadPvt(Section, "ReportAddress", "", IniFile)
    PagerKeyList = IniReadPvt(Section, "PagerKeyList", "", IniFile)
    NotificationText = IniReadPvt(Section, "NotificationText", "", IniFile)
    MailServer = IniReadPvt(Section, "MailServer", "", IniFile)
    PagingAddress = IniReadPvt(Section, "PagingAddress", "", IniFile)
    SendEmail = IniReadPvt(Section, "SendEmail", "", IniFile)
    SendPage = IniReadPvt(Section, "SendPage", "", IniFile)
    SendShow = IniReadPvt(Section, "SendShow", "", IniFile)
    SendStats = IniReadPvt(Section, "SendStats", "", IniFile)

    ;validate required entries have been made
    en = 64
    if StrLen(Notification) < 1 then en = en + 1
    if StrLen(EventLog) < 1 then en = en + 1
    if StrLen(AlertList) < 1 then en = en + 1
    if StrLen(FromAddress) < 1 then en = en + 1
    if StrLen(ReportAddress) < 1 then en = en + 1
    if StrLen(PagerKeyList) < 1 then en = en + 1
    if StrLen(NotificationText) < 1 then en = en + 1
    if StrLen(MailServer) < 1 then en = en + 1
    if StrLen(PagingAddress) < 1 then en = en + 1
    if StrLen(SendEmail) < 1 then en = en + 1
    if StrLen(SendPage) < 1 then en = en + 1
    if StrLen(SendShow) < 1 then en = en + 1
    if StrLen(SendStats) < 1 then en = en + 1
    if en > 64
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e4%"
        gosub ErrorExit
    endif

    en = 80
    if (Notification == "YES") || (Notification == "NO")
        if Notification == "YES"
            Notification = @TRUE
        else
            Notification = @FALSE
        endif
    else
        en = en + 1
    endif
    if (EventLog == "YES") || (EventLog == "NO")
        if EventLog == "YES"
            EventLog = @TRUE
        else
            EventLog = @FALSE
        endif
    else
        en = en + 1
    endif
    if (SendEmail == "YES") || (SendEmail == "NO")
        if SendEmail == "YES"
            SendEmail = @TRUE
        else
            SendEmail = @FALSE
        endif
    else
        en = en + 1
    endif
    if (SendPage == "YES") || (SendPage == "NO")
        if SendPage == "YES"
            SendPage = @TRUE
        else
            SendPage = @FALSE
        endif
    else
        en = en + 1
    endif
    if (SendShow == "YES") || (SendShow == "NO")
        if SendShow == "YES"
            SendShow = @TRUE
        else
            SendShow = @FALSE
        endif
    else
        en = en + 1
    endif
    if (SendStats == "YES") || (SendStats == "NO")
        if SendStats == "YES"
            SendStats = @TRUE
        else
            SendStats = @FALSE
        endif
    else
        en = en + 1
    endif
    if en > 80
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e4%"
        gosub ErrorExit
    endif

    ;list counts must be identical
    alc = ItemCount(AlertList, "|")
    klc = ItemCount(PagerKeyList, "|")
    if alc <> klc
        ErrorLevel = 2
        MsgTxt = "Error 97 %e4%|List counts are invalid"
        gosub ErrorExit
    endif
    Drop(alc, klc)

    gosub ParamClean    
return

;----------------------------------------------------------------------
; SUBROUTINE: ReadParamService
;----------------------------------------------------------------------/
:ReadParamService
    gosub ParamSetup    
    Section = "Service"

    AppName = "PdcMeter Service"
    AppFile = ""
    AppParm = ""

    AppPath = IniReadPvt(Section, "AppPath", "", IniFile)
    LicensePath = IniReadPvt(Section, "LicensePath", "", IniFile)
    LogEventPath = IniReadPvt(Section, "LogEventPath", "", IniFile)

    gosub ParamValidateLe
    gosub ParamValidateDf

    MeterInterval = IniReadPvt(Section, "MeterInterval", "", IniFile)
    MeterFrom = IniReadPvt(Section, "MeterFrom", "", IniFile)
    MeterTo = IniReadPvt(Section, "MeterTo", "", IniFile)
    OpenLogOnStart = IniReadPvt(Section, "OpenLogOnStart", "", IniFile)
    CloseLogOnStop = IniReadPvt(Section, "CloseLogOnStop", "", IniFile)

    en  = 112
    if !IsNumber(MeterInterval)
        en = en + 1
        MsgTxt = "Error %en% - %e5%"
        ErrorLevel = 2
        gosub ErrorExit
    endif

    ct1 = MeterFrom
    ct2 = MeterTo
    gosub CheckTime
    if !result
        en = en + 1
        MsgTxt = "Error %en% - %e5%"
        ErrorLevel = 2
        gosub ErrorExit
    endif
    
    en = 128
    if (OpenLogOnStart == "YES") || (OpenLogOnStart == "NO")
        if OpenLogOnStart == "YES"
            OpenLogOnStart = @TRUE
        else
            OpenLogOnStart = @FALSE
        endif
    else
        en = en + 1
    endif
    if (CloseLogOnStop == "YES") || (CloseLogOnStop == "NO")
        if CloseLogOnStop == "YES"
            CloseLogOnStop = @TRUE
        else
            CloseLogOnStop = @FALSE
        endif
    else
        en = en + 1
    endif
    if en > 128
        ErrorLevel = 2
        MsgTxt = "Error %en% - %e5%"
        gosub ErrorExit
    endif

    ;read the ApplicationList and set the MeterCount
    en = 144
    MeterCount = 0
    ApplicationList = ""
    i = 1
    while @TRUE
        a = IniReadPvt(Section, "Application%i%", "", IniFile)
        if StrLen(a) > 0
            MeterCount = MeterCount + 1
            ApplicationList = StrCat(ApplicationList, a, "|")
        else
            break
        endif
        
        i = i + 1
    endwhile
    if MeterCount < 1
        en = en + 1
        MsgTxt = "Error %en% - %e5%"
        ErrorLevel = 2
        gosub ErrorExit
    endif

    gosub ParamClean    
return

;----------------------------------------------------------------------
; SUBROUTINE: ParamDerived
;----------------------------------------------------------------------/
:ParamDerived
    LicenseLockFile = StrCat(LockDirectory, LicenseLock)
    LogLockFile = StrCat(LockDirectory, LogLock)
    ErrLockFile = StrCat(LockDirectory, ErrLock)

    gosub GetTimeFn

    BackupLog =  StrCat(LogDirectory, "Reports\_", TimeFn, "_LOG_BAK.txt")
    BackupErr = StrCat(LogDirectory, "Reports\_", TimeFn, "_ERR_BAK.txt")
    SummaryLog = StrCat(LogDirectory, "Reports\_", TimeFn, "_REPORT.txt")        

    TmpLog = StrCat(LogDirectory, "Reports\_PDCMETER_LOG_TMP.txt")
    TmpErr = StrCat(LogDirectory, "Reports\_PDCMETER_ERR_TMP.txt")
    TmpSum = StrCat(LogDirectory, "Reports\_PDCMETER_CUR_TMP.txt")        
    
    if !DirExist(StrCat(LogDirectory, "Reports"))
        DirMake(StrCat(LogDirectory, "Reports"))
    endif    
return

;----------------------------------------------------------------------
; SUBROUTINE: IsWinNT
;----------------------------------------------------------------------/
:IsWinNT
    Result = @TRUE
    platform=WinMetrics(-4)
    if platform <> 4
        Result = @FALSE
    endif
    Drop(platform)    
return    

;----------------------------------------------------------------------
; SUBROUTINE: CheckTime                                              
;----------------------------------------------------------------------/
:CheckTime

    result = @FALSE
    i = 1
    while IsDefined(ct%i%)
        if StrLen(ct%i%) <> 5 then return
        if StrSub(ct%i%, 3, 1) <> ":" then return
        s1 = StrSub(ct%i%, 1, 2)
        s2 = StrSub(ct%i%, 4, 2)
        StrReplace(s1, "0", "")
        StrReplace(s2, "0", "")
        if !IsNumber(s1) then return
        if !IsNumber(s2) then return
        if s1 > 23 then return
        if s2 > 59 then return
        i = i + 1
    endwhile
    j = i - 1
    result = @TRUE

    ;cleanup
    for i = 1 to j
        Drop(ct%i%)
    next
    Drop(i, j, s1, s2)    
return

;----------------------------------------------------------------------
; SUBROUTINE: QualifyTime
;----------------------------------------------------------------------/
:QualifyTime
    ;assumes valid from-time in p1, to-time in p2, and current-time in p3
    ;valid format is 00:00 (midnight) to 23:59
    ;time window cannot span midnight
    result = @FALSE
    
    p3 = StrSub(TimeYmdHms(), 12, 5)
    p3 = StrReplace(p3, ":", "")
    p2 = StrReplace(p2, ":", "")
    p1 = StrReplace(p1, ":", "")
    
    if (p1 < p3) && (p3 < p2) then result = @TRUE
    ;a = StrCat(" p1(from)=", p1, " p2(to)=", p2, " p3(current)= ", p3)
    ;LogTxt = a
    ;gosub WriteLogFile        
return

;----------------------------------------------------------------------
; SUBROUTINE: GetTimeFn
;----------------------------------------------------------------------/
:GetTimeFn    
    TimeFn = TimeYmdHms()
    TimeFn = StrReplace(TimeFn, ":", "")    
return

;----------------------------------------------------------------------
; SUBROUTINE: TimeDiffFormat
;----------------------------------------------------------------------/
:TimeDiffFormat
    sd = 86400
    sh = 3600
    sm = 60    

    for i = 1 to 2
        if i == 1 then x = p1
        if (i == 2) && (p2 > 0) 
            x = p1 / p2
        else
            x = 0
        endif
        ;format seconds to "DD:HH:MM:SS" string
        d = 0
        h = 0
        m = 0
        s = 0
        if x / sd > 0
            d = x / sd
            x = x mod sd
        endif
        if x / sh > 0
            h = x / sh
            x = x mod sh
        endif
        if x / sm > 0
            m = x / sm
            x = x mod sm
        endif
        s = x
        retval = StrCat(StrFixLeft(d, "0", 2), ":", StrFixLeft(h, "0", 2), ":", StrFixLeft(m, "0", 2), ":", StrFixLeft(s, "0", 2))
        if i == 1 then retval1 = retval
        if i == 2 then retval2 = retval
    next
    
    Drop(p1, p2, sd, sh, sm, d, h, m, s, x, retval)    
return

;----------------------------------------------------------------------
; SUBROUTINE: DisplayMessage
;----------------------------------------------------------------------/
:DisplayMessage

    s = StrReplace(MsgTxt, "|", C2)
        
    if Task < 2
        ;RUN
        if IsDefined(AppName)
            if StrLen(AppName) > 1 then PNAME = AppName
        endif
        
        Message(PNAME, s)
    else
        ;all other options
        Display(3, PNAME, s)
    endif
return    

;----------------------------------------------------------------------
; SUBROUTINE: SendNotification
;----------------------------------------------------------------------/
:SendNotification    
    ;set up message text
    NotificationText = StrCat("%PNAME%: ", NotificationText, " ERROR=%ErrorLevel%")
    nerrtxt = "%PNAME%: Error Sending Notification"
    subject = "%PNAME%: Alert"

    ;write to NT Event Log
    if EventLog    
        if Task > 1
            Run(LogEventPath, StrCat('"', NotificationText, '"'))
        endif
    endif

    ;this is how many notifications we will need to send out    
    ic = ItemCount(AlertList, "|")

    ;send email notifications, one per
    ;if unsuccessful, record in the NT Event Log
    if SendEmail
        for i = 1 to ic
            ;for each operator on the alert list
            toaddr = ItemExtract(i, AlertList, "|")
            ErrorMode(@OFF)
            result = smtpSendText(MailServer, FromAddress, toaddr, subject, NotificationText)
            ErrorMode(@CANCEL)
            if !result
                if Task > 1
                    Run(LogEventPath, StrCat('"', nerrtxt, '"'))
                endif
            endif
        next    
    endif
    
    ;send pager notifications, one-shot
    ;if unsuccessful, record in the NT Event Log
    if SendPage
        key = ""
        for i = 1 to ic
            ;for each operator on the alert list                            
            k = ItemExtract(i, PagerKeyList, "|")
            key = StrCat(key, k, ",")
        next
        key = StrSub(key, 1, StrLen(key) - 1)
        ptext = StrCat("key: ", key, @CRLF, "msg: ", NotificationText)
        ErrorMode(@OFF)
        result = smtpSendText(MailServer, FromAddress, PagingAddress, subject, ptext)
        ErrorMode(@CANCEL)
        if !result
            if Task > 1
                Run(LogEventPath, StrCat('"', nerrtxt, '"'))
            endif
        endif
    endif
return

;----------------------------------------------------------------------
; SUBROUTINE: SendReport
;----------------------------------------------------------------------/
:SendReport    
    nerrtxt = "%PNAME%: Error Sending Statistics"
    subject = "%PNAME%: Statistics Report"
    
    if Notification
        ErrorMode(@OFF)
        result = smtpSendFile(MailServer, FromAddress, ReportAddress, subject, p1)
        ErrorMode(@CANCEL)
        if !result
            ;report can only be run from NT
            Run(LogEventPath, StrCat('"', nerrtxt, '"'))
        endif
    endif    
return

;----------------------------------------------------------------------
; SUBROUTINE: DisplayVerInfo
;----------------------------------------------------------------------/
:DisplayVerInfo
    MsgTxt = VERINFO
    gosub DisplayMessage
return

;----------------------------------------------------------------------
; SUBROUTINE: ErrorExit
;----------------------------------------------------------------------/
:ErrorExit
    IntControl(1000, ErrorLevel, 0, 0, 0)
    gosub DisplayMessage
    if ErrorLevel > 2
        MsgTxt = StrReplace(MsgTxt, "|", "@")
        ErrTxt = "ERROR|RESPONSE=0|ERRORLEVEL=%ErrorLevel%|%MsgTxt%"
        gosub WriteErrorFile
        if Notification
            gosub SendNotification
        endif
        ;if running as a service, do not exit
        if Task > 19 then return
    endif
    exit    
return    

;----------------------------------------------------------------------
; SUBROUTINE: ProgramExit
;----------------------------------------------------------------------/
:ProgramExit
    IntControl(1000, ErrorLevel, 0, 0, 0)
    exit    
return    

;----------------------------------------------------------------------
; SAMPLE INI FILE (save and remove semi-colons)
;----------------------------------------------------------------------/
;[Application]
;AppName=Symantec Visual Page
;AppFile=vpage.exe
;AppParms=
;
;[Run]
;AppPath=c:\app
;LicensePath=c:\app
;
;[Meter]
;AppPath=c:\app
;LicensePath=c:\app
;LogEventPath=c:\app
;
;[Notification]
;Notification=NO
;EventLog=YES
;AlertList=name1@yourdomain.com|name2@yourdomain.com
;PagerKeyList=pagerkey1|pagerkey2
;FromAddress=yourname@yourdomain.com
;ReportAddress=yourname@yourdomain.com
;NotificationText=An Error has occurred metering Symantec Visual Page. Please review the application error log for details.
;MailServer=mail.host.com
;PagingAddress=page@pager.host.com
;SendEmail=YES
;SendPage=YES
;SendShow=YES
;SendStats=YES
;
;[Service]
;MeterInterval=300
;MeterFrom=06:00
;MeterTo=18:00
;OpenLogOnStart=YES
;CloseLogOnStop=YES
;Application1=c:\app\pdcmeter.ini
;Application2=
;Application3=



Article ID:   W13798
Filename:   Software Metering Example.txt
File Created: 2000:12:26:14:01:28
Last Updated: 2000:12:26:14:01:28