Console Application with Timers and the Skype API - vb.net

so i have a problem, when trying to call the Skype API on a timer it gets nothing, im just trying to read messages on a loop and display them in my console, but on timer tick, nothing happens. But if i put the timer tick code in main it works fine. Here is my code:
Imports SKYPE4COMLib
Imports System.Timers.Timer
Module main
Dim oSkype As New SKYPE4COMLib.Skype
Dim aUser = oSkype.User("echo123")
Dim aChat = oSkype.Messages(aUser.Handle)
Dim tmr As New Timers.Timer
Sub Main()
tmr.AutoReset = True
tmr.Interval = 1000
AddHandler tmr.Elapsed, AddressOf tmrTick
tmr.Enabled = True
Console.ReadLine()
End Sub
Public Sub tmrTick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
For Each aMessages In aChat
Console.WriteLine(aMessages.FromHandle & ": " & aMessages.Body)
Next
Console.WriteLine("")
End Sub
End Module
Thanks,
Adam

Timers swallow exceptions, you might be getting an exception in the timer code, most likely a cross thread exception. Try settings visual studio to break on exceptions (debug > exceptions) and see if you get anything.
If you do get a cross thread exception, you wont be able to use System.timer timers as they run on the thread pool. in that case you should use a ui friendly timer such as the ones from winforms/wpf, or a dedicated thread

Related

WinForms.IllegalCrossThreadCall with filewatcher

I'm new to Visual Basic and overall kind of new to coding in general.
Currently I work on a program which uses a filewatcher. But If I try this:
Public Class Form1
Private WithEvents fsw As IO.FileSystemWatcher
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
fsw = New IO.FileSystemWatcher("PATH")
fsw.EnableRaisingEvents = True
' fsw.Filter = "*.settings"
End Sub
Private Sub GetSettingsFromFile()
Some Code
More Code
CheckBox1.Checked = True
End Sub
Private Sub fsw_Changed(sender As Object, e As FileSystemEventArgs) Handles fsw.Changed
fsw.EnableRaisingEvents = False 'this is set because the file is changed many times in rapid succesion so I need to stop the Filewatcher from going of 200x (anyone has a better idea to do this?)
Threading.Thread.Sleep(100)
GetSettingsFromFile()
fsw.EnableRaisingEvents = True 'enabling it again
End Sub
End Class
But when I do this (trying to change anyhting in the form) I get this error:
System.InvalidOperationException (WinForms.IllegalCrossThreadCall)
It wont stop the program from working, but I want to understand what is wrong here and why the debugger is throwing this at me
regards
The event is being raised on a secondary thread. Any changes to the UI must be made on the UI thread. You need to marshal a method call to the UI thread and update the UI there. Lots of information around on how to do that. Here's an example:
Private Sub UpdateCheckBox1(checked As Boolean)
If CheckBox1.InvokeRequired Then
'We are on a secondary thread so marshal a method call to the UI thread.
CheckBox1.Invoke(New Action(Of Boolean)(AddressOf UpdateCheckBox1), checked)
Else
'We are on the UI thread so update the control.
CheckBox1.Checked = checked
End If
End Sub
Now you simply call that method wherever you are and whatever thread you're on. If you're already on the UI thread then the control will just be updated. If you're on a secondary thread then the method will invoke itself a second time, this time on the UI thread, and the control will be updated in that second invocation.

Timer which can be called from a class and form both

