Para los que no lo sepan, estoy diseñando un programa, y tenía un problema, la app se colgaba al darle al botón "start", hasta que "el proceso" finalizaba no podía tocar nada.
...
...
Después de estar días para conseguir meter una función en un thread separado, ahora que lo he conseguido ...no hay ninguna diferencia... hasta que no finaliza "el proceso" no puedo mover el form por la pantalla, ni pulsar cualquier botón del form, ni nada, solo puedo esperar hasta que acabe...
...Espero alguna ayuda, porqué yo ya no sé que más intentar para que no se me cuelgue, no sé lo que he hecho mal.
(http://img853.imageshack.us/img853/2071/prtscrcapturegq.jpg)
Hasta que no se terminan de mostrar todas las líneas del richtextbox no me deja tocar NADA.
...Muchas gracias por leer.
El form:
Imports System.IO
Imports System.Threading
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports Ookii.Dialogs
Public Class Form1
#Region "Declarations"
' MediaInfo
Dim MI As MediaInfo
' Others
Dim NameOfDirectory As String = Nothing
Dim aFile As FileInfo
#End Region
#Region "Properties"
#End Region
#Region "Load / Close"
' Load
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' MediaInfo Instance
MI = New MediaInfo
End Sub
#End Region
#Region "Get Total files Function"
#End Region
#Region "Option checkboxes"
#End Region
#Region "Folder buttons"
#End Region
#Region "Append text function"
' Append Text
Public Sub AppendText(box As RichTextBox, color As Color, text As String)
Control.CheckForIllegalCrossThreadCalls = False
Dim start As Integer = box.TextLength
box.AppendText(text)
Dim [end] As Integer = box.TextLength
' Textbox may transform chars, so (end-start) != text.Length
box.[Select](start, [end] - start)
If True Then
box.SelectionColor = color
' could set box.SelectionBackColor, box.SelectionFont too.
End If
box.SelectionLength = 0
' clear
End Sub
#End Region
#Region "Thread"
Public _WaitHandle_FirstThreadDone As New System.Threading.AutoResetEvent(False)
Public Sub ThreadProc(ByVal aDir As DirectoryInfo)
Dim aFile As FileInfo
For Each aFile In aDir.GetFiles()
If accepted_extensions.ToLower.Contains(aFile.Extension.ToLower) Then
' print output
AppendText(consolebox, Color.Yellow, "Processing: ")
AppendText(consolebox, Color.White, aFile.ToString() + vbNewLine)
consolebox.ScrollToCaret()
processedfiles += 1
totalfiles_label.Text = "Processed " + processedfiles.ToString() + " of " + totalfiles.ToString() + " total video files"
' Attributes
If attribs = True Then
aFile.Attributes = (aFile.Attributes And Not FileAttributes.ReadOnly And Not FileAttributes.Hidden And Not FileAttributes.System And Not FileAttributes.Archive)
End If
' Rename to Word-Case
If wordcase = True Then
Dim renamestr As String = StrConv(aFile.Name, VbStrConv.ProperCase)
My.Computer.FileSystem.RenameFile(aFile.FullName, renamestr + "_FILMEN")
My.Computer.FileSystem.RenameFile(aFile.FullName + "_FILMEN", renamestr)
End If
' Rename to Lower-Case
If lowercase = True Then
Dim renamestr As String = StrConv(aFile.Name, VbStrConv.Lowercase)
My.Computer.FileSystem.RenameFile(aFile.FullName, renamestr + "_FILMEN")
My.Computer.FileSystem.RenameFile(aFile.FullName + "_FILMEN", renamestr)
End If
' Playlists
If playlist = True Then
Using writer As StreamWriter = New StreamWriter(aFile.DirectoryName.ToString() & "\" & aDir.Name & ".m3u", True, System.Text.Encoding.UTF8)
writer.WriteLine(aFile.FullName.ToString())
End Using
End If
' MEDIAINFO: (ac3, dts, wav and multitrack)
If ac3 = True Or dts = True Or wav = True Or multitrack = True Then
MI.Open(aFile.FullName)
Dim Pos As Integer = 0
To_Display = Nothing
' multitrack
If multitrack = True Then
If MI.Count_Get(StreamKind.Audio) > 1 Then
results_box.AppendText("Multi Track: " + aFile.FullName.ToString() + vbNewLine)
results_box.SelectionStart = results_box.Text.Length
results_box.ScrollToCaret()
problems += 1
problems_label.Text = problems.ToString() + " problems found"
End If
End If
While Pos < MI.Count_Get(StreamKind.Audio)
' AC-3
If ac3 = True Then
If MI.Get_(StreamKind.Audio, Pos, "Format").ToString() = "AC-3" Then
results_box.AppendText("AC3 Track: " + aFile.FullName.ToString() + vbNewLine)
results_box.SelectionStart = results_box.Text.Length
results_box.ScrollToCaret()
problems += 1
problems_label.Text = problems.ToString() + " problems found"
End If
End If
' DTS
If dts = True Then
If MI.Get_(StreamKind.Audio, Pos, "Format").Contains("DTS") Then
results_box.AppendText("DTS Track: " + aFile.FullName.ToString() + vbNewLine)
results_box.SelectionStart = results_box.Text.Length
results_box.ScrollToCaret()
problems += 1
problems_label.Text = problems.ToString() + " problems found"
End If
End If
' WAV
If wav = True Then
If MI.Get_(StreamKind.Audio, Pos, "Format").Contains("PCM") Then
results_box.AppendText("WAV Track: " + aFile.FullName.ToString() + vbNewLine)
results_box.SelectionStart = results_box.Text.Length
results_box.ScrollToCaret()
problems += 1
problems_label.Text = problems.ToString() + " problems found"
End If
End If
System.Math.Max(System.Threading.Interlocked.Increment(Pos), Pos - 1)
End While
End If
If metadata = True Then
Dim ffmpeg_process As New Process()
Dim ffmpeg_startinfo As New ProcessStartInfo()
ffmpeg_startinfo.FileName = "cmd.exe "
ffmpeg_startinfo.Arguments = "/C ffmpeg.exe -y -i " & ControlChars.Quote & aFile.FullName.ToString() & ControlChars.Quote & " -f ffmetadata " & ControlChars.Quote & "%TEMP%\" & aFile.Name.ToString() & "_metadata.txt" & ControlChars.Quote & " >NUL 2>&1 && Type " & ControlChars.Quote & "%TEMP%\" & aFile.Name.ToString() & "_metadata.txt" & ControlChars.Quote & "| FINDSTR /I " & ControlChars.Quote & "^INAM ^title" & ControlChars.Quote & " >NUL && Echo FOUND && EXIT || Echo NOT FOUND && Exit"
ffmpeg_startinfo.UseShellExecute = False
ffmpeg_startinfo.CreateNoWindow = True
ffmpeg_startinfo.RedirectStandardOutput = True
ffmpeg_startinfo.RedirectStandardError = True
ffmpeg_process.EnableRaisingEvents = True
ffmpeg_process.StartInfo = ffmpeg_startinfo
ffmpeg_process.Start()
ffmpeg_process.WaitForExit()
Dim readerStdOut As IO.StreamReader = ffmpeg_process.StandardOutput
Dim FINDstdOut As String = ffmpeg_process.StandardOutput.ReadToEnd
If FINDstdOut.Contains("FOUND") Then
AppendText(consolebox, Color.Red, "TAGS FOUND! Removing tags, please wait..." & vbNewLine)
Dim relative_dir As String = aDir.FullName.ToString().Replace(aDir.Root.ToString(), "\")
Dim ffmpegconvert_process As New Process()
Dim ffmpegconvert_startinfo As New ProcessStartInfo()
ffmpegconvert_startinfo.FileName = "cmd.exe "
ffmpegconvert_startinfo.Arguments = "/C MKDIR " & ControlChars.Quote & userSelectedFolderPathmetadata & relative_dir & ControlChars.Quote & " 2>NUL & ffmpeg.exe -y -i " & ControlChars.Quote & aFile.FullName.ToString() & ControlChars.Quote & " -c copy -map_metadata -1 " & ControlChars.Quote & userSelectedFolderPathmetadata & relative_dir & "\" & aFile.Name.ToString() & ControlChars.Quote & " >NUL 2>&1 & Exit"
ffmpegconvert_startinfo.UseShellExecute = False
ffmpegconvert_startinfo.CreateNoWindow = True
ffmpegconvert_startinfo.RedirectStandardOutput = True
ffmpegconvert_startinfo.RedirectStandardError = True
ffmpegconvert_process.EnableRaisingEvents = True
ffmpegconvert_process.StartInfo = ffmpegconvert_startinfo
ffmpegconvert_process.Start()
ffmpegconvert_process.WaitForExit()
'Dim ffmpegconvertreaderStdOut As IO.StreamReader = ffmpegconvert_process.StandardOutput
End If
Do While readerStdOut.EndOfStream = False
consolebox.AppendText(readerStdOut.ReadLine() + vbNewLine)
consolebox.SelectionStart = consolebox.Text.Length
consolebox.ScrollToCaret()
Loop
End If
End If
Next
_WaitHandle_FirstThreadDone.Set()
End Sub
#End Region
#Region "Organize function"
Public Sub MediaInfo(Directory)
Dim MyDirectory As DirectoryInfo
MyDirectory = New DirectoryInfo(NameOfDirectory)
MediaInfoWorkWithDirectory(MyDirectory)
End Sub
Public Sub MediaInfoWorkWithDirectory(ByVal aDir As DirectoryInfo)
Dim nextDir As DirectoryInfo
Dim t As New Threading.Thread(AddressOf ThreadProc)
t.Start(aDir)
_WaitHandle_FirstThreadDone.WaitOne()
For Each nextDir In aDir.GetDirectories
If playlist = True Then
Using writer As StreamWriter = New StreamWriter(aDir.FullName & "\" & nextDir.Name & "\" & nextDir.Name & ".m3u", False, System.Text.Encoding.UTF8)
'overwrite existing playlist
End Using
End If
MediaInfoWorkWithDirectory(nextDir)
Next
End Sub
#End Region
#Region "Action buttons"
' start button
Public Sub Button2_Click(sender As Object, e As EventArgs) Handles start_button.Click
If metadata = True And metadatatextbox.Text = "Select a folder to save the converted videos without metadata..." Then
MsgBox("You must select a folder for the saved metadata videos...", , "Filmen v1.0")
Else
If ac3 = False And dts = False And wav = False And multitrack = False And playlist = False And attribs = False And wordcase = False And metadata = False And lowercase = False Then
MsgBox("You must select at least one option...", , "Filmen v1.0")
Else
consolebox.Clear()
' pause / cancel button ON
pause_button.Enabled = True
cancel_button.Enabled = True
' Total files label
processedfiles = 0
totalfiles_label.Text = totalfiles.ToString() + " Total video files"
' Problems label
problems = 0
problems_label.Text = "0 problems found"
' Organization process
NameOfDirectory = userSelectedFolderPath
MediaInfo(NameOfDirectory)
consolebox.AppendText(vbNewLine + "[+] Organization finalized!" + vbNewLine)
consolebox.Refresh()
consolebox.SelectionStart = consolebox.Text.Length
consolebox.ScrollToCaret()
' pause / cancel button OFF
pause_button.Enabled = False
cancel_button.Enabled = False
End If
End If
End Sub
#End Region
End Class
vi tanto temas tuyos de thread, que te hice este ejemplo simple, para que veas que facil es hacer un thread, de un proceso largo que te traba toda la UI.
Imports System.Threading
Public Class Form1
Private Delegate Sub Progreso()
Private vHilo As Thread
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
TextBox1.Text = 0
vHilo = New Thread(New ThreadStart(AddressOf Proceso))
vHilo.Start()
End Sub
Private Sub Proceso()
If Me.InvokeRequired Then
Me.Invoke(New Progreso(AddressOf Proceso))
Else
Do While True
TextBox1.Text += CInt(1)
Application.DoEvents()
Loop
End If
End Sub
End Class
lo que hace es simplemente sumar un valor en el textbox en un bucle infinito, que sin esto se te trabaria toda la pantalla y no podrias tocar nada, y como usa el control textbox hay que usar un delgado, de lo contrario te sale el famoso error "Operación no válida a través de subprocesos: Se tuvo acceso al control 'TextBox1' desde un subproceso distinto a aquel en que lo creó.", ese error quiere decir que no podes manipular un control del formulario, ya que este esta en un hilo diferente (el hilo de la UI), que es diferente al hilo que creas vos ahi.
con esa forma podes hacer lo que se te cante.
saludos.
Cita de: seba123neo en 29 Noviembre 2012, 21:39 PM
y como usa el control textbox hay que usar un delgado, de lo contrario te sale el famoso error "Operación no válida a través de subprocesos: Se tuvo acceso al control 'TextBox1' desde un subproceso distinto a aquel en que lo creó.", ese error quiere decir que no podes manipular un control del formulario, ya que este esta en un hilo diferente (el hilo de la UI), que es diferente al hilo que creas vos ahi.
Como dato, si no quieres emplear delegados en el code, en el contexto de insertar una modificación en un control dentro de un subproceso distinto al que creo dicho control, simplemente se "fixea" el error seteando la propiedad CheckForIllegalCrossThreadCalls a False. De esta manera evitas que se compruebe que un la propiedad de un control fue modificada desde un subproceso distinto al original.
Más info el la Msdn, dónde explican como utilizar dicha propiedad y su funcionamiento -> http://msdn.microsoft.com/es-es/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx (http://msdn.microsoft.com/es-es/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx)
Saludos!
si, pero esa propiedad no es recomendada usar.
Hay casos en los cuales no funciona, siempre es de mejor practica usar delegados, aunque si es algo muy sencillo se puede usar pero igual no se recomienda.
Cita de: kub0x en 29 Noviembre 2012, 21:48 PM
Como dato, si no quieres emplear delegados en el code, en el contexto de insertar una modificación en un control dentro de un subproceso distinto al que creo dicho control, simplemente se "fixea" el error seteando la propiedad CheckForIllegalCrossThreadCalls a False. De esta manera evitas que se compruebe que un la propiedad de un control fue modificada desde un subproceso distinto al original.
Más info el la Msdn, dónde explican como utilizar dicha propiedad y su funcionamiento -> http://msdn.microsoft.com/es-es/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx (http://msdn.microsoft.com/es-es/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx)
Saludos!
q aprenda a usar delegados, es lo mas maravilloso que puede existir en cuanto al tema de multi-hilos :D
por cierto EleKtro H@cker
tenes los 2 foros (este y el-hacker) spameados de consultas, no seria mejor investigar ? y hacer preguntas mas precisas :/