从System.ComponentModel.BackgroundWorker.RunWorkerCompleted关闭WinForm时vb.net上的System.StackOverflowException

时间:2017-10-03 17:10:10

标签: vb.net winforms


我遇到了后台工作人员和表格。
我试图在工作事件RunWorkerCompleted上调用me.close,但它在myform.Designer.vb文件的重写“Dispose”Sub上拖出了StackOverflow异常。
在我因为需要而重载“New”构造函数之前,它工作了一段时间,现在我总是得到一个StackOverflow异常,但我不知道为什么。 我没有更改设计器文件,但如果我使用以前的代码,它不会失败。 我可以将堆栈大小增加为临时解决方案吗? 这是竞争条件的结果吗? 我还尝试增加后台进程优先级并降低用户界面,没有运气。

我的表单代码如下:

Public Class frmProgreso

Private elImpresionCancelada As Boolean
Private WithEvents miWorker As System.ComponentModel.BackgroundWorker
Private miListaReports As Report.EnumNombreReport()
Private miListaReportsStr As String(,)
Private miInforme_ruta As String
Private miEmpresa As String
Private miAño As Integer
Private miMes As Integer
Private oReport As Report
Private lasCategorias As String()
Private got_closing_order As Boolean = False

Public Sub New(ByVal ListaReports As Report.EnumNombreReport(), ByVal Empresa As String, ByVal Año As Integer, ByVal Mes As Integer, ByVal OpcionMenu As String, ByVal Categorias As String())

    ' Llamada necesaria para el diseñador.
    InitializeComponent()

    ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
    miEmpresa = Empresa
    miAño = Año
    miMes = Mes
    lasCategorias = Categorias
    miListaReports = ListaReports
    ReiniciarInformes(0)
    ReiniciarCeldas(0)
    lblOpcionMenu.Text = OpcionMenu

End Sub
Public Sub New(ByVal informes As String(,), ByVal Empresa As String, ByVal Año As Integer, ByVal Mes As Integer, ByVal OpcionMenu As String, ByVal Categorias As String())

    ' Esta llamada es exigida por el diseñador.
    InitializeComponent()

    ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
    miEmpresa = Empresa
    miAño = Año
    miMes = Mes
    lasCategorias = Categorias
    miListaReportsStr = informes
    ReiniciarInformes(0)
    ReiniciarCeldas(0)
    lblOpcionMenu.Text = OpcionMenu
End Sub
Public Sub New(ByVal ruta_completa_informe As String, ByVal Empresa As String, ByVal Año As Integer, ByVal Mes As Integer, ByVal OpcionMenu As String, ByVal Categorias As String())

    ' Esta llamada es exigida por el diseñador.
    InitializeComponent()

    ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
    miEmpresa = Empresa
    miAño = Año
    miMes = Mes
    lasCategorias = Categorias
    miInforme_ruta = ruta_completa_informe
    ReiniciarInformes(0)
    ReiniciarCeldas(0)
    lblOpcionMenu.Text = OpcionMenu
End Sub

Public ReadOnly Property ProcesoCancelado() As Boolean
    Get
        Return elImpresionCancelada
    End Get
End Property

Public Sub ImprimirDesdeCatalogo(Optional ByVal informes As String(,) = Nothing)
    If Not IsNothing(informes) Then
        miListaReportsStr = informes
    End If
    Me.Show()
    LanzarImpresion()
End Sub

Public Sub ReiniciarCeldas(ByVal NumeroCeldas As Integer)
    pbCeldas.Minimum = 0
    pbCeldas.Maximum = NumeroCeldas
    pbCeldas.Value = pbCeldas.Minimum
    pbCeldas.Step = 1
    lblCeldas.Text = String.Empty
End Sub

Public Sub ReiniciarInformes(ByVal NumeroInformes As Integer)
    pbInformes.Minimum = 0
    pbInformes.Maximum = NumeroInformes * 3 'Para cada informe, se realizan tres pasos: carga de plantilla en array, procesamiento de celdas y carga de array en plantilla
    pbInformes.Step = 1
    pbInformes.Value = pbInformes.Minimum
    lblInforme.Text = String.Empty
End Sub

'Private Sub frmProgreso_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
'    If miWorker.IsBusy() Then
'        got_closing_order = True
'        miWorker.CancelAsync()
'        e.Cancel = True
'        Me.Enabled = False
'        Return
'    End If
'    MyBase.OnFormClosing(e)
'End Sub

Private Sub frmProgreso_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Me.WindowState = FormWindowState.Maximized
    CentrarObjeto(gbPrincipal)
End Sub

Private Sub miWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles miWorker.DoWork
    System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.RealTime
    If Not IsNothing(miListaReportsStr) Then
        'Proceso nuevo.
        miWorker.ReportProgress((UBound(miListaReportsStr, 1)) * 3, "INICIAR INFORMES") 'Para cada informe, se realizan tres pasos: carga de plantilla en array, procesamiento de celdas y carga de array en plantilla
        For i As Integer = 0 To UBound(miListaReportsStr, 1) - 1
            If miWorker.CancellationPending Then
                Exit For
            End If
            'miWorker.ReportProgress(1, miListaReports.ElementAt(i).ToString)
            oReport = New Report(miListaReportsStr(0, i), miEmpresa, miAño, miMes, miWorker, cRutaBase_InformesXLSGenerados, lasCategorias, miListaReportsStr(1, i))
            oReport.Imprimir(txtCeldaValidacion.Text.Trim)
        Next
    ElseIf miInforme_ruta <> "" Then
        'proceso nuevo fichero individual 
        miWorker.ReportProgress(3, "INICIAR INFORMES") 'Para cada informe, se realizan tres pasos: carga de plantilla en array, procesamiento de celdas y carga de array en plantilla
        'miWorker.ReportProgress(1, miListaReports.ElementAt(i).ToString)
        oReport = New Report(miInforme_ruta, miEmpresa, miAño, miMes, miWorker, cRutaBase_InformesXLSGenerados, lasCategorias)
        oReport.Imprimir(txtCeldaValidacion.Text.Trim)

    Else
        'Proceso Antiguo
        miWorker.ReportProgress(miListaReports.Length * 3, "INICIAR INFORMES") 'Para cada informe, se realizan tres pasos: carga de plantilla en array, procesamiento de celdas y carga de array en plantilla
        For i As Integer = 0 To miListaReports.Length - 1
            If miWorker.CancellationPending Then
                Exit For
            End If
            'miWorker.ReportProgress(1, miListaReports.ElementAt(i).ToString)
            oReport = New Report(miListaReports.ElementAt(i), miEmpresa, miAño, miMes, miWorker, cRutaBase_InformesXLSGenerados, lasCategorias)
            oReport.Imprimir(txtCeldaValidacion.Text.Trim)
        Next
    End If
