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
GUIThread = 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
Related
I was getting a weird error in a legacy application (not written by myself), where I was getting a StackOverflow exception when I changed the date on a calendar.
A simplified version is below. This is the code-behind of a Windows Form containing two controls, a Label called label2 and a calendar called MonthCalendar called monthCalendar1.
I think the idea here was to create a typewriter effect. I am on XP, my colleague on Windows 7 is able to run this ok:
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
{
const string sTextDisplay = "Press Generate button to build *** Reports ... ";
for (var i = 0; i < 45; i++)
{
label2.Text = Mid(sTextDisplay, 1, i);
System.Threading.Thread.Sleep(50);
//Error on this line
//An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll
Application.DoEvents();
}
}
public static string Mid(string s, int a, int b)
{
var temp = s.Substring(a - 1, b);
return temp;
}
I can't see the stack trace, all I see is:
{Cannot evaluate expression because the current thread is in a stack overflow state.}
Also, I'm interested in the comments asking why I haven't checked the stack trace of my StackOverflow exception, as it looks like this isn't possible without third party tools at least.
What could be causing this? Thanks
Remember, programs are stack-based. As your program runs, every function call places a new entry on the stack. Every time a function completes, you pop from the stack to see where to go back to, so you can continue the prior method. When a function completes and the stack is empty, the program ends.
It's important to remember the program stack is generous, but finite. You can only put so many function calls on the stack before it runs out of space. This is what happens when we say the stack overflows.
DoEvents() is just another function call. You might put it in a long-running task to allow your program to handle messages from the operating system about user activity: things like clicks, keystrokes, etc. It also allows your program to handle messages from the operating system, for example if the program needs to re-draw it's windows.
Normally, there will only be one or two (or even zero) messages waiting for a DoEvents() call. Your program handles these, the DoEvents() call is popped off the stack, and the original code continues. Sometimes, there may be many messages waiting. If any of those messages also results in code running that again calls to DoEvents(), we are now another level deep in the call stack. And if that code in turn finds a message waiting which causes DoEvents() to run, we'll be yet another level deep. Maybe you can see where this is going.
DoEvents(), used in conjuction with the MouseMove event, is a common source of problems like this. MouseMove events can pile up on you very quickly. This can also happen with KeyPress events, when you have a key that is held down.
Normally, I wouldn't expect a Calendar DateChanged event to have this kind of problem, but if you have DoEvents() somewhere else, or drive another event (perhaps on your label) that in turn updates your calendar, you can easily create a cycle that will force your program to spiral into a stack overflow situation.
What you want to do instead is explore the BackgroundWorder component, or the newer Task and async patterns.
You may also want to read my write-up on DoEvents() for this question:
How to use DoEvents() without being "evil"?
Normally you have a message pump pretty close to the top of the stack. Adding lots of messages isn't ever resulting in a "deep" stack, as they are all processed by a top level pump. Using DoEvents is creating a new message pump at a point deeper in the stack. If one of the messages that you are pumping also calls DoEvents, you now have a message pump even deeper on in the stack. If that message pump has another message that calls DoEvents ... and you get the idea.
The only way for the stack to clear up again is for the message queue to be empty, at which point you start calling back up the stack until you get to the top level message pump.
The problem here is that your code doesn't make it easy. It calls DoEvents a lot in a loop, so it needs to have an idle queue for quite some time to actually get back out of that loop. On top of that, if you happen to have an "active" application that's sending lots of messages to the message queue, possibly lots of monthCalendar1_DateChanged events, or even other events using DoEvents in a loop, or just other events to keep the queue from being empty, it's not particularly hard to believe that your stack would get deep enough to result in an SOE.
The ideal solution of course is to not use DoEvents. Write asynchronous code instead, so that your stack depth never exceeds a constant value.
DoEvents shouldn't use in any case and you don't require substring to archive a TypeWriting effect
Here is the best way I know at the moment:
using System.Threading;
private string text = "this is my test string";
private void button1_Click(object sender, EventArgs e)
{
new Thread(loop).Start();
}
private void loop()
{
for (int i = 0; i < text.Length; i++)
{
AddChar(text[i]);
Thread.Sleep(50);
}
}
private void AddChar(char c)
{
if (label1.InvokeRequired)
Invoke((MethodInvoker)delegate { AddChar(c); });
else
label1.Text += c;
}
In .NET 4.0 I'm dealing with an app which has a long loading time (about 20 seconds), so I wanted to display a swish scrolling marquee on a form that comes on top of the application whilst it is loading.
Since the main UI thread is doing all the loading of data UI elements, I couldn't get that to execute on a separate thread, so I ended up trying to run the form on a new thread. I ended up sticking this code in the form itself, to have it show itself on a new thread, like this:
Public Class frmWait
Public Property Message As String
Get
Return Me.lblMessage.Text
End Get
Set(value As String)
If Not String.IsNullOrEmpty(value) Then
Me.lblMessage.Text = value
Else
Me.lblMessage.Text = DefaultMessage
End If
End Set
End Property
Private OwnerThread As Thread
Private OwnerForm As Form
Private Const DefaultMessage As String = "しばらくお待ちください..."
Public Sub New(ByVal ParentForm As Form)
InitializeComponent()
Me.Message = DefaultMessage
Me.OwnerForm = ParentForm
End Sub
Public Sub New(ByVal Message As String, ByVal ParentForm As Form)
Call InitializeComponent()
Me.Message = Message
Me.OwnerForm = ParentForm
End Sub
Public Sub ShowOnThread()
' Position the form in the center of the owner
With Me.OwnerForm
Dim ownerCenter As New Point(.Location.X + CInt(.Width / 2), .Location.Y + CInt(.Height / 2))
Me.Location = New Point(ownerCenter.X - CInt(Me.Width / 2), ownerCenter.Y - CInt(Me.Height / 2))
End With
Me.OwnerThread = New Thread(New ThreadStart(AddressOf Me.ShowDialog))
Call Me.OwnerThread.Start()
End Sub
Public Shadows Sub Close()
If Me.OwnerThread IsNot Nothing AndAlso Me.OwnerThread.IsAlive Then
Call Me.OwnerThread.Abort()
Else
Call MyBase.Close()
End If
End Sub
End Class
This is probably quite clumsy, but I am showing it in different places in the application, so this seemed the most code-efficient way of doing this...
It actually works quite well, but I am encountering problems from time to time with this and need some help on how to address these issues.
Sometimes when the form gets closed I get an error about the thread being aborted in an unsafe manner.
At the moment I position the form manually in the centre of the form I want it to cover form. Ideally I'd like to be able to call .ShowDialog(ParentForm) on it, but of course that raises an exception because of cross-thread access from one form to the other.
Any suggestions on how to resolve this would be most appreciated.
Because I know virtually nothing about threading I probably coded this like a monkey, so if there is a better method to get this done, I would very much like to know about it.
The code I list is in VB.NET, but answer code in C# is fine too (for any overzealous retaggers)
UPDATE:
I realise now that I should have given a lot more details in my question... The wait form is actually not the first form I am displaying the app. There first is a login screen. When the user is authenticated, the login form launches the main interface of the app, which is the form which actually takes a long time to load.
I am displaying the wait form in between the login form and the main interface. I also use this form to cover for any long running tasks launched on the main interface by the user.
VisualStudio can do this for you. You can certainly write your own, of course, but if you look at your project options under Application there is a setting for Splash Screen. You can assign any form (other than the startup form) to be your splash screen. This runs on its own thread and you can marshall calls to it during startup to advance a progress bar, etc.
MSDN : Splash Screen
Instead of trying to show a dialog on a separate thread you should be moving your loading code to a separate thread / background worker.
Then just start your threads and show the progressbar on form_load and hide the progressbar when the thread completes:
Dim _progressForm As frmLoading
Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
'start loading on a separate thread
BackgroundWorker1.RunWorkerAsync()
'show a marquee animation while loading
_progressForm = New frmLoading
_progressForm.ShowDialog(Me)
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'simulate a long load
For i As Integer = 1 To 10
System.Threading.Thread.Sleep(1000)
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
_progressForm.Close()
End Sub
Have a look at TaskFactory.New
Run your threaded code of a different thread to keep the UI responsive
http://msdn.microsoft.com/en-us/library/ee782519.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-3
You could use the ApplicationContext class to allow the splash screen to be run first and then swap in the Main form when it is ready. You use it in place of your main form in the call to Application.Run:
Application.Run(new MyApplicationCtx())
Just googled up a article for you as well:
http://www.codeproject.com/Articles/5756/Use-the-ApplicationContext-Class-to-Fully-Encapsul
I've just "earned" the privilege to maintain a legacy library coded in C# at my current work.
This dll:
Exposes methods for a big legacy system made with Uniface, that has no choice but calling COM objects.
Serves as a link between this legacy system, and another system's API.
Uses WinForm for its UI in some cases.
More visually, as I understand the components :
*[Big legacy system in Uniface]* ==[COM]==> [C# Library] ==[Managed API]==> *[Big EDM Management System]*
The question is: One of the methods in this C# Library takes too long to run and I "should" make it asynchronous!
I'm used to C#, but not to COM at all. I've already done concurrent programming, but COM seems to add a lot of complexity to it and all my trials so far end in either:
A crash with no error message at all
My Dll only partially working (displaying only part of its UI, and then closing), and still not giving me any error at all
I'm out of ideas and resources about how to handle threads within a COM dll, and I would appreciate any hint or help.
So far, the biggest part of the code I've changed to make my method asynchronous :
// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
errMsg = "";
try {
Action<string> asyncOp = AsyncComparedSearch;
asyncOp.BeginInvoke(application, null, null);
} catch (ex) {
// ...
}
return 0;
}
private int AsyncComparedSearch(string application) {
// my actual method doing the work, that was the called method before
}
Any hint or useful resource would be appreciated.
Thank you.
UPDATE 1:
Following answers and clues below (especially about the SynchronizationContext, and with the help of this example) I was able to refactor my code and making it to work, but only when called from another Window application in C#, and not through COM.
The legacy system encounters a quite obscure error when I call the function and doesn't give any details about the crash.
UPDATE 2:
Latest updates in my trials: I managed to make the multithreading work when the calls are made from a test project, and not from the Uniface system.
After multiple trials, we tend to think that our legacy system doesn't support well multithreading in its current config. But that's not the point of the question any more :)
Here is a exerpt of the code that seems to work:
string application;
SynchronizationContext context;
// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
this.application = application;
context = WindowsFormsSynchronizationContext.Current;
Thread t = new Thread(new ThreadStart(AsyncComparedSearchAndShowDocs));
t.Start();
errMsg = "";
return 0;
}
private void AsyncComparedSearch() {
// ANY WORK THAT AS NOTHING TO DO WITH UI
context.Send(new SendOrPostCallback(
delegate(object state)
{
// METHODS THAT MANAGE UI SOMEHOW
}
), null);
}
We are now considering other solutions than modifying this COM assembly, like encapsulating this library in a Windows Service and creating an interface between the system and the service. It should be more sustainable..
It is hard to tell without knowing more details, but there are few issues here.
You execute the delegate on another thread via BeginInvoke but you don't wait for it. Your try\catch block won't catch anything as it has already passed while the remote call is still being executed. Instead, you should put try\catch block inside AsyncComparedSearch.
As you don't wait for the end of the execution of remote method (EndInvoke or via callback) I am not sure how do you handle the results of the COM call. I guess then that you update the GUI from within AsyncComparedSearch. If so, it is wrong, as it is running on another thread and you should never update GUI from anywhere but the GUI thread - it will most likely result with a crash or other unexpected behavior. Therefore, you need to sync the GUI update work to GUI thread. In WinForms you need to use Control.BeginInvoke (don't confuse it with Delegate.BeginInvoke) or some other way (e.g. SynchronizationContext) to sync the code to GUI thread. I use something similar to this:
private delegate void ExecuteActionHandler(Action action);
public static void ExecuteOnUiThread(this Form form, Action action)
{
if (form.InvokeRequired) { // we are not on UI thread
// Invoke or BeginInvoke, depending on what you need
form.Invoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
}
else { // we are on UI thread so just execute the action
action();
}
}
then I call it like this from any thread:
theForm.ExecuteOnUiThread( () => theForm.SomeMethodWhichUpdatesControls() );
Besides, read this answer for some caveats.
I'm playing a little bit with some C# Winforms/WPF code and just stumbled upon something strange.
Let's say I have a code like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DoSomething();
// something more if everything worked okay
}
}
What puzzles me is that I cannot simply close the application from the method DoSomething before the constructor finishes its job. If anything during the execution of DoSomething fails, I need to close the application immediately; however, it just keeps running, executes the part // something more... and THEN closes, but that's way too late for me.
I have to put the code for closing the form inside the constructor itself with a following return; and then it works, but I don't really find that an acceptable solution. I'm trying to move such validation logic from the constructor to my methods.
I've tried things like:
public void DoSomething()
{
Close();
}
and
public void DoSomething()
{
Application.Current.Shutdown();
}
But it doesn't seem to work. Yes, both codes do close the application, but only after a fully finished constructor code.
Why would I need such a thing? Well, because at startup I need to check for various things, like availability of the connection and hardware, validate the user etc, and if anything fails, there's no point of executing more code.
I tried the same principle with Winforms and WPF (hence the tags) — works the same way.
Can anybody provide an explanation or a solution?
Just try using Environment.Exit(-1) in your situation and all will be good.
ADDED: This is the best reference i can get for you.
Difference between Application.Exit vs Application.Shutdown vs Environment.Exit
Application.Exit() is for exiting a windows forms application in a graceful way. Basically, it stops the message pump, closes all windows and lands you back in the Main() method just after the call to Application.Run(). However, sometimes it doesn't appear to work - this is usually because there are other foreground threads (apart from the UI thread) still running which are preventing the thread from ending.
Application.Shutdown() is (broadly) the equivalent of Application.Exit() in a WPF application. However, you have a bit more control as you can set the ShutDownMode so that the application shuts down when the main window closes, the last window closes or only when this method is called.
Environment.Exit() kills all running threads and the process itself stone dead. This should only be used in WF or WPF as a last resort when the more graceful methods are not working for some reason. It can also be used to make an abrupt exit from a console application.
Another Reference: How to properly exit a C# application?
You can always ignore your fellow developers and just use Environment.FailFast()
But really - don't. If you have critical things to do, S.A verifying the serial port is connected to the nuclear power plant, just do it prior. There's no rule forcing you to Application.Run(...) as soon as Main() is called.
There have already been posted viable solutions for your problem.
Just to answer your follow-up question: the reason why methods like Close() and Shutdown() do not immediately exit your application is that both just push messages into the application's message queue. They are only processed after MainWindow's constructor finished and code execution returns to the message processing loop, maybe even after some other still pending messages in the queue have been handled too.
On the contrary, methods like Environment.Exit() or Environment.FailFast() are kind of hard-core os functions leading to more or less immediately killing the process.
A workaround would be to throw a exception and handle it in application.UnhandledException
Define an Exception class:
public class InitializationException : Exception
{
public InitializationException()
{}
public InitializationException(string msg)
: base(msg)
{}
public InitializationException(string msg, Exception inner)
: base(msg, inner)
{}
}
and change your code like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
try
{
DoSomething();
// maybe something more if everything went ok
}
catch( InitializationException ex )
{
// log the exception
Close();
}
}
public void DoSomething()
{
if (notSomethingOK)
throw new InitializationException( "Something is not OK and the applicaiton must shutdown." );
}
}
This is a clean and maintainable solution.
System.Windows.Forms.Application.Exit();
Conceptually such things should not be used in class constructors. Constructor is somewhat made for instance initialization with starting state and not the actual things may happen (like exceptions, message boxes, etc).
Don't forget that you can just return; from constructor, if you need to break its execution. This is better tactic (most times you don't need to just shutdown application on error without displaying some text).
There are "window shown", "visibility changed", "loaded" and many other events in C# on Windows/WPF, that you can override virtually or add as an event handler. Initialize your form/app there.
They're normal methods so all works as expected. You can try throwing exceptions that your application entry point (Main function) will just catch and ignore.
For WPF, check this:
- https://msdn.microsoft.com/en-us/library/system.windows.forms.application.setunhandledexceptionmode(v=vs.110).aspx.
I have a c# form, and the initialization time takes a while (its getting information from a server, and populating a TreeView). Right now, the code looks similar to this:
public class myForm : Form
{
InitializeComponent();
List<Location> locations = getServerLocations(); // Server call
foreach( Location loc in locations )
{
List<POI> POIs = loc.getLocationPOIs(); // Server call
foreach( POI poi in POIs )
{
List<POIDetails> = poi.getPOIDetails(); // Server call
....
}
}
}
you get the point I think ... So there is a large tree, and I know I can not make the calls all the way down until the user expands the tree. But the intent is I just want the Form to display, with a 'loading...' or something on a tool strip while all the processing and server gets are happening.
Right now, it seems as if I haven't loaded the application yet because nothing will show to the user until all the calls are complete.
You shouldn't do any long running processing on the UI thread - instead move this to another thread i.e using a BackgroundWorker. You can initially show the "Loading" screen and, once the background worker completes, update your UI with your tree structure.
You should work with multi threading process, so that you can separate the process that takes time from the rest of the process. Here is a blog that may help you. .NET 4.0 and System.Threading.Tasks
Running your initialization on a separate thread is the preferred way. But if you're constrained to run it on the UI thread then try calling Application.DoEvents() right after your call to .Show() or .ShowDialog() of your form.
If the form shows up, it will still be unresponsive to user actions until the initialization is completed. So running the initialization on a separate thread is the better solution.