Winforms – Random IT Utensils https://blog.adamfurmanek.pl IT, operating systems, maths, and more. Sat, 09 Nov 2024 21:11:37 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.2 Exception propagation in WinForms https://blog.adamfurmanek.pl/2018/09/08/exception-propagation-in-winforms/ https://blog.adamfurmanek.pl/2018/09/08/exception-propagation-in-winforms/#respond Sat, 08 Sep 2018 08:00:41 +0000 https://blog.adamfurmanek.pl/?p=2594 Continue reading Exception propagation in WinForms]]> Let’s start with the following code:

using System;
using System.Windows.Forms;
 
class Program1
{
    [STAThread]
    static void Main()
    {
        var form = new Form();
        form.Load += (sender, e) => throw new Exception();
 
        try
        {
            Application.Run(form);
        }
        catch(Exception e)
        {
            MessageBox.Show("This doesn't execute");
        }
        finally
        {
            MessageBox.Show("But this shows up");
        }
    }
}

You throw exception as soon as your form is loaded, however, catch block is not executed. What happens?

Initially I though this is out of band exception which is thrown on another thread. But after some debugging the reason is much simpler. WinForms provide special event handler for unhandled exceptions, namely ThreadException. If you decompile some code, you can see this:

System.Windows.Forms.NativeWindow.Callback:

private IntPtr Callback(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
{
	Message message = Message.Create(hWnd, msg, wparam, lparam);
	try
	{
		if (this.weakThisPtr.IsAlive && this.weakThisPtr.Target != null)
		{
			this.WndProc(ref message);
		}
		else
		{
			this.DefWndProc(ref message);
		}
	}
	catch (Exception e)
	{
		this.OnThreadException(e);
	}
	finally
	{
		if (msg == 130)
		{
			this.ReleaseHandle(false);
		}
		if (msg == NativeMethods.WM_UIUNSUBCLASS)
		{
			this.ReleaseHandle(true);
		}
	}
	return message.Result;
}

When you throw exception, it is being caught by WinForms and passed to the event handler. There we can see this:

System.Windows.Forms.Application.ThreadContext.OnThreadException:

ThreadExceptionDialog threadExceptionDialog = new ThreadExceptionDialog(t);
DialogResult dialogResult = DialogResult.OK;
IntSecurity.ModifyFocus.Assert();
try
{
	dialogResult = threadExceptionDialog.ShowDialog();
}
finally
{
	CodeAccessPermission.RevertAssert();
	threadExceptionDialog.Dispose();
}
if (dialogResult != DialogResult.Abort)
{
	if (dialogResult == DialogResult.Yes)
	{
		WarningException ex = t as WarningException;
		if (ex != null)
		{
			Help.ShowHelp(null, ex.HelpUrl, ex.HelpTopic);
		}
	}
}
else
{
	Application.ExitInternal();
	new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
	Environment.Exit(0);
}

The application is closed. Top level catch block is not executed because there is physically no exception anymore. Finally is being executed because of stack unwinding. If there was call to Environment.FailFast, it would not be executed.

]]>
https://blog.adamfurmanek.pl/2018/09/08/exception-propagation-in-winforms/feed/ 0
Async Wandering Part 3 — Awaiting in synchronous WinForms code https://blog.adamfurmanek.pl/2017/01/07/async-wandering-part-3/ https://blog.adamfurmanek.pl/2017/01/07/async-wandering-part-3/#comments Sat, 07 Jan 2017 09:00:39 +0000 https://blog.adamfurmanek.pl/?p=1962 Continue reading Async Wandering Part 3 — Awaiting in synchronous WinForms code]]>

This is the third part of the Async Wandering series. For your convenience you can find other parts in the table of contents in Part 1 – Why creating Form from WinForms in unit tests breaks async?

async and await are great features of C#. By using them we can hide all cumbersome details of callbacks and write code in “synchronous” way. However, without good understanding of internals we might quickly run into troubles. Especially if we want to introduce asynchronous methods in synchronous context. Let’s see.

Challenge

Imagine that we have synchronous method in WinForms codebase. Actual technology is not that important, in WPF you might quickly get the same problem since it uses similar concepts.

