Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke_.net_Winforms_Com Interop_Multithreading - Fatal编程技术网

.net 在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke

.net 在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke,.net,winforms,com-interop,multithreading,.net,Winforms,Com Interop,Multithreading,好几天来我一直在想这个。我正在vb.net中开发一个com对象来显示启动屏幕。这将从vb脚本和Powershell中调用,以便在脚本中出现其他指令时向用户提供状态。我间歇性地收到此错误,如有任何帮助,将不胜感激 这里是我用来帮助开发我的应用程序的链接。 消息循环 Private Sub StartMessageLoop() Application.Run(appContext) End Sub 展示形式 Public Sub Show() If frmSplash.Inv

好几天来我一直在想这个。我正在vb.net中开发一个com对象来显示启动屏幕。这将从vb脚本和Powershell中调用,以便在脚本中出现其他指令时向用户提供状态。我间歇性地收到此错误,如有任何帮助,将不胜感激

这里是我用来帮助开发我的应用程序的链接。

消息循环

 Private Sub StartMessageLoop()
    Application.Run(appContext)
 End Sub
展示形式

Public Sub Show()
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated = True Then
            appContext.MainForm.Invoke(ShowDelegate)
        End If
    End If
End Sub
卸下

 Public Sub Unload()
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            appContext.MainForm.Invoke(UnLdDelegate)
        End If
    End If
End Sub
线程退出事件

 Private Sub ac_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles appContext.ThreadExit

    appContext.MainForm.Dispose()
    appContext.MainForm = Nothing
    appContext.Dispose()
    appContext = Nothing
    frmSplash.Dispose()
    frmSplash = Nothing

End Sub
当我从powershell脚本调用Show方法时,通常会引发此错误。任何帮助都将不胜感激。谢谢

完整代码

Private ShowLock As New ManualResetEvent(False)
Private WithEvents appContext As ApplicationContext
Private frmSplash As frmProgress

Private Delegate Sub FormDelegate()
Private Delegate Sub DisplayDelegate(ByVal msg As String)
Private Delegate Sub FormSettings(ByVal val As Boolean)

Private ShowDelegate As FormDelegate
Private HideDelegate As FormDelegate
Private UnLdDelegate As FormDelegate

Public Sub New()

    MyBase.New()
    frmSplash = New frmProgress

End Sub

Public Sub SetDisplayText1(ByVal msg As String)
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetDisplayText1)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label1.Text = msg
        frmSplash.Label1.Refresh()
    End If
End Sub


Public Sub SetDisplayText2(ByVal msg As String)
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetDisplayText2)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label2.Text = msg
        frmSplash.Label2.Refresh()
    End If

End Sub

Public Sub SetTitle(ByVal msg As String)
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetTitle)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Text = msg
    End If
End Sub


Public WriteOnly Property AlwaysOnTop() As Boolean

    Set(ByVal value As Boolean)
        SetTop(value)
    End Set
End Property


Public Sub Show()

    AddHandler frmSplash.HandleCreated, AddressOf frm_HandleCreated

    If IsNothing(appContext) Then
        Dim t As Thread
        appContext = New ApplicationContext(frmSplash)
        t = New Thread(AddressOf StartMessageLoop)
        t.IsBackground = True
        t.SetApartmentState(ApartmentState.STA)
        t.Start()
    Else
        ShowLock.WaitOne()
        If frmSplash.InvokeRequired Then
            If frmSplash.IsHandleCreated = True Then
                ShowDelegate = New FormDelegate(AddressOf Show)
                appContext.MainForm.Invoke(ShowDelegate)
            End If
        Else
            frmSplash.Show()
        End If

    End If
End Sub

Public Sub SetTop(ByVal val As Boolean)
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetTop)
        frmSplash.Invoke(d, New Object() {[val]})
    Else
        frmSplash.TopMost = val
        frmSplash.TopLevel = val
    End If
End Sub

