VB.NET Multithreaded SerialPort SMS Delay - vb.net

Wanna ask if how can I can create a delay without using System.Thread.Sleep(interval).
My apps serves as server runs in a endless loop that reads SMSINBOX using serialport to interface with a GSM MODEM.. readSMSINBOX() is followed by a delay ... The problem here is the delay thats kills me.... It hangs all the controls of my app. Other functions aside from reading, is sending, userMANAGEMENT, console, etc. Any idea how I can implement a delay that consumes time WITHOUT hanging the app by using SYSTEM.TIMERS or SYSTEM.THREADING or BACKGROUNDworker... Please... I can't post all my codes here.. Don't know either how to publish my code in a live site. Just a pure NOOB..

Well the timer should do exactly what you need (it doesn't block the UI).
Exact implementation of timer depends on version of VB.NET you're using but
you can find a good (and downloadable) example of using timers here: Working with Timer Control in VB.NET
You'll have to import System.Timers
myTimer can be variable in the code of main form
Timer myTimer
You can set it up and start it in Form1_load
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)
myTimer = new Timer(30000)
myTimer.Enabled = true
addhandler myTimer.Tick,addressof OnTimerEvent
End Sub
And your (tick) handler would be something like:
Private Sub OnTimerEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)
'here you can call you communication routines
End Sub

Related

How do I run a background worker on an infinite loop