Now imagine, that you want to run some lengthy action and you would like to have it asynchronous, however, before ending your job you would like to wait for the results. Snippet representing the idea:

public void SynchronousAction(){
	// Doing stuff
	var task = LengthyAction(this.Form);
	// Doing even more stuff
	task.Wait(); // We want to make sure that action is done
	return;
}

public async Task LengthyAction(Form form){
	// Crazy stuff going on here
}

SynchronousAction runs on UI thread, LengthyAction might run somewhere else. This solution might be sufficient for our needs (if lengthy action is not that lengthy or else we will freeze the UI), however, imagine now, that action does the following:

public async Task LengthyAction(Form form){
	form.Invoke(someLambda);
}

This quickly leads to a deadlock.

Deadlock?

Invoke works by posting message to other thread’s message loop and waits until it is handled. In our case, UI thread cannot process the message because it is blocked on task.Wait() method. If we would use await, then we would have no such problem — await in WinForms awaits for tasks on message pump and is able of processing messages. This is very important detail which you don’t need to know as long as you do not block UI thread explicitly. General rule of thumb is: if you use async somewhere in your codebase, you must use it all the way up. Every method must be asynchronous or else you need to be very careful with waits.

Ok, so how can we solve this problem without rewriting everything to asynchronous methods? Well, we can do some dirty magic.

Running message pump manually

Instead of waiting for a task indefinitely, we will perform busy waiting and run message loop by hand:

public void SynchronousAction(){
{
	// Doing stuff
	var signal = new ManualResetEvent(false );
	var task = Task.Run( async () =>
	{
		await LengthyAction(this.Form);
		signal.Set();
	});

	// Doing even more stuff
	while (!signal.WaitOne( TimeSpan.FromMilliseconds(1)))
	{
		Application.DoEvents();
	}
	return;
}

Instead of running the method directly, we create another task with asynchronous lambda. This new task awaits for lengthy action and sets signal when it is done. We are guaranteed that the second task will not set the signal too early, because we can simply await for our lengthy action.

Next, we cannot block UI thread. Instead of waiting indefinitely, we sleep for a millisecond, call message pump and retry the operation. We will not move forward until the signal is set, however, if lengthy action posts a message to our thread, we will execute it with a little delay (one millisecond here).

Summary

Does it work? Yes. Is it nice? Well, we might argue here. Introducing asynchronous code in synchronous codebase is not easy, we cannot simply replace all methods with asynchronous ones because sometimes it is technically impossible. How do you await for asynchronous event handlers? And if you know (since it is possible but cumbersome), how do you do that in VB.NET (in that language event cannot return anything, so you don’t have a task to wait for). This snippet might save your life one day, but you had better don’t need to try.

Bonus chatter: WPF doesn’t have a Application.DoEvents() for running message pump, however, it looks like it is possible to achieve similar effect with this code.

]]>
https://blog.adamfurmanek.pl/2017/01/07/async-wandering-part-3/feed/ 2
Async Wandering Part 2 — Synchronous call on WinForms control and ObjectDisposedException https://blog.adamfurmanek.pl/2016/12/31/async-wandering-part-2/ https://blog.adamfurmanek.pl/2016/12/31/async-wandering-part-2/#comments Sat, 31 Dec 2016 09:00:19 +0000 https://blog.adamfurmanek.pl/?p=1956 Continue reading Async Wandering Part 2 — Synchronous call on WinForms control and ObjectDisposedException]]>

This is the second part of the Async Wandering series. For your convenience you can find other parts in the table of contents in Part 1 – Why creating Form from WinForms in unit tests breaks async?

I once found the following code in some WinForms application:

private async Task Broadcast(Func< object, Task> action, object sender)
{
	if (!Control.InvokeRequired)
	{
		await action(sender);
	}
	else
	{
		await (Task)Control.Invoke(action, new[] { sender});
	}
}

Here Control is any WinForms control, usually some kind of a Form. The code is supposed to run some lambda on UI thread, is this is possible and if it is required. This snipped worked quite good for some time, however, one day it started throwing ObjectDisposedException on Control.Invoke. The reason is quite obvious: we don’t check if the Control is still there, and since this code runs in non-ui thread, the control might get disposed in any arbitrary moment in time. The question is: how to solve it? We might of course try to catch exception and run action normally, however, let’s start experimenting with the code.

