Last active
January 5, 2020 08:42
-
-
Save retran/b57e4db1a173048c2cee49ac6d523fc2 to your computer and use it in GitHub Desktop.
WM_PAINT reentrancy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Windows.Forms; | |
namespace WutExample | |
{ | |
static class Program | |
{ | |
class MyVeryCustomException : Exception { } | |
private static readonly object sync = new object(); | |
static void Throw() | |
{ | |
throw new MyVeryCustomException(); | |
} | |
static void Lock() | |
{ | |
lock (sync) { } | |
} | |
[STAThread] | |
static void Main() | |
{ | |
var mainThreadId = Thread.CurrentThread.ManagedThreadId; | |
bool throwOnPaint = false; | |
var form = new Form(); | |
form.Paint += (sender, args) => | |
{ | |
Debug.Assert(Thread.CurrentThread.ManagedThreadId == mainThreadId); | |
if (throwOnPaint) | |
{ | |
Throw(); | |
} | |
}; | |
var button = new Button { Text = "Click Me" }; | |
button.Click += (sender, args) => | |
{ | |
Task.Run(() => | |
{ | |
Debug.Assert(Thread.CurrentThread.ManagedThreadId != mainThreadId); | |
lock (sync) | |
{ | |
Thread.CurrentThread.Join(500); | |
// Will send WM_PAINT if called from a non-main thread. | |
form.Invalidate(); | |
} | |
}); | |
try | |
{ | |
Debug.Assert(Thread.CurrentThread.ManagedThreadId == mainThreadId); | |
throwOnPaint = true; | |
Thread.CurrentThread.Join(100); | |
Lock(); | |
} | |
finally | |
{ | |
throwOnPaint = false; | |
} | |
}; | |
form.Controls.Add(button); | |
Application.Run(form); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment