Buen día a todos, quisiera que me apoyen en poder ver cual es mi error ya que al momento de ejecutar la app se marca error en la linea txtResults.Text = SR.ReadToEnd.
La idea es que en vez que se muestre en la ventana del cmd, figure en el cuadro de texto txtResults y sería mucho mejor si fuera continuo o sea el resultado de ping 127.0.0.1 -t figure en el cuadro de texto.
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
Dim CMDThread As New Threading.Thread(AddressOf CMDAutomate)
CMDThread.Start()
End Sub
Private Sub CMDAutomate()
Dim PROCESO As New Process
Dim INFO As New System.Diagnostics.ProcessStartInfo
INFO.FileName = "cmd"
INFO.RedirectStandardInput = True
INFO.RedirectStandardOutput = True
INFO.UseShellExecute = False
PROCESO.StartInfo = INFO
PROCESO.Start()
Dim SR As System.IO.StreamReader = PROCESO.StandardOutput
Dim SW As System.IO.StreamWriter = PROCESO.StandardInput
Dim comandoping As String = String.Concat("ping ", TextBox1.Text, ".", TextBox2.Text, ".", TextBox3.Text, ".", TextBox4.Text)
SW.WriteLine(comandoping)
SW.WriteLine("exit")
txtResults.Text = SR.ReadToEnd
SW.Close()
SR.Close()
End Sub
Gracias por todo. Saludos.
Cita de: rochro en 11 Noviembre 2014, 15:39 PMal momento de ejecutar la app se marca error en la linea txtResults.Text = SR.ReadToEnd.
1. Cuando tengas un error, por favor da los detalles necesarios para poder ayudarte.
El mensaje exacto de error que te indica el debugger de VisualStudio. ya que de lo contrario estamos haciendo el paripé sin tener información precisa.
Sea cual sea el error que te indique imagino que es porque estás intentando modificar un control desde un Thread distinto al Thread donde creaste el cotnrol. es decir, tienes el control
txtResults en el thread "X" e intentas modificarlo desde el thread "Y", no puedes modificar un control así como así desde otro thread, primero debes comprobar si el control necesita ser invocado, y después, invocarlo.
Ejemplo:
Imports System.Threading.Tasks
Public Class Form1
''' <summary>
''' The CMD <see cref="System.Diagnostics.Process"/> instance.
''' </summary>
Private WithEvents cmdProcess As New Process With
{
.EnableRaisingEvents = True,
.StartInfo = New ProcessStartInfo With
{
.FileName = "cmd.exe",
.Arguments = String.Empty,
.RedirectStandardInput = False,
.RedirectStandardOutput = True,
.RedirectStandardError = True,
.UseShellExecute = False,
.CreateNoWindow = True
}
}
''' <summary>
''' Gets the ping commandline arguments.
''' </summary>
Private ReadOnly Property PingArguments As String
Get
Return String.Format("ping.exe ""{0}.{1}.{2}.{3}""",
TextBox1.Text, TextBox2.Text,
TextBox3.Text, TextBox4.Text)
End Get
End Property
Private Sub btnSend_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnsend.Click
Task.Factory.StartNew(AddressOf CMDAutomate)
End Sub
Private Sub CMDAutomate()
With Me.cmdProcess
.StartInfo.Arguments = String.Format("/C ""{0}""", Me.PingArguments)
.Start()
.BeginOutputReadLine()
.BeginErrorReadLine()
.WaitForExit()
End With
End Sub
''' <summary>
''' Occurs when an application writes to its redirected <see cref="System.Diagnostics.Process.StandardOutput"/> stream.
''' Occurs when an application writes to its redirected <see cref="System.Diagnostics.Process.StandardError"/> stream.
''' </summary>
Private Sub cmdProcess_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs) _
Handles cmdProcess.OutputDataReceived,
cmdProcess.ErrorDataReceived
Select Case txtResults.InvokeRequired
Case True
txtResults.Invoke(Sub() txtResults.AppendText("" & e.Data))
txtResults.Invoke(Sub() txtResults.AppendText(Environment.NewLine))
Case Else
txtResults.AppendText(e.Data)
txtResults.AppendText(Environment.NewLine)
End Select
#If DEBUG Then
' Debug.WriteLine(e.Data)
#End If
End Sub
''' <summary>
''' Occurs when a <see cref="System.Diagnostics.Process"/> exits.
''' </summary>
Private Sub cmdProcess_Exited(ByVal sender As Object, ByVal e As EventArgs) _
Handles cmdProcess.Exited
Debug.WriteLine(String.Format("cmdProcess has exited with exit code: {0}",
DirectCast(sender, Process).ExitCode))
End Sub
End Class
Saludos
Cita de: Eleкtro en 11 Noviembre 2014, 18:29 PM
Sea cual sea el error que te indique imagino que es porque estás intentando modificar un control desde un Thread distinto al Thread donde creaste el cotnrol. es decir, tienes el control txtResults en el thread "X" e intentas modificarlo desde el thread "Y", no puedes modificar un control así como así desde otro thread, primero debes comprobar si el control necesita ser invocado, y después, invocarlo.
Woww.. en serio eres un capo en esto. Muchas gracias por tu ayuda. Era exactamente lo que queria. Prometo que seré mas cuidadosa con mis publicaciones y poner la información completa.
Gracias por todo. :D
De nada, para eso estamos, de todas formas esto que te expliqué es quizás lo más básico de la programación asíncrona en .Net.
Se me olvidó comentar algo importante para que no te pierdas en el largo código que te mostré (en caso de que te hayas perdido un poco xD), todo ese código es solo una mejora del código que tú publicaste... por si lo quieres usar de esa manera (suscribiéndote a los eventos de la instancia del proceso), pero lo importante del código es lo siguiente, donde llamo a la propiedad
.Invokerequired y el método
.Invoke desde el subproceso/thread secundario:
Cita de: Eleкtro ...
Select Case txtResults.InvokeRequired
Case True
txtResults.Invoke(Sub() txtResults.AppendText("" & e.Data))
txtResults.Invoke(Sub() txtResults.AppendText(Environment.NewLine))
Case Else
txtResults.AppendText(e.Data)
txtResults.AppendText(Environment.NewLine)
End Select
...
⇲Control.InvokeRequired Property - MSDN (http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired%28v=vs.110%29.aspx)
Control.Invoke(Lambda) Method - MSDN (http://msdn.microsoft.com/en-us/library/zyzhdc6b%28v=vs.110%29.aspx)
Saludos
Cita de: Eleкtro en 11 Noviembre 2014, 19:41 PM
De nada, para eso estamos, de todas formas esto que te expliqué es quizás lo más básico de la programación asíncrona en .Net.
Tengo un inconveniente y quisiera que me ayudes. En el código que me entregaste sólo aumenté el -t al comando ping pero al crear un linklabel para que vacie los campos, el comando ping se sigue ejecutando. Como lo puedo parar?
...
Private ReadOnly Property PingArguments As String
Get
Return String.Format("ping.exe ""{0}.{1}.{2}.{3}"" -t",
TextBox1.Text, TextBox2.Text,
TextBox3.Text, TextBox4.Text)
End Get
End Property
...
Private Sub LinkLabel1_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
Dim x As Control
For Each x In Me.Controls
If TypeOf x Is System.Windows.Forms.TextBox Then x.Text = ""
Next
End Sub
Cita de: rochro en 12 Noviembre 2014, 17:56 PMComo lo puedo parar?
Depende.
1) ¿Al clickar en el linklabel es cuando quieres detener Ping?
Debes detener la ejecución del thread que está corriendo la cmd, si estás usando la Class
Thread entonces puedes llamar al método
Thread.Abort, si estás usando la class
Tasks entonces puedes llamar al método
Task.Cancel usando un token de cancelación para esa
Task.
O también puedes hacerlo desde la winAPi, con la función
TerminateThread: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686717%28v=vs.85%29.aspx
2) ¿Estás usando la misma
Task del código que te mostré?;
Muestra el resto del código relevante, es decir, la declaración del thread y el método del thread (donde ejecutas la cmd)
EDITO: De todas formas hace tiempo escribí un ejemplo de uso de la class
Tasks para cancelar una
Task, te podría servir hasta nueva respuesta:
#Region " TASK Example "
Public Class Form1
' NORMAL TASK USAGE:
' ------------------
Private Task1 As Threading.Tasks.Task
Private Task1CTS As New Threading.CancellationTokenSource
Private Task1CT As Threading.CancellationToken = Task1CTS.Token
Private Sub MyTask1(ByVal CancellationToken As Threading.CancellationToken)
For x As Integer = 0 To 9999
If Not CancellationToken.IsCancellationRequested Then
Debug.Print("Task1: " & x)
Else
MsgBox(String.Format("Task1 Canceled at ""{0}""", x))
Exit Sub
End If
Next x
End Sub
' ANONYMOUS TASK METHOD:
' ---------------------
Private Task2 As Threading.Tasks.Task
Private Task2CTS As New Threading.CancellationTokenSource
Private Task2CT As Threading.CancellationToken = Task2CTS.Token
Private Delegate Function Task2Delegate(ByVal CancellationToken As Threading.CancellationToken)
Private MyTask2 As Task2Delegate =
Function(CancellationToken As Threading.CancellationToken) As Boolean
For x As Integer = 0 To 9999
If Not CancellationToken.IsCancellationRequested Then
Debug.Print("Task2: " & x)
Else
MsgBox(String.Format("Task2 Canceled at ""{0}""", x))
Return False
End If
Next x
Return True
End Function
Private Sub TaskTest() Handles MyBase.Shown
' Run an asynchronous Task.
Task1 = Threading.Tasks.Task.Factory.StartNew(Sub() MyTask1(Task1CT), Task1CT)
' Wait 2 seconds (Just to demonstrate this example)
Threading.Thread.Sleep(2 * 1000)
' Cancel the Task.
Task1CTS.Cancel()
' Wait for the Task to finish the being cancelled.
Task1.Wait()
' Show the task status
MsgBox(Task1.Status.ToString) ' Result: RanToCompletion
' ReStart the Task1.
Task1 = Threading.Tasks.Task.Factory.StartNew(Sub() MyTask1(Task1CT), Task1CT)
' Start the Task2
Task2 = Threading.Tasks.Task.Factory.StartNew(Of Boolean)(Function() MyTask2(Task2CT), Task2CT)
' Wait for both Tasks to finish their execution.
Threading.Tasks.Task.WaitAll()
End Sub
End Class
#End Region
Saludos
Cita de: Eleкtro en 12 Noviembre 2014, 18:24 PM
Depende.
1) ¿Al clickar en el linklabel es cuando quieres detener Ping?
Si. Quiero que al hacer clic en el linklabel se cancele el task. Trato de entender el código pero ya me confundí :(
Disculpa por tanta molestia elektro.
No es ninguna molestía, ayudar es mi hobbie favorito (y más cuando se trata de VB.Net) :)
He añadido el método StartTask, CancelTask, y el linklabel al código que mostré arriba, aquí esta todo lo necesario:
Imports System.Threading
Imports System.Threading.Tasks
Public Class Form1
Private cmdTask As Task
Private cmdTaskCTS As New CancellationTokenSource
Private cmdTaskCT As CancellationToken
''' <summary>
''' The CMD <see cref="System.Diagnostics.Process"/> instance.
''' </summary>
Private WithEvents cmdProcess As New Process With
{
.EnableRaisingEvents = True,
.StartInfo = New ProcessStartInfo With
{
.FileName = "cmd.exe",
.Arguments = String.Empty,
.RedirectStandardInput = False,
.RedirectStandardOutput = True,
.RedirectStandardError = True,
.UseShellExecute = False,
.CreateNoWindow = True
}
}
''' <summary>
''' Gets the ping commandline arguments.
''' </summary>
Private ReadOnly Property PingArguments As String
Get
Return String.Format("ping.exe -t ""{0}.{1}.{2}.{3}""",
TextBox1.Text, TextBox2.Text,
TextBox3.Text, TextBox4.Text)
End Get
End Property
Private Sub btnSend_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles btnsend.Click
Me.StartTask()
End Sub
Private Sub CMDAutomate()
With Me.cmdProcess
.StartInfo.Arguments = String.Format("/C ""{0}""", Me.PingArguments)
.Start()
.BeginOutputReadLine()
.BeginErrorReadLine()
.WaitForExit(Integer.MaxValue)
End With
End Sub
''' <summary>
''' Occurs when an application writes to its redirected <see cref="System.Diagnostics.Process.StandardOutput"/> stream.
''' Occurs when an application writes to its redirected <see cref="System.Diagnostics.Process.StandardError"/> stream.
''' </summary>
Private Sub cmdProcess_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs) _
Handles cmdProcess.OutputDataReceived,
cmdProcess.ErrorDataReceived
Select Case txtresults.InvokeRequired
Case True
txtresults.Invoke(Sub() txtresults.AppendText("" & e.Data))
txtresults.Invoke(Sub() txtresults.AppendText(Environment.NewLine))
Case Else
txtresults.AppendText(e.Data)
txtresults.AppendText(Environment.NewLine)
End Select
#If DEBUG Then
' Debug.WriteLine(e.Data)
#End If
End Sub
''' <summary>
''' Occurs when a <see cref="System.Diagnostics.Process"/> exits.
''' </summary>
Private Sub cmdProcess_Exited(ByVal sender As Object, ByVal e As EventArgs) _
Handles cmdProcess.Exited
Debug.WriteLine(String.Format("cmdProcess has exited with exit code: {0}",
DirectCast(sender, Process).ExitCode))
End Sub
Private Sub LinkLabel1_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) _
Handles LinkLabel1.LinkClicked
' limpio el texto de cada textbox.
For Each tb As TextBox In Me.Controls.OfType(Of TextBox)()
tb.Clear()
Next tb
' cancelo la tarea en segundo plano.
Me.CancelTask()
End Sub
Private Sub StartTask()
Me.cmdTask = Task.Factory.StartNew(AddressOf CMDAutomate)
Me.cmdTaskCTS = New Threading.CancellationTokenSource
Me.cmdTaskCT = cmdTaskCTS.Token
End Sub
Private Sub CancelTask()
' Si el proceso no se ha detenido...
If Not Me.cmdProcess.HasExited Then
With Me.cmdProcess
' cancelo la lectura de los outputs.
.CancelOutputRead()
.CancelErrorRead()
.Kill() ' mato el proceso (cmd.exe)
End With
' Cancelo la tarea en segundo plano.
Me.cmdTaskCTS.Cancel()
' Espero a que la tarea se haya cancelado.
Me.cmdTask.Wait()
End If
End Sub
End Class
EDITO: Fíjate que también cambié esto en el método CMDAutomate, para que funcionase del modo esperado:
Citar.WaitForExit(Integer.MaxValue)
Saludos.
Cita de: Eleкtro en 13 Noviembre 2014, 16:54 PM
No es ninguna molestía, ayudar es mi hobbie favorito (y más cuando se trata de VB.Net) :)
Gracias Elektro. Como que ya voy entendiendo un poco este tema de los tasks. Ahora no se como hacer, ya que como se va avanzando con esta pequeña app se me ocurre si hay alguna manera de que grabe los datos del textbox y por mas que se cierre y vuelva a abrir aparece con esos valores hasta que se cambie.
Gracias por tu atención :)
Cita de: rochro en 18 Noviembre 2014, 17:57 PMse me ocurre si hay alguna manera de que grabe los datos del textbox y por mas que se cierre y vuelva a abrir aparece con esos valores hasta que se cambie.
Hay muchas maneras de hacer eso, lo que más sencillo te resultará es utilizar la infrastructura de
My.Settings.
Puedes crear la propiedad desde las opciones del proyecto, y luego acceder a dicha propiedad en tiempo de ejecución para guardar/cargar valores.
Es muy sencillo, pero lee un poco acerca de ello para enterarte:
Managing Application Settings (http://msdn.microsoft.com/en-us/library/a65txexh.aspx)
Using My.Settings in Visual Basic 2005 (http://msdn.microsoft.com/en-us/library/ms379611%28VS.80%29.aspx)
How to: Change User Settings in Visual Basic (http://msdn.microsoft.com/en-us/library/shytyc55.aspx)
Saludos