First attempt

We can simply check if control is disposed before running the lambda:

private async Task Broadcast(Func< object, Task> action, object sender)
{
	if (!Control.InvokeRequired || Control.IsDisposed)
	{
		await action(sender);
	}
	else
	{
		await (Task)Control.Invoke(action, new[] { sender});
	}
}

Looks good, unfortunately, it doesn’t work because of a race condition. Imagine that worker thread checks whether control was disposed and tries to execute second branch (with Control.Invoke). Before actually invoking the method, the thread might be suspended and other thread might dispose the control.

Second attempt

Let’s decompile some WinForms code. If we go to the Component.Dispose method, we will see the following:

protected virtual void Dispose(bool disposing) {
	if (disposing) {
		lock(this) {
			if (site != null && site.Container != null) {
				site.Container.Remove(this);
			}
			if (events != null) {
				EventHandler handler = (EventHandler)events[EventDisposed];
				if (handler != null) handler(this, EventArgs.Empty);
			}
		}
	}
}

It looks like Dispose locks itself before disposing the object. We can use this to block control from disposing until we finish our job:

private async Task Broadcast(Func< object, Task> action, object sender)
{
	lock(Control)
	{
		if (!Control.InvokeRequired || Control.IsDisposed)
		{
			await action(sender);
		}
		else
		{
			await (Task)Control.Invoke(action, new[] { sender});
		}
	}
}

Looks good and in theory this could work. However, this code has some fatal flaw: if action lambda awaits for a method which in turn call Broadcast from other thread, we will get a deadlock. We need to come up with fancier solution.

Third attempt

private async Task Broadcast(Func< object, Task> action, object sender)
{
	if (!Control.InvokeRequired
	{
		await action(sender);
		return;
	}
	
	IAsyncResult result = null;
	lock (Control)
	{
		if (!Control.IsDisposed)
		{
			result = Control.BeginInvoke(action, new[] { sender });
		}
	}
	if (result != null)
	{
		result.AsyncWaitHandle.WaitOne();
		Task toWait = null;
		lock (Control)
		{
			if (!Control.IsDisposed)
			{
				toWait = (Task)Control.EndInvoke(result);
			}
		}
		if (toWait != null)
		{
			await toWait;
		}
	}
}

We first check if invoke is required — if it is not, we simply execute our action.
Next, we try to invoke action in non-blocking manner. We lock a control, check if it is disposed, and if it is not, we post our lambda. We release the lock, so the lambda is able to call the method deeper in the execution stack without deadlocking. Next, we try to wait for our lambda, lock control once again, once again check if it is disposed, and finally obtain task. Now, we need to release the lock once again, and since our lambda represents asynchronous action, we have a Task to await for.

Summary

It looks like we found a solution for our problem. I leave it for your discretion if you prefer to call the code with multiple locks and tasks, or just simply catch the exception and rerun the action. And, what’s more important, I cannot guarantee that last solution works fine in all cases — it worked quite reliably in my situation, however, threads can be very surprising.

]]>
https://blog.adamfurmanek.pl/2016/12/31/async-wandering-part-2/feed/ 1
Async Wandering Part 1 — Why creating Form from WinForms in unit tests breaks async? https://blog.adamfurmanek.pl/2016/10/08/async-wandering-part-1/ https://blog.adamfurmanek.pl/2016/10/08/async-wandering-part-1/#comments Sat, 08 Oct 2016 08:00:36 +0000 https://blog.adamfurmanek.pl/?p=1840 Continue reading Async Wandering Part 1 — Why creating Form from WinForms in unit tests breaks async?]]>

This is the first part of the Async Wandering series. For your convenience you can find other parts using the links below (or by guessing the address):
Part 1 — Why creating Form from WinForms in unit tests breaks async?
Part 2 — Synchronous call on WinForms control and ObjectDisposedException
Part 3 — Awaiting in synchronous WinForms code
Part 4 — Awaiting for void methods
Part 5 — Catching exceptions from async void
Part 6 — Exceptions logging
Part 7 — Exceptions on unobserved tasks
Part 8 — async and await — the biggest C# mistake?
Part 9 — awaiting with timeout
Part 10 — Project Loom in .NET – awaiting with fibers
Part 11 — Wrapping fibers in context
Part 12 — Fibers with generics
Part 13 — Reentrant recursive async lock
Part 14 — Async with Fibers reimplemented in .NET Core
Part 15 — How async in C# tricks you and how to order async continuations