Public Sub Hide()

    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            HideDelegate = New FormDelegate(AddressOf Hide)
            appContext.MainForm.Invoke(HideDelegate)
        End If
    Else
        frmSplash.Hide()
    End If

End Sub

Public Sub Unload()

    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            UnLdDelegate = New FormDelegate(AddressOf Unload)
            appContext.MainForm.Invoke(UnLdDelegate)
        End If
    Else
        frmSplash.Close()
    End If

End Sub

Private Sub StartMessageLoop()
    Application.Run(appContext)
End Sub

Private Sub ac_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles appContext.ThreadExit

    appContext.MainForm.Dispose()
    appContext.MainForm = Nothing
    appContext.Dispose()
    appContext = Nothing
    frmSplash.Dispose()
    frmSplash = Nothing

End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
End Sub

Public Sub frm_HandleCreated()
    ShowLock.Set()
End Sub
我的调试行会让我相信崩溃正在这里发生

 Public Sub Show()

    AddHandler frmSplash.HandleCreated, AddressOf frm_HandleCreated

    If IsNothing(appContext) Then
        Dim t As Thread
        appContext = New ApplicationContext(frmSplash)
        t = New Thread(AddressOf StartMessageLoop)
        t.IsBackground = True
        t.SetApartmentState(ApartmentState.STA)
        t.Start()
感谢到目前为止的所有帮助。

创建MainForm后,在最终成为UI线程的同一线程上访问其Handle属性。将它分配给某个一次性变量,关键是要访问它。WinForms延迟初始化句柄,因此在访问属性或首次显示属性之前,句柄无效。InvokeRequired通过查看创建句柄的线程来工作,因此如果尝试在后台线程上惰性地初始化它,则可能会发生不好的事情

有关更多详细信息,请参阅

可能不是这样,但听起来确实像是我以前打过的。希望它能让您走上正轨。

创建MainForm后,在最终成为UI线程的同一线程上访问其句柄属性。将它分配给某个一次性变量,关键是要访问它。WinForms延迟初始化句柄,因此在访问属性或首次显示属性之前,句柄无效。InvokeRequired通过查看创建句柄的线程来工作,因此如果尝试在后台线程上惰性地初始化它,则可能会发生不好的事情

有关更多详细信息,请参阅


可能不是这样,但听起来确实像是我以前打过的。希望它能让你走上正轨。

好的,我知道问题出在哪里了。我猜您正在从PS脚本调用一个SetDisplayText方法。您需要通过检查InvokeRequired和IsHandleCreated来保护这些用户,另外还需要在表单的初始显示周围提供同步。我的VB.NET有点生锈,但我会尽全力:

首先,将其添加为局部变量:

Private ShowLock As New ManualResetEvent(False);
然后,在frmSplash上为HandleCreated事件添加一个处理程序,并在该处理程序中:

Public Sub Form_HandleCreated(...)
     ShowLock.Set
End Sub
然后,在ShowForm方法中,等待那个家伙完成设置:

Public Sub Show()
    ShowLock.WaitOne
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated = True Then
            appContext.MainForm.Invoke(ShowDelegate)
        End If
    End If
End Sub
这样,您就可以确保在第一个线程尝试显示窗体或执行任何其他操作之前,窗体的句柄已经创建

最后,保护那些SetXXX方法对任何涉及表单并可能从脚本调用的内容执行此操作:

Public Sub SetDisplayText1(ByVal msg As String)
    If frmSplash.InvokeRequired Then
        Dim d As New SetDisplayText1Delegate(AddressOf SetDisplayText1)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label1.Text = msg
        frmSplash.Label1.Refresh()
    End If
End Sub
编辑:试试这个-我从上面获取了你的代码,并重新编写了一点

Private ShowLock As New ManualResetEvent(False)
Private WithEvents appContext As ApplicationContext
Private frmSplash As frmProgress