I have a simple WinForm application. The main entry point of the application is mainForm. I am using a Timer on the form and the timer interval is being set to 2000ms. The Tick event of the Timer is as below,
Public myValue as Integer = 100
Private Sub myTimer_Tick(sender As Object, e As EventArgs) Handles myTimer.Tick
If myValue = 0 Then
myTimer.Enabled = False
Else
myValue = myValue -1
End If
End Sub
The timer is being called at the start of the application when mainForm is loaded. Now myValue is a global variable and here for the purpose of simplicity I have used this otherwise it is replaced by some process count mechanism which is not required to be explained here.
I am able to use this approach as long as I am using Windows.Forms.Timer placed on some specific Form. I have two more scenarios in which this approach fails.
1 - I have to use the same functionality on some other form and for this currently I am using a separate Timer on another Form and it has its own Tick event.
2 - I have to use the same functionality from another module/class and I am unable to achieve this because for this to work I require a Form.
Now for a start I have looked into Threading.Timer. The problem I am facing is that I don't know how to wait for Threading.Timer to finish as the control goes to next line after Threading.Timer is called. I am not sure whether this can be done with the help of WaitHandle or not. Also I have read that Threading.Timer creates a separate Thread for each of its Tick. This seems like an overkill in my simple scenario.
I just want to use the Timer functionality without the need of Form. Also I could create the similar functionality using a Do Loop with Thread.Sleep inside it but unless I am sure that my Timer functionality is not going to work in other situations I am going to stick to my Timer approach.
I see ... If thats the case, you should really create a second thread that runs a loop. That thread has some exiting parameters that indicates that operation is completed and the Thread itself is set to Isbackground = false.
However, you could also do this ...
Imports System.Timers
Public Class Main
Private Shared WithEvents m_oTimer As Timers.Timer = Nothing
Private Shared m_oWaitHandle_TimerHasCompleted As System.Threading.AutoResetEvent = Nothing
Public Shared Sub Main()
Try
'Application Entry point ...
'Create the global timer
m_oTimer = New Timers.Timer
With m_oTimer
.AutoReset = True
.Interval = 2000
.Start()
End With
'Create the WaitHandle
m_oWaitHandle_TimerHasCompleted = New System.Threading.AutoResetEvent(False)
'Show your form
Dim oFrm As New Form1
Application.Run(oFrm)
'Wait for the timer to also indicate that it has finished before exiting
m_oWaitHandle_TimerHasCompleted.WaitOne()
Catch ex As Exception
'Error Handling here ...
End Try
End Sub
Private Shared Sub m_oTimer_Elapsed(sender As Object, e As ElapsedEventArgs) Handles m_oTimer.Elapsed
'Timer will fire here ...
Try
If 1 = 2 Then
m_oWaitHandle_TimerHasCompleted.Set()
End If
Catch ex As Exception
'Error Handling ...
End Try
End Sub
End Class
Please note that 'm_oWaitHandle_TimerHasCompleted.Set()' will never run, you'll have to add a condition ... however, once run, the WaitOne will complete and the application will exit as required.
Hows zat?
Sounds to me like you want to create a single instance of a timer, that does not need to be instantiated via a form?
If so ... Create a new class called 'Main' and copy the following into it.
Imports System.Timers
Public Class Main
Private Shared WithEvents m_oTimer As Timers.Timer = Nothing
Public Shared Sub Main()
Try
'Application Entry point ...
'Create the global timer
m_oTimer = New Timers.Timer
With m_oTimer
.AutoReset = True
.Interval = 2000
.Start()
End With
'Show your form
Dim oFrm As New Form1
Application.Run(oFrm)
Catch ex As Exception
'Error Handling here ...
End Try
End Sub
Private Shared Sub m_oTimer_Elapsed(sender As Object, e As ElapsedEventArgs) Handles m_oTimer.Elapsed
'Timer will fire here ...
Try
Catch ex As Exception
'Error Handling ...
End Try
End Sub
End Class
Once done, right click on your project and select 'Properties'. In the Application tab you'll see a checkbox called 'Enable Application framework'. Uncheck this box. Now, in the dropdown called 'Startup Object' you should now see 'Sub Main' .... Select that.
When the application runs, Sub Main will now run instead of your form.
This will create the Timer that will fire outside of your form. Please note, as you're not syncing it, I believe it'll run inside a thread so be a little careful there :)

Application Ends when TimerCallback function executes

I was trying to create a very basic scheduler app in VB.NET (4.0). There is a form and button and label. So what exactly I want to happen is after 10 seconds the label text has to be changed. So here is the stuffs I did.
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim t As Timer
t = New Timer(New TimerCallback(AddressOf timerevent))
Dim scheduledTime As DateTime = DateTime.MinValue
scheduledTime = DateAdd(DateInterval.Second, 10, DateTime.Now)
Dim timespan As TimeSpan = scheduledTime.Subtract(DateTime.Now)
Dim dueTime As Integer = Convert.ToInt32(timespan.TotalMilliseconds)
t.Change(dueTime, Timeout.Infinite)
End Sub
Private Sub timerevent(e As Object)
Try
Label1.Text = Now.ToString
Catch ex As Exception
Label1.Text = ex.Message
End Try
End Sub
But the issue is timerevent fires correctly on 10 seconds, but immediately the application stops execution or ends up. I'm not getting an idea why this happen.
You're using the System.Threading.Timer which will fire the callback in ThreadPool thread.
Inside the callback you're updating the UI --which will result in InvalidOperationException. Agreed; you have a try/catch which will catch the exception but you again do the same mistake in catch block. Nobody can save you there.
You simply need to use System.Windows.Forms.Timer to fix the problem. This will work because the winforms Timer will fire the Tick event in UI thread.
Know the difference between Timers in .Net framework.

