Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.
Keywords: software metering
;---------------------------------------------------------------------- ; 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