Private Delegate Sub FormDelegate()
Private Delegate Sub DisplayDelegate(ByVal msg As String)
Private Delegate Sub FormSettings(ByVal val As Boolean)

Private ShowDelegate As FormDelegate
Private HideDelegate As FormDelegate
Private UnLdDelegate As FormDelegate

Public Sub New()

    MyBase.New()
    frmSplash = New frmProgress
    AddHandler frmSplash.HandleCreated, AddressOf frm_HandleCreated
    Dim t As Thread
    appContext = New ApplicationContext(frmSplash)
    t = New Thread(AddressOf StartMessageLoop)
    t.IsBackground = True
    t.SetApartmentState(ApartmentState.STA)
    t.Start()

End Sub

Public Sub SetDisplayText1(ByVal msg As String)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetDisplayText1)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label1.Text = msg
        frmSplash.Label1.Refresh()
    End If
End Sub


Public Sub SetDisplayText2(ByVal msg As String)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetDisplayText2)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label2.Text = msg
        frmSplash.Label2.Refresh()
    End If

End Sub

Public Sub SetTitle(ByVal msg As String)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetTitle)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Text = msg
    End If
End Sub

Public WriteOnly Property AlwaysOnTop() As Boolean
    Set(ByVal value As Boolean)
        SetTop(value)
    End Set
End Property

Public Sub Show()
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated = True Then
            ShowDelegate = New FormDelegate(AddressOf Show)
            appContext.MainForm.Invoke(ShowDelegate)
        End If
    Else
        frmSplash.Show()
    End If
End Sub

Public Sub SetTop(ByVal val As Boolean)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetTop)
        frmSplash.Invoke(d, New Object() {[val]})
    Else
        frmSplash.TopMost = val
        frmSplash.TopLevel = val
    End If
End Sub

Public Sub Hide()
    ShowLock.WaitOne()    
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            HideDelegate = New FormDelegate(AddressOf Hide)
            appContext.MainForm.Invoke(HideDelegate)
        End If
    Else
        frmSplash.Hide()
    End If

End Sub

Public Sub Unload()
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            UnLdDelegate = New FormDelegate(AddressOf Unload)
            appContext.MainForm.Invoke(UnLdDelegate)
        End If
    Else
        frmSplash.Close()
    End If

End Sub

Private Sub StartMessageLoop()
    Application.Run(appContext)
End Sub

Private Sub ac_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles appContext.ThreadExit

    appContext.MainForm.Dispose()
    appContext.MainForm = Nothing
    appContext.Dispose()
    appContext = Nothing
    frmSplash.Dispose()
    frmSplash = Nothing

End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
End Sub

Public Sub frm_HandleCreated()
    ShowLock.Set()
End Sub

好的,我知道问题出在哪里了。我猜您正在从PS脚本调用一个SetDisplayText方法。您需要通过检查InvokeRequired和IsHandleCreated来保护这些用户,另外还需要在表单的初始显示周围提供同步。我的VB.NET有点生锈,但我会尽全力:

首先,将其添加为局部变量:

Private ShowLock As New ManualResetEvent(False);
然后,在frmSplash上为HandleCreated事件添加一个处理程序,并在该处理程序中:

Public Sub Form_HandleCreated(...)
     ShowLock.Set
End Sub
然后,在ShowForm方法中,等待那个家伙完成设置:

Public Sub Show()
    ShowLock.WaitOne
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated = True Then
            appContext.MainForm.Invoke(ShowDelegate)
        End If
    End If
End Sub
这样,您就可以确保在第一个线程尝试显示窗体或执行任何其他操作之前,窗体的句柄已经创建

最后,保护那些SetXXX方法对任何涉及表单并可能从脚本调用的内容执行此操作:

Public Sub SetDisplayText1(ByVal msg As String)
    If frmSplash.InvokeRequired Then
        Dim d As New SetDisplayText1Delegate(AddressOf SetDisplayText1)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label1.Text = msg
        frmSplash.Label1.Refresh()
    End If