Basic delay command for Visual Basic

I need a wait command in Visual Basic that suits me.
I know:
Declare Sub Sleep Lib "kernel32.dll" (ByVal milliseconds As Long)
sleep 5000
But that makes the program unresponsive.
System.Threading.Thread.Sleep(5000) 'The window doesn't load until the timing is over (useless)
My code:
Imports Microsoft.Win32 'To check if is 64Bit or 32Bit
Public Class Loading
Private Sub Loading_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Registry.LocalMachine.OpenSubKey("Hardware\Description\System\CentralProcessor\0").GetValue("Identifier").ToString.Contains("x86") Then
My.Settings.Is64 = False
Else
My.Settings.Is64 = True
End If
'I need command here
If My.Settings.Is64 = True Then
Form64.Show()
Me.Close()
Else
MsgBox("No version developed for 32-bit computers.")
End
End If
End Sub
End Class
Errors:
#Idle_Mind
1. function 'OnInitialize' cannot be declared 'Overrides' because it does not override a function in a base class.
2. 'MinimumSplashScreenDisplayTime' is not a member of 'App.Loading.MyApplication'.
3. 'OnInitialize' is not a member of 'Object'.
From the comments:
Go into Project Properties and leave your main form as the Startup form. Set your splash screen form as the splash screen entry down at the bottom. Now click the "View Application Events" button to the right and override OnIntialize so you can set the MinimumSplashScreenDisplayTime() like this:
Namespace My
' The following events are available for MyApplication:
'
' Startup: Raised when the application starts, before the startup form is created.
' Shutdown: Raised after all application forms are closed. This event is not raised if the application terminates abnormally.
' UnhandledException: Raised if the application encounters an unhandled exception.
' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
Partial Friend Class MyApplication
Protected Overrides Function OnInitialize(ByVal commandLineArgs As System.Collections.ObjectModel.ReadOnlyCollection(Of String)) As Boolean
' Set the display time to 5000 milliseconds (5 seconds).
Me.MinimumSplashScreenDisplayTime = 5000
Return MyBase.OnInitialize(commandLineArgs)
End Function
End Class
End Namespace
If you want to execute the rest of your code after 5 seconds, why not create a separate thread/task, which will wait for 5 seconds and then trigger the rest of your code to run via a callback to the main thread? This approach will not hang your UI.
EDIT: If you want a splash screen, drop a Timer control, set the interval to 5 seconds and run the rest of your code inside a Tick event handler.
Assuming you have already set up the Timer, move your loading code into Timer1_Tick handler:
Public Class Loading
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
'part 1
If Registry.LocalMachine.OpenSubKey("Hardware\Description\System\CentralProcessor\0").GetValue("Identifier").ToString.Contains("x86") Then
My.Settings.Is64 = False
Else
My.Settings.Is64 = True
End If
'part 2
If My.Settings.Is64 = True Then
Form64.Show()
Me.Close()
Else
MsgBox("No version developed for 32-bit computers.")
End
End If
End Sub
End Class
Or leave part 1 in Load, and move part 2 into Tick. I would prefer this option for semantics.
Also don't forget to set Timer.Enabled = True.
If you want a place to CANCEL the application, you use the Application.Startup event and set e.Cancel = True from within there. When this is done the main form will not even appear; the application will simply exit. That could look something like:
Namespace My
' The following events are available for MyApplication:
'
' Startup: Raised when the application starts, before the startup form is created.
' Shutdown: Raised after all application forms are closed. This event is not raised if the application terminates abnormally.
' UnhandledException: Raised if the application encounters an unhandled exception.
' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(sender As Object, e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
If someCondition Then
MessageBox.Show("oops")
e.Cancel = True ' <-- main form will NOT show, app will simply exit
End If
End Sub
End Class
End Namespace
just do this:
For i As Integer = 1 To 500
System.Threading.Thread.Sleep(10)
System.Windows.Forms.Application.DoEvents()
Next
Edit: Be careful with DoEvents; it can cause problems if the user clicks on something or an event is processed when it shouldn't. See http://www.codinghorror.com/blog/2004/12/is-doevents-evil.html
Since sleeping and busy waiting are generally frowned upon, you could do something with an AutoResetEvent:
Private ReadOnly _resetEvent As AutoResetEvent = New AutoResetEvent(False)
Sub Pause(ByVal milliseconds As Long)
Dim waitInterval As TimeSpan = TimeSpan.FromMilliseconds(milliseconds)
While Not _resetEvent.WaitOne(waitInterval)
' Waiting!
End While
End Sub
This is not recommended, but here's an example using the System.Diagnostics.Stopwatch class:
Sub Pause(ByVal milliseconds As Long)
If milliseconds <= 0 Then Return
Dim sw As New Stopwatch()
sw.Start()
Dim i As Long = 0
Do
If i Mod 50000 = 0 Then ' Check the timer every 50,000th iteration
sw.Stop()
If sw.ElapsedMilliseconds >= milliseconds Then
Exit Do
Else
sw.Start()
End If
End If
i += 1
Loop
End Sub
And then where you need to pause, just call this Pause() method:
Pause(5000) ' Pause for 5 seconds