Recently I was debugging little unit test which was creating Form (WinForms) and later was executing asynchronous method with async keyword which was causing a deadlock. Apart from the stupidity o testing UI this way (which I am not going to explain since it is irrelevant to this note), the code was so simple that there was next to nothing to spoil. The code looked similar to this:

[TestMethod]
public async Task DoWork_FormPassed_ExecutedSuccessfully_TrueReturned()
{
	// Arrange
	var form = new Form();
	var sut = CreateSUT();

	// Act
	var result = await sut.DoWork(form);

	// Assert
	Assert.That(result, Is.True);
}

We simply create system under test and Form, next we execute a method, and finally we assert. Nothing fancy here, however, call to DoWork never returned and the process was stalled.

Observations

The interesting thing here is: if we pass null to DoWork, everything works fine. We could try to fake it but FakeItEasy is unable to do that. So it looks like creating Form causes this whole mess. But why? Let’s dig into the code (decompiled with R#):

First, the Form constructor:

public Form()
{
  int num = this.IsRestrictedWindow ? 1 : 0;
  this.formStateEx[Form.FormStateExShowIcon] = 1;
  this.SetState(2, false);
  this.SetState(524288, true);
}

Well, it looks decent. Some flags, some state, nothing else. First line is integersing — why does it create an unused variable? Maybe this.IsRestrictedWindow does something in getter? Let’s see:

/// <summary>Gets a value indicating whether the form can use all windows and user input events without restriction.</summary>
/// <returns>true if the form has restrictions; otherwise, false. The default is true.</returns>
/// <filterpriority>1</filterpriority>
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public bool IsRestrictedWindow
{
  get
  {
	if (this.formState[Form.FormStateIsRestrictedWindowChecked] == 0)
	{
	  this.formState[Form.FormStateIsRestrictedWindow] = 0;
	  try
	  {
		IntSecurity.WindowAdornmentModification.Demand();
	  }
	  catch (SecurityException ex)
	  {
		this.formState[Form.FormStateIsRestrictedWindow] = 1;
	  }
	  catch
	  {
		this.formState[Form.FormStateIsRestrictedWindow] = 1;
		this.formState[Form.FormStateIsRestrictedWindowChecked] = 1;
		throw;
	  }
	  this.formState[Form.FormStateIsRestrictedWindowChecked] = 1;
	}
	return (uint) this.formState[Form.FormStateIsRestrictedWindow] > 0U;
  }
}

Some magic but nothing here should break async so this is a dead end. Well, let’s check class hierarchy:

public class Form : ContainerControl

Hmm, it looks like this is a derived class (which should not be a surprise). Let’s go to the base’s constructor:

/// <summary>Initializes a new instance of the <see cref="T:System.Windows.Forms.ContainerControl" /> class.</summary>
public ContainerControl()
{
  this.SetStyle(ControlStyles.AllPaintingInWmPaint, false);
  this.SetState2(2048, true);
}

Still nothing. Let’s go up:

/// <summary>Initializes a new instance of the <see cref="T:System.Windows.Forms.ScrollableControl" /> class.</summary>
public ScrollableControl()
{
  this.SetStyle(ControlStyles.ContainerControl, true);
  this.SetStyle(ControlStyles.AllPaintingInWmPaint, false);
  this.SetScrollState(1, false);
}

And up:

/// <summary>Initializes a new instance of the <see cref="T:System.Windows.Forms.Control" /> class with default settings.</summary>
public Control()
: this(true)
{
}

Oh, here is something interesting. Let’s see the constructor with parameter:

internal Control(bool autoInstallSyncContext)
{
  this.propertyStore = new PropertyStore();
  this.window = new Control.ControlNativeWindow(this);
  this.RequiredScalingEnabled = true;
  this.RequiredScaling = BoundsSpecified.All;
  this.tabIndex = -1;
  this.state = 131086;
  this.state2 = 8;
  this.SetStyle(ControlStyles.UserPaint | ControlStyles.StandardClick | ControlStyles.Selectable | ControlStyles.StandardDoubleClick | ControlStyles.AllPaintingInWmPaint | ControlStyles.UseTextForAccessibility, true);
  this.InitMouseWheelSupport();
  if (this.DefaultMargin != CommonProperties.DefaultMargin)
	this.Margin = this.DefaultMargin;
  if (this.DefaultMinimumSize != CommonProperties.DefaultMinimumSize)
	this.MinimumSize = this.DefaultMinimumSize;
  if (this.DefaultMaximumSize != CommonProperties.DefaultMaximumSize)
	this.MaximumSize = this.DefaultMaximumSize;
  Size defaultSize = this.DefaultSize;
  this.width = defaultSize.Width;
  this.height = defaultSize.Height;
  CommonProperties.xClearPreferredSizeCache((IArrangedElement) this);
  if (this.width != 0 && this.height != 0)
  {
	NativeMethods.RECT lpRect = new NativeMethods.RECT();
	// ISSUE: explicit reference operation
	// ISSUE: variable of a reference type
	NativeMethods.RECT& local = @lpRect;
	int num1;
	int num2 = num1 = 0;
	// ISSUE: explicit reference operation
	(^local).bottom = num1;
	int num3;
	int num4 = num3 = num2;
	// ISSUE: explicit reference operation
	(^local).top = num3;
	int num5;
	int num6 = num5 = num4;
	// ISSUE: explicit reference operation
	(^local).right = num5;
	int num7 = num6;
	// ISSUE: explicit reference operation
	(^local).left = num7;
	CreateParams createParams = this.CreateParams;
	SafeNativeMethods.AdjustWindowRectEx(ref lpRect, createParams.Style, false, createParams.ExStyle);
	this.clientWidth = this.width - (lpRect.right - lpRect.left);
	this.clientHeight = this.height - (lpRect.bottom - lpRect.top);
  }
  if (!autoInstallSyncContext)
	return;
  WindowsFormsSynchronizationContext.InstallIfNeeded();
}

Most of this is not interesting, however, parameter’s name is very suspicious: autoInstallSyncContext. Last thing of this function is:

if (!autoInstallSyncContext)
  return;
WindowsFormsSynchronizationContext.InstallIfNeeded();

Yes, got it. This class installs synchronization context. Let’s see it:

internal static void InstallIfNeeded()
{
  if (!WindowsFormsSynchronizationContext.AutoInstall || WindowsFormsSynchronizationContext.inSyncContextInstallation)
	return;
  if (SynchronizationContext.Current == null)
	WindowsFormsSynchronizationContext.previousSyncContext = (SynchronizationContext) null;
  if (WindowsFormsSynchronizationContext.previousSyncContext != null)
	return;
  WindowsFormsSynchronizationContext.inSyncContextInstallation = true;
  try
  {
	SynchronizationContext synchronizationContext = AsyncOperationManager.SynchronizationContext;
	if (synchronizationContext != null && !(synchronizationContext.GetType() == typeof (SynchronizationContext)))
	  return;
	WindowsFormsSynchronizationContext.previousSyncContext = synchronizationContext;
	new PermissionSet(PermissionState.Unrestricted).Assert();
	try
	{
	  AsyncOperationManager.SynchronizationContext = (SynchronizationContext) new WindowsFormsSynchronizationContext();
	}
	finally
	{
	  CodeAccessPermission.RevertAssert();
	}
  }
  finally
  {
	WindowsFormsSynchronizationContext.inSyncContextInstallation = false;
  }
}

And we can see that it indeed replaces synchronization context with different one. We have our culprit!

Solution

What can we do? Well, we can hack it in the following way:

var context = SynchronizationContext.Current;
new Form();
SynchronizationContext.SetSynchronizationContext(context);

So we store existing context, create problematic instance, and restore the context. After this change in test everything works fine.

However… It is better to simply not test UI (or at least use interfaces or form provider).

]]>
https://blog.adamfurmanek.pl/2016/10/08/async-wandering-part-1/feed/ 7