End Sub
编辑:试试这个-我从上面获取了你的代码,并重新编写了一点

Private ShowLock As New ManualResetEvent(False)
Private WithEvents appContext As ApplicationContext
Private frmSplash As frmProgress

Private Delegate Sub FormDelegate()
Private Delegate Sub DisplayDelegate(ByVal msg As String)
Private Delegate Sub FormSettings(ByVal val As Boolean)

Private ShowDelegate As FormDelegate
Private HideDelegate As FormDelegate
Private UnLdDelegate As FormDelegate

Public Sub New()

    MyBase.New()
    frmSplash = New frmProgress
    AddHandler frmSplash.HandleCreated, AddressOf frm_HandleCreated
    Dim t As Thread
    appContext = New ApplicationContext(frmSplash)
    t = New Thread(AddressOf StartMessageLoop)
    t.IsBackground = True
    t.SetApartmentState(ApartmentState.STA)
    t.Start()

End Sub

Public Sub SetDisplayText1(ByVal msg As String)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetDisplayText1)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label1.Text = msg
        frmSplash.Label1.Refresh()
    End If
End Sub


Public Sub SetDisplayText2(ByVal msg As String)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetDisplayText2)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Label2.Text = msg
        frmSplash.Label2.Refresh()
    End If

End Sub

Public Sub SetTitle(ByVal msg As String)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetTitle)
        frmSplash.Invoke(d, New Object() {[msg]})
    Else
        frmSplash.Text = msg
    End If
End Sub

Public WriteOnly Property AlwaysOnTop() As Boolean
    Set(ByVal value As Boolean)
        SetTop(value)
    End Set
End Property

Public Sub Show()
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated = True Then
            ShowDelegate = New FormDelegate(AddressOf Show)
            appContext.MainForm.Invoke(ShowDelegate)
        End If
    Else
        frmSplash.Show()
    End If
End Sub

Public Sub SetTop(ByVal val As Boolean)
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        Dim d As New DisplayDelegate(AddressOf SetTop)
        frmSplash.Invoke(d, New Object() {[val]})
    Else
        frmSplash.TopMost = val
        frmSplash.TopLevel = val
    End If
End Sub

Public Sub Hide()
    ShowLock.WaitOne()    
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            HideDelegate = New FormDelegate(AddressOf Hide)
            appContext.MainForm.Invoke(HideDelegate)
        End If
    Else
        frmSplash.Hide()
    End If

End Sub

Public Sub Unload()
    ShowLock.WaitOne()
    If frmSplash.InvokeRequired Then
        If frmSplash.IsHandleCreated Then
            UnLdDelegate = New FormDelegate(AddressOf Unload)
            appContext.MainForm.Invoke(UnLdDelegate)
        End If
    Else
        frmSplash.Close()
    End If

End Sub

Private Sub StartMessageLoop()
    Application.Run(appContext)
End Sub

Private Sub ac_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles appContext.ThreadExit

    appContext.MainForm.Dispose()
    appContext.MainForm = Nothing
    appContext.Dispose()
    appContext = Nothing
    frmSplash.Dispose()
    frmSplash = Nothing

End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
End Sub

Public Sub frm_HandleCreated()
    ShowLock.Set()
End Sub

这是完整的展示方式吗?没有其他条件吗?另外,您可以显示堆栈跟踪和/或更新表单以显示状态的方法吗?这是完整的显示方法没有什么特别的,正在显示的win表单只是一个带有两个标签的表单,progressbar设置为100。该表单在加载时还从包含电话号码的注册表项中读取单个值。在那之后,它就一直在那里,直到我们调用unload方法。。。到目前为止,您发布的代码看起来不错,因此我怀疑问题出在其他地方。具体来说,我希望看到在表单显示后更新进度的方法。也就是说,进度条从不更新。它在设计时设置为最大值,并且在显示后从不更新。是否需要将所有代码附加到一个文件中,或者我必须将其全部发布在黑板上?您只能像发布其余代码一样发布-您可以编辑问题并添加它。让我们从异常的堆栈跟踪开始-我可能可以从中找到它。这是完整显示方法吗?没有其他条件吗?另外,您是否可以显示堆栈跟踪