End Sub

Private Sub miWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles miWorker.ProgressChanged
    If e.UserState = "INICIAR CELDAS" Then
        pbCeldas.Minimum = 0
        pbCeldas.Maximum = e.ProgressPercentage
        pbCeldas.Value = pbCeldas.Minimum
        pbCeldas.Step = 1
        lblCeldas.Text = String.Empty

    ElseIf e.UserState = "INCREMENTAR CELDAS" Then
        pbCeldas.Value = pbCeldas.Value + 1
        lblCeldas.Text = "Calculando celda " & pbCeldas.Value & "/" & pbCeldas.Maximum
        'If pbCeldas.Value = 9811 Then
        '    MessageBox.Show("1")
        'End If

    ElseIf e.UserState = "LEER CELDAS PLANTILLA" Then
        pbCeldas.Value = pbCeldas.Value + 1
        lblCeldas.Text = "Leyendo plantilla celda " & pbCeldas.Value & "/" & pbCeldas.Maximum

    ElseIf e.UserState = "VOLCAR CELDAS PLANTILLA" Then
        pbCeldas.Value = pbCeldas.Value + 1
        lblCeldas.Text = "Escribiendo en plantilla celda " & pbCeldas.Value & "/" & pbCeldas.Maximum

    ElseIf e.UserState = "INICIAR INFORMES" Then
        pbInformes.Minimum = 0
        pbInformes.Maximum = e.ProgressPercentage
        pbInformes.Value = pbInformes.Minimum
        pbInformes.Step = 1
        lblInforme.Text = String.Empty

    Else
        lblInforme.Text = "Imprimiendo...  < " & e.UserState & " >    (Fase " & (pbInformes.Value Mod 3) + 1 & "/3)" '
        pbInformes.Value = pbInformes.Value + e.ProgressPercentage
    End If
End Sub

Private Sub frmImportarInformesExcel_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    CentrarObjeto(gbPrincipal)
End Sub

Private Sub butCancelarImpresion_Click(sender As System.Object, e As System.EventArgs) Handles butCancelarImpresion.Click
    If MessageBox.Show("¿Estás seguro de que deseas cancelar la impresión?", "Cancelar impresión", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) = Windows.Forms.DialogResult.Yes Then
        elImpresionCancelada = True
        If oReport IsNot Nothing Then
            oReport.CancelarImpresion = True
        End If
        If miWorker IsNot Nothing Then
            miWorker.CancelAsync()
        End If
        'Me.Close()
        Me.Hide()
    End If
End Sub

Private Sub LanzarImpresion()
    System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.Processpriorityclass.BelowNormal
    butComenzar.Enabled = False
    txtCeldaValidacion.Enabled = False
    lblInforme.Visible = True
    lblCeldas.Visible = True
    pbCeldas.Visible = True
    pbInformes.Visible = True
    lblOpcionMenu.Visible = False
    miWorker = New System.ComponentModel.BackgroundWorker()
    miWorker.WorkerReportsProgress = True
    miWorker.WorkerSupportsCancellation = True
    miWorker.RunWorkerAsync()
End Sub

Private Sub butComenzar_Click(sender As System.Object, e As System.EventArgs) Handles butComenzar.Click
    LanzarImpresion()
End Sub

Private Sub miWorker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles miWorker.RunWorkerCompleted
    ' a veces no se puede cerrar al usar el debugger... parece un error por utilizar hilos. ç
    miWorker.CancelAsync()
    miWorker.Dispose()
    miWorker = Nothing
    System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.Normal
    Me.Dispose(False)
End Sub

Private Sub txtCeldaValidacion_LostFocus(sender As Object, e As EventArgs) Handles txtCeldaValidacion.LostFocus
    txtCeldaValidacion.Text = Replace(Replace(Replace(txtCeldaValidacion.Text, " ", ""), ":", ""), "$", "")
End Sub

End Class

编辑1: 我一直在尝试观察调用堆栈,是的,存在堆栈溢出,因为frmprogreso.designer.vb上的dispose方法被多次调用。
Effective stack overflow
但是从用户代码方面来看,它只被调用一次,因为我可以看到...
Only one call from user code side

1 个答案:

答案 0 :(得分:0)

我的错是在myform.Designer.vb上 出于某种原因(可能是我自己的错),处理方法如下:

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    Try
        If disposing AndAlso components IsNot Nothing Then
            components.Dispose()
        End If
    Finally
        Me.Dispose(disposing)
    End Try
End Sub

非常感谢Hans Passant指出&#34; Me.Dispose(处理)&#34;这是一个大错,它是在呼唤自己。它应该绝对是MyBase.Dispose(disposing)