Basic definition of a Windows Service is a program with no (or very little) user interface which provides programmatic services on the computer on which it is running. Real services though is registered in Windows' Service Control Manager Database and can be started, stopped, restarted, configured via the Services mode of the Computer Management Console.
However, if your need is just like mine, i.e., a VFP app continuously running in the background just to do some things for my other app, then this simple demo which does not really put the exe among the Windows Services is enough. What it will do is create a system tray icon to tell you it is running, then run continuously and on a specific time (which I control via passing the time as parameter to make it more flexible) will perform something for you (whatever you want that is possible).
That need on my end to create this service arises because our Group Financial Controller wanted me to create a way to track down stocks daily. And for that, I decided that instead of maintaining a table where I will transfer every day's stock to that for historical purposes which will eventually bloat that table very fast, it is better for me to create a snapshot via a CSV format of our stocks daily; saved inside a folder.
Brief History
That need was mentioned to me before my SWFox DevCon trip. What I have done then is I rushed a simple module to be performed at every day's end by our Warehouse Manager. Told him, "before going home click that, then click Perform EOD button. What it will do is it will create a snapshot of your stocks, both in CSV format and Pivot Report (via ssExcelPivot class), which the top management needs!". Showed him and he said ecstatic, "That's great! That will fix our need, don't worry I will do that daily!".
This morning though, I remembered about that snapshot thing and so I checked the folder where those go and to my dismay, it contains only the last snapshot during my demo to him. So I called him and said, "Hey! I checked, you never performed that EOD!". And he told me he is sorry but it always escapes his mind because of so many things to do and think of.
And so the thought of this service this morning.
Bernard Bout's ReduceMemory() Function
Observing, while the RAM consumption is low, it is slowly creeping up over time so I decided to incorporate WinAPI calls I have seen from Bernard Bout's ReduceMemory() function. The result is very satisfying as the memory usage of the service in process is always returning back to just around 840K. This is really among my favorite simple things, thanks Bernard!
What this service can do?
It creates a system tray icon of your choosing so you will be aware of the process. Plus it gives you a way out to kill the service via double-clicking on it.
It can run background processes you may need on your end in a specific time. In my end I need to create a snapshot of our daily stocks without user intervention. Maybe next week I will also loop on all tables and create a snapshot of the records via COPY TO < filename > TYPE CSV as an additional precaution against data loss. And maybe some more. Right now, I am running the service on our server so it will continue doing creating snapshots unimpeded.
Anyway, here are my codes so you can get an idea of how I use this on my end. You can create your own process in the Timer's Timer Event:
*************
* Service.prg
*************
Lparameters cTime
* For reducing memory eaten by
VFP as seen from Bernard Bout's ReduceMemory() function
Declare Integer SetProcessWorkingSetSize
In kernel32 As SetProcessWorkingSetSize ;
Integer hProcess , ;
Integer dwMinimumWorkingSetSize
, ;
Integer dwMaximumWorkingSetSize
Declare Integer GetCurrentProcess
In kernel32 As GetCurrentProcess
On Error Wait Window '' Nowait
* Set it to where your systray
class is
Set Classlib To 'c:\ssclasses\systray.vcx'
Local loSysTray,
loTimer
loSysTray = Createobject('myTray',
'systray.vcx')
loSysTray.TipText = "Snapshots set to run at "+Alltrim(m.cTime)+'! Double-click to Exit service..'
loSysTray.AddIconToSystray()
*** Add the needed _screen
properties
* for detecting of new day
_Screen.AddProperty('OldDate',Date())
* switch to ensure it will be
processed only once per day
_Screen.AddProperty('IsProcessing',.F.)
* to specify what hour to process
_Screen.AddProperty('TargetHour',Int(Val(Getwordnum(m.cTime,1,':'))))
*to specify what minute of the
hour to process
_Screen.AddProperty('TargetMins',Int(Val(Getwordnum(m.cTime,2,':'))))
loTimer = Createobject(
"myTimer" )
Read Events
Define Class myTray As systray
IconFile = Addbs(Justpath(Sys(16,0)))+"bcservice.ico"
* Use
Double-click to exit service
Function iconDblClickEvent
If Messagebox('Do you really
want to stop this service?',4+32,'Oooppppssss!') = 6
Clear Events
Endif
Endfunc
Enddefine
Define Class myTimer As Timer
Interval
=
1000
Function Timer
Local
lcMain,
lcPath, lcFile
lcMain
= Addbs(Justpath(Sys(16,0)))
lnHour
= Hour(Datetime())
lnMins
= Minute(Datetime())
* Check if it is
now time to perform the service
If m.lnHour >= _Screen.TargetHour And
m.lnMins >= _Screen.TargetMins And _Screen.IsProcessing = .F.
* Switch to .T.
so it won't be repeated until next day
_Screen.IsProcessing =
.T.
**** Place your
codes here like creating a compressed backup, cleaning temporary files used,
etc. ****
Endif
* If new date,
reset isProcessing back to false
If Date() > _Screen.OldDate
_Screen.OldDate = Date()
_Screen.IsProcessing =
.F.
Endif
* Reduce Memory
SetProcessWorkingSetSize(GetCurrentProcess(),-1,-1)
Endfunc
Enddefine
******* End Of Program
Additional Files Needed
You have to add the class systray found in VFP's Samples\Solution\Toledo sub-folder if you want to have a system tray icon. The files are: systray.vcx and systray.vct.
Create a new project and add that prg plus that class is all that is needed to make the exe running as a service later. Also, choose an icon to your liking so it can be displayed in the system tray.
If you use the codes above and just changed the insides of the timer event, then when you run it, pass a parameter for time like this:
C:\BizCore\bcservice.exe 17:00
Where 17:00 means run the event at 5PM of each day.
How to run it automatically with the unit?
Read this: http://sandstorm36.blogspot.com.au/2011/10/while-we-are-at-it-your-exe-and-nothing.html
As a Real Service?
If you are interested in creating a real service where you can NET START/STOP it, then read this:
http://blogs.msdn.com/b/calvin_hsia/archive/2004/12/13/282351.aspx
Benefits of having a Service
Your app is doing its normal things via user interactions like adding, editing, saving transactions, and generating reports. But there are things that needs to be done regularly like cleaning temporary files used, creating compressed backup of data, and other more things. However, if you leave the management of those I call end of the day processes to users, chances are, they may forget about it or simply not do those things.
A small service-like app such as this will fix that need for you because it can do those things on a scheduled time of your choosing not requiring any user interaction. Click it then leave it!
Hey Jun
ReplyDeleteVery cool and easy implementation!
Thanks a lot for sharing
Cesar
Thanks Cesar! You know I always love simple things, LOL!
Deletethanks for sharing....
ReplyDeleteYcongconZsopo Jared Ellenberg https://wakelet.com/wake/-0wb9v_bGWIeWe988ObyQ
ReplyDeletecoabestlugoo
0caucrucmult-dzu1993 Carol Collins Download
ReplyDeleteprograms
tadartestda