detect system date change, visual basics - vb.net

I am writing an application on Windows-7 using Visual Basics 2010. I am accessing System Date with
Dim today As Integer
today = Format(Now, "dd")
Well, that works fine. But I need some indication/notification when system date changes, so that I can retrieve the new date. Is there any function/way to achieve that ?
Thanks

The system date may change for two reasons:
The user manually changed the system date/time. This can be detected using the method described here: http://vbnet.mvps.org/index.html?code/subclass/datetime.htm
Time passes, the clock goes from 23:59:59 to 00:00:00. I'm don't know of any system event that will tell you when this happens, but you can detect it easily by using a Timer in VB6. By using a Timer you will get an event at a predefined interval. You might then check, say everey minute, if the date has changed.
To use the standard VB6 Timer control, you need a Form on which you put your Timer, but there are other alternatives, like this one: http://www.codeproject.com/KB/vb-interop/TimerLib.aspx
My code example uses the standard VB6 Timer on a Form to watch for "change in minute". My Timer control has the original name of Timer1
Dim iMinute As Integer 'The "current" minute
Private Sub Form_Load()
'Initialize
iMinute = Format(Now, "n") 'Get the current time as minute
Timer1.Interval = 1000 'Set interval = 1000 milliseconds
Timer1.Enabled = True 'Start Timer1 (my Timer)
End Sub
Private Sub Timer1_Timer()
'This happens when the given Interval has passed (in this case, every second)
Dim iMinuteNow As Integer
iMinuteNow = Format(Now, "n")
If iMinuteNow <> iMinute Then
MsgBox "You are now in a new minute"
iMinute = iMinuteNow
End If
End Sub

Related

Monitor user activity in vb.net

I would like to make a program that monitors user activity. I do not need to know what the user is doing, all i need to know is that he is doing something. Moving the mouse, or typing. The program will be used to show to the company who is at the desk and who is gone from the workstation. So if there is no activity for 2 minutes, that means that the user is away from the computer.
I was thinking of using the keyboard hook and the mouse position to monitor changes every lets say 5 seconds. On every change I will reset the counter.
Is there a better way? (For example reading the screensaver countdown or something like that)
You can P/Invoke the WinAPI's GetLastInputInfo() function to be able to get the millisecond count at which point the last input was received since the computer was started.
Subtracting Environment.TickCount with the above will give you how many milliseconds have lapsed since the last input was received:
<DllImport("user32.dll")> _
Public Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)> _
Public Structure LASTINPUTINFO
<MarshalAs(UnmanagedType.U4)> _
Public cbSize As Integer
<MarshalAs(UnmanagedType.U4)> _
Public dwTime As Integer
End Structure
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
Dim LastInput As New LASTINPUTINFO With {.cbSize = Marshal.SizeOf(GetType(LASTINPUTINFO))} 'The "cbSize" field must be set every time we call the function.
If GetLastInputInfo(LastInput) = True AndAlso _
(Environment.TickCount - LastInput.dwTime) >= 120000 Then '120000 ms = 120 s = 2 min.
Timer1.Stop()
'Computer has been idle for 2 minutes. Do your stuff here.
End If
End Sub
This will check for both mouse and keyboard input.
The Timer's Interval property is set to 5000 to make it check every 5 seconds, and the Enabled property is set to True.
Keep in mind that you must restart the timer after the two minutes of idle time have lapsed if you want it to check again.

Why is basic time/date output taking two seconds to display?

What I have:
I'm displaying the current time and date (real-time) at the bottom of a form using a timer element.
I'm using two labels to display the time and date respectively.
What I need:
I need the time and date labels to display as instantly as everything else.
My problem:
There is a two second delay in the displaying of the time and date labels.
My code:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
'Format time and date labels.
TimeMain.Text = Format(Now, "hh:mm:ss")
DateMain.Text = Format(Now, "dddd, d/MM/yyyy")
End Sub
Note: The above is preceded by a Form_Load sub that simply defines a default accept button. The above is followed by 5 by five short subs.
Edit:
Though the steps for reproducing the problem have already provided in the comments I've been requested to reiterate here. The only difference between the two code blocks posted in this question is that I've left the label text at default to spare the reproducer having to type anything.
Drag two labels and a timer onto a new form and use the following code:
Public Class Form1
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
'Format time and date labels.
Label1.Text = Format(Now, "hh:mm:ss")
Label2.Text = Format(Now, "dddd, d/MM/yyyy")
End Sub
End Class
For the timer's properties, Enabled is defined as True and Interval as 1000.
I know this isn't exactly an answer but this is too long to fit in a comment. Also read here for a little more information on timers:
Why are .NET timers limited to 15 ms resolution?
Does the System.Windows.Forms.Timer run on a different thread than the UI?
Timer elapsed events from what i understand (which could very well be wrong) aren't guaranteed to fire exactly when the time has elapsed, it's more of... put it in queue to fire once the timer has elapsed.
Imagine your application/timer started at "00:00:01.999" and your label states "00:00:01" as the current time.
Exactly 1000 MS later you're at "00:00:02.999 and the elapsed event fires, completing at "2014-01-01 00:00:03.0045" and your label is updated to "2014-01-01 00:00:03" - you've already "lost" a second here.
You could try setting your interval to something lower than one second (say 750) which would get you a potentially more accurate looking counter. Additionally, ensure you're setting the timer labels on form load. I've not worked very much with timers and i'm having trouble finding the article i was reading earlier but you might need to worry about UI locking depending on the timer type used (there are apparently 4 timer classes in the .net framework.) Perhaps someone else can expand on that though, I don't know much about winforms.