Console APP with Timer not running

I did this first into a WinForm project, now I've changed the application type to "Console application", I've deleted the form1.vb, changed the startup object to this "Module1.vb" but now I can't run the app.
well the app runs but the timer tick is doing nothing, the code is exactly the same, I only did one change for the sub main/form1_load name
What I'm doing wrong?
PS: I've tested if the error was in the conditional of the lock method and all is good there, the problem is with the ticker event but I don't know why.
#Region " Vars "
Dim Running As Boolean = False
Dim Errors As Boolean = False
Dim Executable_Name As String = Nothing
Dim Toogle_Key As System.Windows.Forms.Keys = Nothing
Dim WithEvents Toogle_Key_Global As Shortcut = Nothing
Dim Executable_Timer As New Timer
Dim Lock_Timer As New Timer
Dim Lock_Interval As Int32 = 10
Dim Lock_Sleep As Int32 = Get_Milliseconds(3)
Dim Screen_Center_X As Int16 = (Screen.PrimaryScreen.Bounds.Width / 2)
Dim Screen_Center_Y As Int16 = (Screen.PrimaryScreen.Bounds.Height / 2)
#End Region
' Load
Sub main()
Pass_Args()
Sleep()
Lock()
End Sub
' Lock
Private Sub Lock()
If Process_Is_Running(Executable_Name) Then
AddHandler Lock_Timer.Tick, AddressOf Lock_Tick
AddHandler Executable_Timer.Tick, AddressOf Executable_Tick
Lock_Timer.Interval = Lock_Interval
Lock_Timer.Start()
Executable_Timer.Start()
Running = True
Else
Terminate()
End If
End Sub
' Lock Tick
Private Sub Lock_Tick()
Console.WriteLine("test")
If Running Then Cursor.Position = New Point(Screen_Center_X, Screen_Center_Y)
End Sub
UPDATE
I made these changes like in the examples of MSDN:
Dim Executable_Timer As New System.Timers.Timer
Dim Lock_Timer As New System.Timers.Timer
AddHandler Lock_Timer.Elapsed, AddressOf Lock_Tick
AddHandler Executable_Timer.Elapsed, AddressOf Executable_Tick
But the tick/elapsed is still doing nothing...
FROM MSDN
Windows.Forms.Timer
Implements a timer that raises an event at user-defined intervals.
This timer is optimized for use in Windows Forms applications and must
be used in a window.
You need a System.Timer
Of course this requires a different event Handling
(Example taken from MSDN)
' Create a timer with a ten second interval.
Dim aTimer = new System.Timers.Timer(10000)
' Hook up the Elapsed event for the timer.
AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
....
Private Shared Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime)
End Sub
You could use Windows.Forms.Timer in console application if you add Application.Run() at the end of your main().
This kind of timer might be useful in some console applications if you are using any offscreen Windows.Forms object - ie.: for offscreen rendering - these objects can't be simply accessed from System.Timer since it fires on separate thread (than the one where Windows.Forms object was created on).
Otherwise by all means use the System.Timers.Timer or System.Threading.Timer