Mi form se cuelga al iniciar un thread...

Iniciado por Eleкtro, 29 Noviembre 2012, 19:36 PM

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

Eleкtro

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.



Hasta que no se terminan de mostrar todas las líneas del richtextbox no me deja tocar NADA.

...Muchas gracias por leer.




El form:

Código (vbnet) [Seleccionar]
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








seba123neo

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.

Código (vbnet) [Seleccionar]
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.
La característica extraordinaria de las leyes de la física es que se aplican en todos lados, sea que tú elijas o no creer en ellas. Lo bueno de las ciencias es que siempre tienen la verdad, quieras creerla o no.

Neil deGrasse Tyson

kub0x

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

Saludos!
Viejos siempre viejos,
Ellos tienen el poder,
Y la juventud,
¡En el ataúd! Criaturas Al poder.

Visita mi perfil en ResearchGate


seba123neo

si, pero esa propiedad no es recomendada usar.
La característica extraordinaria de las leyes de la física es que se aplican en todos lados, sea que tú elijas o no creer en ellas. Lo bueno de las ciencias es que siempre tienen la verdad, quieras creerla o no.

Neil deGrasse Tyson

Keyen Night

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.
La Fé Mueve Montañas...
                                    ...De Dinero

La programación es más que un trabajo es más que un hobby es una pasión...

spiritdead

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

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 :/
Facilitador De Tareas - Task Simplifier (FDT)