[Solucionado] Aplicación de Consola con Timer no funciona

Iniciado por Eleкtro, 3 Abril 2013, 13:33 PM

0 Miembros y 1 Visitante están viendo este tema.

Eleкtro

Este programa lo hice en un WinForm y funcionaba bien, pero luego decidí que me iba a ser más útil por consola así que modifiqué el tipo de proyecto a "consola", añadí un módulo, eliminé el formulario, pegué el código modificando el Timer para que funcionase y añadíendo el sub main...

Creo que no me ha faltado nada por añadir o modificar, pero el timer no me funciona, es decir, el sub que asocio al evento Elapsed no funciona

Código (vbnet) [Seleccionar]
   ' Lock Tick
   Public Sub Lock_Ticks()
       Console.WriteLine("test")
       'If Running Then Cursor.Position = New Point(Screen_Center_X, Screen_Center_Y)
   End Sub


(No escribe ninguna línea.)

En el form uso dos timers, y en cambio el otro timer ("Executable timer") si que me funciona perféctamente...

Este es el test del segundo timer (el que funciona):


Y este el del que no funciona (no bloquea el mouse, el evento Elapsed de ese timer no se ejecuta):


Me he asegurado de que el intervalo del primer timer es correcto, y en fin no sé que puede estar pasando...

Y como ya digo, si todo esto lo paso a un WinForm, vuelve a funcionar de forma correcta, no lo entiendo!.






Este es el proyecto completo, lo pueden probar:

Código (vbnet) [Seleccionar]
Module Module1

#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 System.Timers.Timer
   Dim Lock_Timer As New System.Timers.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

   ' Help
   Private Sub Help()
       Console.WriteLine( _
           "[+] Syntax:" & vbNewLine & _
           vbNewLine & _
           "    MouseLock {Executable Name}" & vbNewLine & _
           vbNewLine & _
           vbNewLine & _
           "[+] Syntax (using optional features):" & vbNewLine & _
           vbNewLine & _
           "    MouseLock {Executable Name} -S {Seconds} -I {Milliseconds} -K {Key}" & vbNewLine & _
           vbNewLine & _
           vbNewLine & _
           "[+] Options:" & vbNewLine & _
           vbNewLine & _
           " -S (or) -Sleep" & vbNewLine & _
           "    The time to wait until MouseLock will be activated." & vbNewLine & _
           "    * Default is ""3000""" & vbNewLine & _
           vbNewLine & _
           " -I (or) -Interval" & vbNewLine & _
           "    The time between the mouse locks" & vbNewLine & _
           "    * Default is ""10"", maybe want to use bigger numbers in slower PC's." & vbNewLine & _
           vbNewLine & _
           " -K (or) -Key" & vbNewLine & _
           "    The key for toogle between Enabled/Disabled while MouseLock is running." & vbNewLine & _
           "    * Valid keys: A-Z, 0-9 (Numpad) and F0-F12." & vbNewLine & _
           "    * All valid keys can be combined with ALT, CTRL or SHIFT." & vbNewLine & _
           vbNewLine & _
           vbNewLine & _
           "[+] Examples:" & vbNewLine & _
           vbNewLine & _
           "    MouseLock Game.exe" & vbNewLine & _
           "    MouseLock Game.exe -S 5" & vbNewLine & _
           "    MouseLock Game.exe -I 250" & vbNewLine & _
           "    MouseLock Game.exe -K F10" & vbNewLine & _
           "    MouseLock Game.exe -Sleep 10 -Interval 500 -Key ALT+Z")
   End Sub

   ' Pass arguments
   Private Sub Pass_Args()

       ' Empty?
       If My.Application.CommandLineArgs.Count = 0 Then
           Errors = True
           Help()
           End
       End If

       ' Executable Name
       If Not My.Application.CommandLineArgs.Item(0).ToLower.EndsWith(".exe") Then
           Console.WriteLine("Bad executable name: " & My.Application.CommandLineArgs.Item(0))
           Errors = True
       Else
           Executable_Name = My.Application.CommandLineArgs.Item(0).Substring(0, My.Application.CommandLineArgs.Item(0).Length - 4)
       End If

       For I As Integer = 0 To My.Application.CommandLineArgs.Count - 1

           ' Sleep
           If My.Application.CommandLineArgs.Item(I).ToLower = "-s" Or My.Application.CommandLineArgs.Item(I).ToLower = "-sleep" Then
               Try : Lock_Sleep = Get_Milliseconds(My.Application.CommandLineArgs.Item(I + 1))
               Catch
                   Console.WriteLine("Bad argument for -Sleep")
                   Errors = True
               End Try
           End If

           ' Interval
           If My.Application.CommandLineArgs.Item(I).ToLower = "-i" Or My.Application.CommandLineArgs.Item(I).ToLower = "-interval" Then
               Try : Lock_Interval = My.Application.CommandLineArgs.Item(I + 1)
               Catch
                   Console.WriteLine("Bad argument for -Interval")
                   Errors = True
               End Try
           End If

           ' Key
           If My.Application.CommandLineArgs.Item(I).ToLower = "-k" Or My.Application.CommandLineArgs.Item(I).ToLower = "-key" Then
               Try

                   If My.Application.CommandLineArgs.Item(I + 1).ToLower.StartsWith("alt+") Then
                       Toogle_Key = [Enum].Parse(GetType(System.Windows.Forms.Keys), My.Application.CommandLineArgs.Item(I + 1).ToLower.Replace("alt+", ""), True)
                       Toogle_Key_Global = Shortcut.Create(Shortcut.Modifier.Alt, Toogle_Key)
                   ElseIf My.Application.CommandLineArgs.Item(I + 1).ToLower.StartsWith("ctrl+") Then
                       Toogle_Key = [Enum].Parse(GetType(System.Windows.Forms.Keys), My.Application.CommandLineArgs.Item(I + 1).ToLower.Replace("ctrl+", ""), True)
                       Toogle_Key_Global = Shortcut.Create(Shortcut.Modifier.Ctrl, Toogle_Key)
                   ElseIf My.Application.CommandLineArgs.Item(I + 1).ToLower.StartsWith("shift+") Then
                       Toogle_Key = [Enum].Parse(GetType(System.Windows.Forms.Keys), My.Application.CommandLineArgs.Item(I + 1).ToLower.Replace("shift+", ""), True)
                       Toogle_Key_Global = Shortcut.Create(Shortcut.Modifier.Shift, Toogle_Key)
                   Else
                       Toogle_Key = [Enum].Parse(GetType(System.Windows.Forms.Keys), My.Application.CommandLineArgs.Item(I + 1), True)
                       Toogle_Key_Global = Shortcut.Create(Shortcut.Modifier.None, Toogle_Key)
                   End If

               Catch
                   Console.WriteLine("Bad argument for -Key")
                   Errors = True
               End Try
           End If

       Next

       If Errors Then End

   End Sub

   ' Sleep
   Private Sub Sleep()
       Console.WriteLine("Sleeping for " & (Lock_Sleep \ 1000) & " seconds before start locking the mouse...")
       Dim x As Integer = 0
       While Not x = (Lock_Sleep \ 1000)
           Threading.Thread.Sleep(1000)
           x += 1
       End While
   End Sub

   ' Lock
   Private Sub Lock()
       If Process_Is_Running(Executable_Name) Then
           AddHandler Lock_Timer.Elapsed, AddressOf Lock_Ticks
           AddHandler Executable_Timer.Elapsed, AddressOf Executable_Tick
           Lock_Timer.Interval = Lock_Interval
           'Lock_Timer.Interval = 100
           Lock_Timer.Start()
           Executable_Timer.Start()
           Running = True
       Else
           Terminate()
       End If
   End Sub

   ' Lock Tick
   Public Sub Lock_Ticks()
       Console.WriteLine("test - funciona el lock timer?")
       If Running Then Cursor.Position = New Point(Screen_Center_X, Screen_Center_Y)
   End Sub

   ' Executable Tick
   Private Sub Executable_Tick()
       Console.WriteLine("test - funciona el executable timer?")
       If Not Process_Is_Running(Executable_Name) Then Terminate()
   End Sub



   ' Esta parte no es necesaria para testear
   ' Toogle Key
   'Private Sub Toogle_Key_Global_Press(ByVal s As Object, ByVal e As Shortcut.HotKeyEventArgs) Handles Toogle_Key_Global.Press
   '    Select Case Running
   '        Case False
    '           Running = True
   '            Lock_Timer.Start()
    '       Case True
   '            Running = False
   '    End Select
   'End Sub



   ' Get Milliseconds
   Private Function Get_Milliseconds(ByVal Seconds As Int32) As Int32
       Dim Time_Span As New TimeSpan(TimeSpan.TicksPerSecond * Seconds)
       Return Time_Span.TotalMilliseconds
   End Function

   ' Process Is Running
   Public Function Process_Is_Running(ByVal Process_Name As String) As Boolean
       Dim myProcess As Process() = Process.GetProcessesByName(Process_Name)
       If Not myProcess.Length = 0 Then Return True Else Return False
   End Function

   ' Terminate
   Private Sub Terminate()
       Console.WriteLine("Application """ & Executable_Name & ".exe"" is not Running.")
       Console.WriteLine("MouseLock finished.")
       Application.Exit()
   End Sub

