This is baffling me. When clicking the button in the windows form project, the code below results in 'Exception thrown: 'System.EntryPointNotFoundException' in mscorlib.dll'. I cannot figure out why. The app doesn't crash, and the task (or any amount of tasks) continues just fine, with everything working as it should.
What's going on here?
namespace FormsExperiment
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btn_fire_Click(object sender, EventArgs e)
{
Task.Run(() => "Hello");
}
}
}
Edit: Trying this on another computer, I'm not able to reproduce the bug. I'm going to chalk this up to VS2015 weirdness that seems beyond the scope of stackoverflow. Thanks for the replies all - the code here works, the error just makes no sense.
Related
I'm very confused because I feel like I'm using async/await in a completely typical way here, no different than I've been using it for years, and yet I'm getting the dreaded Control accessed from a thread other than the thread it was created on message all over the place in my application (an old WinForms app I'm trying to breathe new life into).
The project is in .NET Framework 4.8 and I have just converted an old form from using a BackgroundWorker to async/await, and I'm losing the SynchronisationContext after await statements in various places, one example of which is shown below. I replaced the complex chain of async code that actually runs with Task.Delay and the problem still arises. Adding ConfigureAwait(true) or ConfigureAwait(false) to Task.Delay doesn't seem to make any difference, not that I feel I should even need it in this scenario.
Grateful if somebody can point out where I'm going wrong.
private async void ListViewSelectedIndexChanged(object sender, EventArgs e) {
Debug.WriteLine(SynchronizationContext.Current != null); // true
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); // 1
await Task.Delay(100);
Debug.WriteLine(SynchronizationContext.Current != null); // false - why?
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); // 8
// Touching controls here throws error
}
EDIT 1: Okay, I chased the creation of the form upwards, and I've hit the root of the problem though I still don't understand why it's a problem. The problem can be reduced to this:
// MainForm designer:
this.Load += new System.EventHandler(this.MainFormLoad);
// MainForm code-behind:
private async void MainFormLoad(object sender, EventArgs e) {
var form = new BackupManagerForm();
form.Show(); // BackupManagerForm will exhibit the problem
// ... some async stuff including adding dynamic context menus to MainForm
}
The problem can be removed by removing async from the Load handler in MainForm. Now that I know that I can code around it, but I'm curious as to why that damages the SynchronizationContext so far downstream (despite the fact it seems perfectly able to add the context menus I mentioned above to MainForm for example).
EDIT 2: I just tried to reconstruct the problem in a blank WinForms problem and can't reproduce it. Making the Load handler for MainForm non-async definitely does solves the problem, but actually that's annoying because there's a load of async work I really need to do at that point.
As requested, this is how MainForm is instantiated (there's a lot of code removed for brevity here but hopefully nothing significant):
public static class App {
[STAThread]
public static void Main(string[] args) {
var builder = new ContainerBuilder();
IocConfig.RegisterDependencies(builder);
var container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
var bootstrapper = ServiceLocator.Current.GetInstance<IAppBootstrapper>();
bootstrapper.Startup();
}
public class AppBootstrapper : IAppBootstrapper {
private readonly ISettings _settings;
private readonly MainForm _mainForm;
public AppBootstrapper(MainForm mainForm, ISettings settings) {
_mainForm = mainForm;
_settings = settings;
}
public void Startup() {
// Other stuff removed but perhaps these might be relevant?
Application.DoEvents();
_settings.SaveAsync().Wait();
Application.Run(_mainForm);
}
}
EDIT 3: That Application.DoEvents() turns out to be significant. So does instantiating the form with an IoC container. If I either remove the Application.DoEvents() statement or use Application.Run(new MainForm()) the problem disappears. The Application.DoEvents() exists because of a splash screen that is shown before MainForm with splashForm.Show() followed by Application.DoEvents() - when MainForm eventually loads, it hides the splash screen on load.
I've found a good solution to the problem now. This comprehensively solves the problem without any annoying side effects as far as I can tell:
public void Startup() {
var context = SynchronizationContext.Current;
_splashForm.Show();
Application.DoEvents();
...
SynchronizationContext.SetSynchronizationContext(context);
Application.Run(_mainForm);
}
I still don't have a clear understanding of the problem, but it's obviously to do with the fact that the main form is not the first form to create a message loop. What's interesting though is how far down inside the application that manifests as a significant problem. Anyway, I'd be happy to accept an answer from anyone who can explain the phenomenon.
Based on MSDN article following code shouldn't work in Windows Forms application and I'm pretty much certain, that it didn't work in past, but recently I've discovered, that in .NET framework 4.7.02558 it works.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Test()
{
Console.WriteLine("One");
var d = DelayAsync();
Console.WriteLine("Three");
d.Wait();
Console.WriteLine("Five");
}
private async Task DelayAsync()
{
Console.WriteLine("Two");
await Task.Delay(1000);
Console.WriteLine("Four");
}
private void Button1_Click(object sender, EventArgs e)
{
Test();
}
}
Did I miss some a release log, or is something wrong (I mean right from user's perspective)?
Edit: An application should freeze after returning from awaited code because in Windows Forms is used CurrentContextSheduller.
Testing on 4.7.1 I get the following results:
One
Two
Three
Four, and Five never get displayed. It seems to be "not-working as intended" for me, as execution of await Task.Delay(1000); is blocking.
Discovered. The problem was caused by ReSharper Build & Run. For some reason, the build wasn't done and switching from ReSharper Build to Visual Studio build program behaves "correctly".
Latest build was done with .ConfigureAway(false), so that's a root cause of why it worked and shouldn't.
I was working on a software in Visual Studio, writing code in C#, while I noticed something. I can't figure out how to exit the application.
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ExitButton_Click(object sender, EventArgs e)
{
Application.Exit(); // This works, when I run the application and click on the button, it will indeed quit.
}
}
}
So as said, when I click on the button, it will indeed quit the application. However if I place Application.Exit(); somewhere else, it won't work. So if I modify Form1() like this, it won't automatically quit the application:
public Form1()
{
InitializeComponent();
Application.Exit();
}
It would be necessary to quit the application instantly if certain conditions are met, for example if some application files are missing.
I than tried to do the following:
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
closeapp();
}
public void closeapp()
{
Application.Exit();
}
private void ExitButton_Click(object sender, EventArgs e)
{
closeapp();
}
}
}
Now if I run the application, it will not exit automatically, however, if I click on the Exit button, it will quit the application.
So it looks like that if it is not called from a event that happens within the form, it will not close the application.
I have searched online (including Google and StackOverflow) with the keyword "Application.Exit();" not working. They recommended that I use "Environment.Exit();". Now in my testing application, this works, but in the real application that I am working on, when I remove all the code (of course while having a backup), it looks like the following and it still does not work.
namespace Censored
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Environment.Exit(1);
}
}
}
What can possibly be the cause of it not working in one application, but working in another one? Is something corrupted?
You can't apply Application.Exit when the application is being initialized. So, why don't you force to exit the application in the FormLoad if your conditions aren't met;
private void Form1_Load(object sender, EventArgs e)
{
Application.Exit();
}
I think the best thing to do here is not Application.Exit because as you said, you want to quit the application because there are some files missing. If there are indeed some files missing, you should really show a message to the user and then quit. Application.Exit will quit the application silently so the user does not know that some files are missing. Bad UX!
One easy way to show an error message is to throw an exception:
throw new FileNotFoundException(
"Some application files are missing! Please add them in before starting this application!");
The reason why Application.Exit does not work here is because the "Application" has not been created at that point in time. In your Main method, you should have this line:
Application.Run(new Form1());
The "Application" will be created after the above method is called. But before Run is called, what else is called? The form's constructor! It then calls InitializeComponent, where you want to exit the application. At this time Run has not been called yet!
please mind I'm still a beginner:
I am creating a program with windows forms in c#. However, after i had some sync issues the main form loader does not seam to be working. I checked the code with my limited knowledge but i can't seem to find anything wrong?
Here's the code (mainfrm.designer.cs:1):
...
this.Name = "frm_Main";
this.Load += new System.EventHandler(this.frm_Main_Load);
this.menuStrip1.ResumeLayout(false);
...
And here is my loader (mainfrm.cs)
private void frm_Main_Load(object sender, EventArgs e)
{
Everything i do here does not get executed.
}
Does anyone see the problem?
This is indeed a bug within Visual Studio, as mentioned by Hans.
stackoverflow.com/a/4934010/17034
I have developed a program for Windows 7 and it runs on my computer as it should (in release mode). However, when I copy and paste the project folder to my external HDD and try it on a different computer, it 'runs' but nothing really shows up. I will try to post relevant code:
class App : Application
{
[STAThread()]
static void Main()
{
new App();
}
/// <summary>
/// Starts application with splash screen
/// </summary>
public App()
{
StartupUri = new System.Uri("SplashScreen.xaml", UriKind.Relative);
Run();
}
}
Even though this screen is never visible, my MessageBox is shown.
//constructor
public SplashScreen()
{
//generated method
InitializeComponent();
System.Windows.MessageBox.Show("WHY ME??");
mw = new MainWindow();
mw.Show();
}
After the splash screen, the main window should open, but it doesn't AND this MessageBox never shows up.
public MainWindow()
{
//Windows generated
InitializeComponent();
System.Windows.MessageBox.Show("WHY ME??");
}
As I mentioned, the program runs as it is supposed to in both release and debug mode, but then when I bring it to another computer it only shows "WHY ME??" once instead of twice like it should. Any ideas?
Turns out there was a lot wrong with my code. One of the largest problems I had was hard-coded file paths to the computer it was running on. However, what really helped me with all computer-migration related problems was adding the following code to each class:
In Constructor:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Create handling function:
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
System.Windows.MessageBox.Show(e.ExceptionObject.ToString());
}
It is slow and tetious however it does a pretty good job of assisting in locating source of problems. So there was multiple things wrong with my program, but adding the above code helped solve a lot of issues.