Replacing my function with a better one

i'm trying to popup a msgbox everytime the current time is equal to a field in a table in the database i'm using the following code:
For i As Integer = 0 To contentTable.Rows.Count() - 1
UpdateListBoxRec2("Sending content " & i + 1 & " to :")
For j As Integer = 0 To subTable.Rows.Count() - 1
While send = False
If contentTable.Rows(i).Item(1) = DateTime.Now.ToString("hh:mm") Then
UpdateListBoxRec2(subTable.Rows(j).Item(0))
MsgBox(contentTable.Rows(i).Item(0))
send = True
End If
End While
'send = False
Next
Next
this method works but when the debugger is in the while loop ( means when the current time is not yet equal to the time i have in my db table ) i can't use any tool of my windows app untill the debugger gets out of the while loop so i'm searching for a similar method to popup my msgbox in the same condition and to be able to use my tools in the app all the time
please note that i'm using vb.net
any help please :)
You should never sit in an endless loop, like that, on the UI thread. As long as the UI thread is busy, it will be blocked from processing any incoming window messages (e.g. key strokes, mouse clicks). You could sit in a loop like that if you were on a separate thread, but that would be silly. The more sane solution would be to use a timer. For instance, if you drop a Timer component onto your form in the designer, and set it's Interval property to 5000 (five seconds), you can then add the following code:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
For i ...
For j ...
If contentTable.Rows(i).Item(1) = DateTime.Now.ToString("hh:mm") Then
UpdateListBoxRec2(subTable.Rows(j).Item(0))
MessageBox.Show(contentTable.Rows(i).Item(0))
End If
Next
Next
End Sub
Now it will just run that code once every five seconds rather than continuously checking the current time and thereby hogging the UI thread.

Terminate thread execution for 24 hours

I have my service working mostly as it should, but it should only do it's work once every day.
To arrange this, my boss recommended I sleep the worker thread until 7am tomorrow:
This Thread.Sleep call is copied directly from a similar service he wrote that apparently works, but this always throws an ArgumentOutOfRangeException - the value returned is a negative.
Private Sub startExport()
#If Not Debug Then
Thread.Sleep(1000 * 60 * 1)
#End If
While runReportExport
Try
runExport()
Catch ex As Exception
el.WriteEntry("Error exporting data: {1}")
Finally
'sleep thread until tomorrow 7am
Thread.Sleep(DateTime.Now.Subtract(Date.Today.AddDays(1).AddHours(7)))
End Try
End While
End Sub
I'm fairly confused about how this all works so if anyone can explain the whole timespan thing for me, I'd greatly appreciate it.
On the other hand, my friend recommends I manage the thread execution in a different way.
Here's what He recommended I do:
Private lastExecute As DateTime = DateTime.Now
Private Overrides Sub OnStart(ByVal args() As String)
startService()
End Sub
Private Sub startService()
Dim nextExecute = lastExecute.AddDays(1)
If nextExecute >= DateTime.Now Then
lastExecute = DateTime.Now
tWorker = New Thread(AddressOf startExport)
tWorker.IsBackground = True
tWorker.Start()
End If
End Sub
He said this would execute the worker thread once on startup and not again for another day. While this code does work without error, it doesn't stop the service loop from executing the worker thread over and over again (currently it executes a 2nd time as soon as it finished it's first run)
Personally I'm open to either approach, I can't seem to get either working.
Basically, all I need at the end of the day is a service that exports data once daily.
My boss' Thread.Sleep option seems the simpler, but my friend's suggestion seems like better practice.
Can anyone help me to get this sorted (at this point I don't care which one I use, just so long as it works)?
DateTime.Now.Subtract(Date.Today.AddDays(1).AddHours(7)))
You subtract a future time from the current time. That always produces a negative value. Kaboom.
You'll need to invert that, subtracting the current time from the future time. Spelled out for clarity and avoiding the race on DateTime.Now :
Dim today = DateTime.Now
Dim tomorrow = today.Date.AddDays(1).AddHours(7)
Dim wait = tomorrow - today
Thread.Sleep(wait)
You will need to do something useful when the service is stopped. Best done with a ManualResetEvent, you'll get the sleep from its WaitOne(wait) method. Btw, extremely wasteful to have a thread sleep for that long and not doing anything useful. Use a Timer instead.
Another approach, and one I use, to run a specific task once a day is to set the task up in a timer. In my case I want the task to run at 12:05am each morning. Accordingly, when my program starts I set the initial interval of the timer such that the first tick will happen at 12:05 am the next day. After that, once a day, at the end of the code the executed as part of the tick I once again reset the timer interval such that the next tick will happen at 12:05am the next day.
...
Timer1.Interval = MillisecondsToMidnight() + 300000 ' next tick 12:05:00 tomorrow
...
Private Function MillisecondsToMidnight() As Integer
Dim ReturnValue As Integer
Dim ts As TimeSpan
Dim Tomorrow As DateTime = Today.AddDays(1)
ts = Tomorrow.Subtract(Now)
ReturnValue = ts.TotalMilliseconds()
ts = Nothing
Return ReturnValue
End Function