End Module








Eleкtro

#1
Ya lo he solucionado, aunque sigo sin entender el motivo... ¿Parece que los Timers los módulos los trata como subprocesos (Threads)?, parece como si la aplicación finalizaba antes de dejarle al timer hacer su trabajo.

Así que he tenido que usar un:
While Running : Application.DoEvents() : End While

Justo después de iniciar los timers, para que la aplicación no finalize.

Código (vbnet) [Seleccionar]
   Private Sub Lock()
       If Process_Is_Running(Executable_Name) Then
           AddHandler Lock_Timer.Elapsed, AddressOf Locker
           AddHandler Executable_Timer.Elapsed, AddressOf Executable_Tick
           Lock_Timer.Interval = Lock_Interval
           Lock_Timer.Start()
           Executable_Timer.Start()
           Running = True
           While Running : Application.DoEvents() : End While
       Else
           Terminate()
       End If
   End Sub


Por esta razón me funcionaba el timer en una class de un WF y no en un module, porque el module no espera a que el timer tickee...
¿Alguien me aclara esto?

Un saludo!








ABDERRAMAH

esque antes no has bloqueado el programa en un loop como ahora entonces sigue y termina. la forma correcta es la segunda, con un bucle while "running" y doevents.

Eleкtro

Tienes toda la razón, el fallo era muy obvio pero no me daba cuenta por despiste, es decir, como en la versión gráfica la instancia no termina hasta que se recibe el evento FormClosing, pues los timers hacian su trabajo "en segundo plano", pero en la versión de consola esto era imposible porque la instancia finalizaba justo después de iniciar el timer.     más o menos xD.

Saludos.








BlackM4ster

- Pásate por mi web -
https://codeisc.com

Eleкtro

No se me ocurrió nada más placentero que hacer un pequeño "homenaje" a las chonis. :silbar:

Saludos