1

I've added a splash-screen form to a C# WinForms application to display while the application is being initialized/checking for updates. I'm using Squirrel.Windows to check for updates in Program.cs.

After adding the splash-screen, a call to Task.WaitAll in Main() never returns. This call worked as I expected before adding the splash-screen.

What can I do to ensure that the task completes in Main() while the splash-screen is displayed in the foreground?

Working example:

static void Main()
    {
        try
        {
            using (var mgr = new UpdateManager("xxxx"))
            {
                var task = mgr.UpdateApp();
                task.RunSynchronously();
                Task.WaitAll(task);
                Console.WriteLine(task.Status);
            }
        }
        catch (Exception ex)
        {
            logger.Debug(ex.Message);
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new XForm());
    }

Non-working example:

static void Main()
    {
        var ss = new SplashScreen();
        Application.Run(ss);
        try
        {
            using (var mgr = new UpdateManager("xxxx"))
            {
                var task = mgr.UpdateApp();
                task.RunSynchronously();
                Task.WaitAll(task);
                Console.WriteLine(task.Status);
            }
        }
        catch (Exception ex)
        {
            logger.Debug(ex.Message);
        }
        ss.Close(); 
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new XForm());
    }

I've read a bunch of SO posts describing lock-up on Task.WaitAll, but I can't find a direct explanation of the phenomena I'm seeing here i.e.
Synchronously waiting for an async operation, and why does Wait() freeze the program here

How would I run an async Task<T> method synchronously?

I did try the suggestion of calling task.RunSynchronously() but it seemed to make no difference.

afarley
  • 781
  • 6
  • 26
  • `Application.Run` is a blocking call, so it won't continue into the `try` until the `ss` form closes. If you are planning on doing something like this, I would put the update code inside the `ss` form, not in the `Main` method. Really you should avoid having two `Application.Run` calls, because they set up message loops and threads. – Ron Beyer May 09 '18 at 01:20

1 Answers1

0

You can solve this problem using one of two approaches.

Change to C# 7.1 and make your main method ASYNC Right click project > Build > Advanced > C# latest Minor Version

static async Task Main()
{
    try
    {
        using (var mgr = new UpdateManager("xxxx"))
        {
            await mgr.UpdateApp();
        }
    }
    catch (Exception ex)
    {
        logger.Debug(ex.Message);
    }

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new XForm());
}

Or

If UpdateApp returns a value

use .Result

If UpdateApp does not return a value

use .Wait()

static void Main()
{
    try
    {
        using (var mgr = new UpdateManager("xxxx"))
        {           
            mgr.UpdateApp().Wait();             
        }
    }
    catch (Exception ex)
    {
        logger.Debug(ex.Message);
    }

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new XForm());
}
Pang
  • 9,564
  • 146
  • 81
  • 122
alacom
  • 236
  • 1
  • 7