Console app timer to call web methods every x minutes

I am coding in VB.Net, VS 2008.
I wrote a console app that consumes 2 web methods from a web site application. I need to enhance this console app so that it launches the web methods continuously, perhaps every x minutes (during business hours), but never before the last invocation has terminated, whose duration may vary, depending on how many accounts there are to process.
Originally, I scheduled the application using Task Scheduler, but I think this doesn't prevent two invocations at the same time.
Although I have seen many posts on using timers, I haven't found exactly what I need.
So far I have:
Dim aTimer As New System.Timers.Timer()
AddHandler aTimer.Elapsed, AddressOf TriggerWebMethods
' Set the Interval to 10 minutes:
aTimer.Interval = 1000 * 60 * 10 '(1 second * 60 = 1 minute * 10 = 10 minutes)
aTimer.Enabled = True
aTimer.AutoReset = True
When should Timer.Elapsed be used vs. Timer.Tick?
What is the difference between Timer.Enabled vs Timer.Start, and should I be selecting just one?
I would like the 2nd web method to kick off when the first one is done.
I'd like to keep this as simple as possible. Thank you for all help.
If you are dealing with a System.Timers.Timer, then you'd only have the Elapsed event available. If a System.Windows.Forms.Timer, then you'd use the Tick event. You're not writing a WinForms app so you would be using the System.Timers.Timer.
Personally, I would only use the Enabled property to see if the timer has been started. I wouldn't use it to start or stop it. Using the Start() or Stop() method makes it very clear what's happening to the timer.
If your web methods execute synchronously, you could just call them one after the other in your TriggerWebMethods() method. The second will not be called until the first completes.
Sub TriggerWebMethods(source As Object, e As ElapsedEventArgs)
FirstWebMethod()
SecondWebMethod()
End Sub
If asynchronously, you'd have to register a callback on the first web method to execute the second when it completes. In VB, I believe you can use the second directly as the callback, depending on how you make the asynchronous call. (Sorry, my VB is very rusty now so might not be 100% correct syntax)
Sub FirstWebMethod()
' ...
End Sub
Sub SecondWebMethod()
' ...
End Sub
Sub TriggerWebMethods(source As Object, e As ElapsedEventArgs)
Dim first As Action = AddressOf FirstWebMethod
first.BeginInvoke(AddressOf SecondWebMethod, first)
End Sub
Just to add a little to Jeff M's answer. The Timer.Elapsed Event has the following note.
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If the
processing of the Elapsed event lasts
longer than Interval, the event might
be raised again on another ThreadPool
thread. In this situation, the event
handler should be reentrant.
Since you're in a Console app you can either hand roll you own SynchronizingObject or you can set the AutoReset to False, and change your TriggerWebMethods to have a start at the end. You may even want to offset the interval to take into consideration the amount of processing time.
e.g.
Dim start As Date = Now
'do stuff
Dim ts As TimeSpan = Now - start
Dim i As Integer = (1000 * 60 * 10) - ts.TotalMilliseconds
Dim aTimer As Timers
aTimer.Interval = i