d/或更新表单以显示状态的方法?这是完整显示方法没有什么特别的,正在显示的win表单只是一个带有两个标签的表单,progressbar的值设置为100。该表单在加载时还从包含电话号码的注册表项中读取单个值。在那之后,它就一直在那里,直到我们调用unload方法。。。到目前为止,您发布的代码看起来不错,因此我怀疑问题出在其他地方。具体来说,我希望看到在表单显示后更新进度的方法。也就是说,进度条从不更新。它在设计时设置为最大值,并且在显示后从不更新。是否需要将所有代码附加到一个文件中,或者我必须将其全部发布在黑板上?您只能像发布其余代码一样发布-您可以编辑问题并添加它。让我们从异常的堆栈跟踪开始—我可能可以从中找到它。我也在考虑这些问题,但他正在检查他向我们展示的方法中的HandleCreated属性。因此,我的问题是我们没有看到什么。我想,但他正在检查飞溅形式,但我没有看到他检查它的主要形式,这是他实际上调用的,除非我有太多的Mt Dew。什么主要形式?Progress类不继承表单。所有这些都是通过脚本实现的。停止appContext.MainForm.InvokeShowDelegate进行中的Show方法,对吗?噢,lawd,我把appContext上的MainForm属性弄混了,弄糊涂了我通常都有一个名为MainForm的实际表单。这里没什么要看的,请移动一下。我也在考虑这些问题,但他正在检查他向我们展示的方法中的HandleCreated属性。因此,我的问题是我们没有看到什么。我想,但他正在检查飞溅形式,但我没有看到他检查它的主要形式,这是他实际上调用的,除非我有太多的Mt Dew。什么主要形式?Progress类不继承表单。所有这些都是通过脚本实现的。停止appContext.MainForm.InvokeShowDelegate进行中的Show方法,对吗?噢,lawd,我把appContext上的MainForm属性弄混了,弄糊涂了我通常都有一个名为MainForm的实际表单。这里没什么可看的,请往前走,这样我确信我能理解。前两段代码将进入我的windows窗体类窗体进度?剩下的就放在我上面贴的课上?您指定的事件是Threading.ManualResetEvent?事件。前两个事件进入进度类。您还需要使用addhandler将Form_OnHandleCreated方法连接到frmSplashI上的HandleCreated事件,因为您已经做了建议的更改。。。它仍然在发生,我已经稍微修改了我的程序,代码已经被重新发布了。你上一篇文章让我了解了发生了什么。我仍然是一个脚本孩子,我希望有一天我能和大个子一起玩。如果你看到别的东西,请告诉我。我有点沮丧。再次感谢你的帮助!!很抱歉让你失望-请参阅我在上面添加的新编辑。这很接近你所做的,但有一些小的修改。如果不是因为你不知道我会做什么,请不要难过。所以,我确信我理解。前两段代码将进入我的windows窗体类窗体进度?剩下的就放在我上面贴的课上?您指定的事件是Threading.ManualResetEvent?事件。前两个事件进入进度类。您还需要使用addhandler将Form_OnHandleCreated方法连接到frmSplashI上的HandleCreated事件,因为您已经做了建议的更改。。。它仍然在发生,我已经稍微修改了我的程序,代码已经被重新发布了。你上一篇文章让我了解了发生了什么。我仍然是一个脚本孩子,我希望有一天我能和大个子一起玩。如果你看到别的东西,请告诉我。我有点沮丧。再次感谢你的帮助!!很抱歉让你失望-请参阅我在上面添加的新编辑。这和你做的非常接近,但是有一些小的改动。如果不是因为你不确定我会做什么,请不要难过。