开发者

How do I get the GUI thread of winform?

I have a winforms app with multiple GUI threads. I want them to be able to access each other's thread objects without having to keep track of that information separately.

Is there a function in .NET that I can feed a winforms control or window object, and get back the thread? Or a function in the API I can pinvoke for the threadID?

(please no comments saying I should do it another way... also this is not about cross-thread window operations.)

Thanks!

Edit

For those of you who for some reason believed my italicized text, congratualations, you're hired!! Here is the problem:

"App is crashing in the wild by locking up totally, that is, it stop responding. Very intermittent, and trying to debug it, it seems to never happen."

So what do do? Install an option in the program that the user can activate under our direction, whereby from another GUI thread in the same app, do a thread.abort on the main GUI thread, then we can look at the call stack in the error log. Viola, found an impossible to debug error in less than a day. (Stop now, it had nothing to do with abusing multithreading:-)

I'll admit I almost didn't ask this, the reason I did was I could see an object reference to the main form, but there wasn't any for its thread. I'm giving Chris Shain the answer a/c it is a quick way, unfortunately when the thread is hanging, I wouldn't be able to do an invoke (it would hang too). A little more digging revealed the GetWindowThreadProcessId API call. But it's an unmanaged thread ID, apparently there are complications turning that into a managed thread ID.

So I bit the bullet and put in a global reference to the main UI thread. Would have posted it to begin with, but hadn't written it yet.

Now if you'll pardon the VB...

In main public module/static class:

Public GUIThread As Threading.Thread
Sub Main()
    '' //  Create app main window
    ShellForm = New frmShell
    '' // Save main GUI Thread for abort routine
    GUIT开发者_Python百科hread = Threading.Thread.CurrentThread  
    If GetSetting("MyApp", "Testing", "CrashDebug", "False") = "True" Then
            '' //  DO NOT run the pgm. like this normally - with try/catch around
            '' //  Application.Run - or uncaught errors will kill the whole app!!!
        Try

            '' // This is the other of the ‘Multiple GUI threads’ I talked
            '' // about in the Orig Post.
            Dim t As New Threading.Thread(AddressOf StartCrashDebug)
            t.Start()

            Application.Run(ShellForm)
        Catch ex As Exception
            '' // This error routine passes errors off to another thread which 
            '' // logs them (and also shows messages)
            MyLogError(ex, "CrashDebug - Main Window blew up")
        End Try
    Else
        '' // Normal mode - uncaught errors will get caught by UnhandledException, 
        '' // logged, and Winforms will keep the GUI alive (since we _do_ care 
        '' // more about users than computers right ;-)
        Application.Run(ShellForm)
    End If
End Sub
Sub StartCrashDebug()
    Dim f As New frmCrashFinder
    '' // Starting a window like this on a separate thread makes it ‘Another 
    '' // GUI thread’ for winforms, by design
    Application.Run(f)
 End Sub

In ‘aborter’ WinForm:

Public Class frmCrashFinder 
    Inherits Windows.Form

    Private Sub Abort_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Abort.Click
        GUIThread.Abort()
    End Sub
End Class


All GUI elements in Windows Forms are typically done on a single thread. I strongly recommend avoiding trying to do this any other way.

You can always marshal code to that thread by using Control.Invoke or Control.BeginInvoke with any Control.

If you really want to get the thread's ID (not sure what use this will be..?), you could use:

int GetControlThreadId(Control control)
{
    int threadId;
    control.Invoke( new Action( () => 
       {
           threadId = Thread.CurrentThread.ManagedThreadId;
       }));
    return threadId;
}


If your code is not in a form or control, you can use

if (System.Windows.Forms.Form.ActiveForm.InvokeRequired)
{
    System.Windows.Forms.Form.ActiveForm.Invoke(...);
}


This should do it, however I agree with other posters that this is probably the wrong thing to do for other reasons...

var thatWindowsThread = (Thread)(WhateverWindow.Invoke(()=>Thread.CurrentThread);


WindowsFormsSynchronizationContext.Current has Post and Send methods from which you can delegate command to UI thread


If you don't have access to any forms or windows or controls you can pull the thread or SynchronizationContext from, you can use

        System.Windows.Forms.Application.OpenForms    

This worked for me. System.Windows.Forms.Form.ActiveForm was null in my case, but Metro's answer made me look closer at static classes in System.Windows.Forms. Use

System.Windows.Forms.Application.OpenForms.Invoke(...) or BeginInvoke. 

You can get the rest from other answers.


Better answer:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsGUIThread([MarshalAs(UnmanagedType.Bool)] bool bConvert);

http://pinvoke.net/default.aspx/Constants.IsGUIThread

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