I am developing a plugin for an application. I need to implement a low-level keyhook to capture keys. I have tried running the keyhook on the same thread as the main application + plugin, but it's performance is hit and miss. I'm not able to query this with the application's original developer.
Thus, I've implemented the code below to run the keyhook on a backgroundworker. It works reliably, but I'm very conscious of the Application.DoEvents I understand this is bad. The code:
Private WithEvents KeyHookBGW As New BackgroundWorker
Private WithEvents KeyHook As New WindowsHookLib.KeyboardHook
Private Sub KeyHookBGW_DoWork(sender As Object, e As DoWorkEventArgs) Handles KeyHookBGW.DoWork
Dim BgKeyhook As New KeyboardHook
BgKeyhook.InstallHook()
AddHandler BgKeyhook.KeyDown, AddressOf KeyHookBGW_KeyDown
Do While e.Cancel = False
Application.DoEvents()
Loop
End Sub
Private Sub KeyHookBGW_KeyDown(sender As Object, e As WindowsHookLib.KeyboardEventArgs)
KeyHookBGW.ReportProgress(0, e.KeyCode)
End Sub
Private Sub KeyHookBGW_ReportProg(sender As Object, e As ProgressChangedEventArgs) Handles KeyHookBGW.ProgressChanged
pm.Console.WriteLine("Key pressed: " & e.UserState)
End Sub
I'm sure my architecture is bad, but I'm a bit stuck with getting this to work in the development context. I tried using a timer in the background thread, but couldn't get this to work. I'm also developing in .net Framework 3.5 (original application's framework) and thus this limits what I can do with Threads, I think. I've looked into Threads and I am struggling to understand how to run them infinitely and also communicate back to the main thread.
So, basically, I'm needing to run the keyhook on a separate thread for the lifetime of the main application + plugin and feed back any keydown and keyup events into the main thread. Any ideas?

winform and session timeout

I have a vb.net winform and I want to know how to add sort of like a session time out to it. For example, I have a varialbe set to 10 min, within that 10 min, if there is no activity (no mouse/no keyboard interaction), I would like to log the user out. Can anyone shine some light on this subject on how to make this work?
First question, why do you want to do in a winform. Such things we generally use in web forms. But even you want to use such things in WinForms you need to use Timer Class.
Whenever you encounter activity, you can just reset the timer by calling Stop then immediately calling Start. Place whatever code you'd like in the Timer's Tick event (assuming this is a System.Windows.Forms.Timer) and you'll be all set.
I'd suggest you use the event Application.Idle.
No need to P/Invoke.
Public Class Form1
Private WithEvents _timer As Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 10 seconds for testing
Me._timer = New Timer With {.Interval = 10000, .Enabled = True}
AddHandler Application.Idle, AddressOf Me.Application_Idle
End Sub
Private Sub Application_Idle(sender As Object, e As EventArgs)
Me._timer.Stop()
Me._timer.Start()
End Sub
Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles _timer.Tick
Me._timer.Stop()
RemoveHandler Application.Idle, AddressOf Me.Application_Idle
' Do something to log the user out
Me.Close()
End Sub
End Class
If you are looking for a way to detect input outside your application Amit's suggestion will not work.
See Detecting idle users in Winforms if that is the case. Calling GetLastInputInfo() and checking the last input value should give you something to go off.
If you are not worried about the user leaving your application, and getting logged out after not using it, use Amit's way of resetting a timer on the input event.

Timer does not work

I try to run a timer from my winform application. For some reason the function that should run on the timer's tick (IsTimeOffsetValid) is not called nor stopped on break point, and basically nothing happens. I attached a code sample below.
I appreciate the help.
Module Module1
Sub main()
Dim OutputForm As New Form17
Application.Run(OutputForm)
End Sub
End Module
Public Class Form17
Private TimerServerOffset As New System.Timers.Timer
Private Sub Form17_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
AddHandler TimerServerOffset.Elapsed, New System.Timers.ElapsedEventHandler(AddressOf IsTimeOffsetValid)
TimerServerOffset.Interval = 1
TimerServerOffset.Start()
End Sub
Private Sub IsTimeOffsetValid()
MsgBox("IsTimeOffsetValid")
End Sub
End Class
Apart from errors in the code that you posted there are other issues with the design.
Read this question: System.Timers.Timer vs System.Threading.Timer
The callback is called on a worker thread (not the UI thread) so displaying a message box could be a big problem.
then switch to a more fitting timer. If all you want to do is validate the inputs every second, switch to the System.Windows.Forms.Timer. The tick handler runs on the UI thread so you can change the UI in the handler.
Then consider changing the interval a message box popping up every millisecond is not possible and not user friendly.
Finally, I would suggest NOT using a timer for this: just handle changes to the input fields and respond to changed inputs or use the standard validation events of the WinForms controls. This is much cheaper (on the CPU) and will not mess with the focus.

VB.NET background worker 60 seconds timeout

During the startup of my app I am doing a long database upgrade.
Before that starts, I show a form that has a progressbar so that the user knows that something is going on and he should wait.
To not block the progressbar from redrawing, I do the database upgrade in a background worker.
The code looks like this:
frmMain_Load(...)
Dim wait As New frmWait
wait.Show()
Dim bw As New frmBWRebuildUserData
bw.Start()
Do While Not bw.Done
System.Threading.Thread.Sleep(100)
Loop
'Okay, db update was done, now continue and show the main app window
My frmBWRebuildUserData looks like this:
Public Class frmBWRebuildUserData
Private m_bDone As Boolean
Public ReadOnly Property Done() As Boolean
Get
Return m_bDone
End Get
End Property
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
modAppDB.RebuildUserDB()
End Sub
Public Sub Start()
Me.BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
m_bDone = True
End Sub
End Class
But after 60 seconds, VB.NET tells me that there were no messages since 60 seconds (I guess you know this error).
But since the background worker is intended for such purposes, I think I am doing something substantially wrong here, but I can't figure out what.
Also, my progressbar is not redrawing.
Can somebody help, please?
Thank you very much!
A couple of things.
There is no built in timeout of 60 seconds in the backgroundworker. So it should be something in your code.
Why do you use a backgroundWorker and then introduce in your code a sleep cycle? The backgroundworker should be used to free the user interface from waiting for the end of long operations.
The backgroundworker when asked to report its progress to a user interface element needs something like this (sorry is C#, but I think you can get the point)
backgroundworker.ProgressChanged += backgroundworker_ProgressChanged;
backgroundworker.WorkerReportsProgress = true;
in this scenario your modAppDB.RebuildUserDB() need to call
backgroundworker.ReportProgress(percentComplete);
for every step that you want to communicate to the progress bar and of course, you need in the form where the progressbar is displayed to intercept the event fired by the ReportProgress call
private void backgroundworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = (e.ProgressPercentage.ToString() + "%");
}
The Backgroundworker is mainly good for tasks where you have a loop inside DoWork, which allows you to do some UI feedback within the loop. If your DoWork just calls another command, it will wait for this command to finish and not do anything in this time. Other than that, using the BGW still allows for the main thread to handle its messages and not get blocked, so I presume it is still entirely right to use it here.
Apart from that, your backgroundworker1 is not declared, and as Steve pointed out, your Start()-Method needs at least this first line:
Addhandler Backgroundworker1.DoWork, AddressOf BackgroundWorker1_DoWork. This triggers the function when RunworkerAsync is called.
For a basic example of thread-communication (and fundamental problems connected with it) take a look at this question and answer:
Multithreading for a progressbar and code locations (vb.net)?
I don't know about the 60 seconds issue either.

Why does having a media player running removes audio latency of my VB.NET application?

I'm having a weird problem when playing a wav file (0.034 seconds long) embedded as a resource on my VB.NET application.
My application is supposed to loop the sound asynchronously while the button is pressed and stop the sound when the button is released.
The problem is that there seems to be a delay when the button is pressed and released quickly, especially if it is clicked multiple times in a row.
This delay makes the audio sound choppy and it also hangs the application until the queue of calls to play() and stop() ends.
However, I noticed that if I have an audio player running (playing a sound file or paused, not in stop) simultaneously when running my application, the delay or latency is gone.
The players I have tested have been: Windows Media Player, Windows Media Player Classic - Home Cinema, Foobar2000 and QuickTime.
Here's the code:
Option Explicit On
Option Strict On
Public Class frmMain
Private btnPlayPressed As Boolean
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
btnPlayPressed = False
End Sub
Private Sub btnPlay_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnPlay.MouseDown
If Not btnPlayPressed Then
My.Computer.Audio.Play(My.Resources.Beep, AudioPlayMode.BackgroundLoop)
btnPlayPressed = True
End If
End Sub
Private Sub btnPlay_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnPlay.MouseUp
If btnPlayPressed Then
My.Computer.Audio.Stop()
btnPlayPressed = False
End If
End Sub
Private Sub btnPlay_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles btnPlay.KeyDown
If e.KeyCode.Equals(Keys.Space) Then
btnPlay_MouseDown(sender, Nothing)
End If
End Sub
Private Sub btnPlay_KeyUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles btnPlay.KeyUp
If e.KeyCode.Equals(Keys.Space) Then
btnPlay_MouseUp(sender, Nothing)
End If
End Sub
End Class
I have also used various of the other audio functions available in VB.NET and they all have this problem but I'm sticking with My.Computer.Audio because of it's simplicity and readability.
Why does having audio players running remove the delay of My.Computer.Audio.play?
Is there a way to remove the delay from within my code?
Other details:
IDE: Visual Studio 2010 Express
OS: Vista sp2 x86/ Windows 7 x64
There could be a couple reasons for this. The first might be that other software is specifically lowering the buffer size for playback. When this is done, there is lower delay.
The second reason might have to do with the sampling rate. If there is a buffer size set in bytes and the sample rate doubles, then that buffer lasts half as long. If you are playing audio in your application at a certain rate, and other software plays at a different rate, then perhaps Windows' audio mixing service adjusts the buffer differently.
There is no way to remote delay completely. That's not how digital audio works. However, you can reduce it significantly by using ASIO or similar.