سؤال

I have a winforms application that I will be calling through the task scheduler to download files and insert them to a database. However it is unpredictable when the files are available so I have used timer (System.Windws.Forms.Timer) to poll for the files.

 static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            if (args != null && args.Length > 0)
            {

                Form1 f1 = new Form1();
                if (f1.IsLive)
                {
                    f1.OnLaunch(); // tests DB connection and reads and updates the expiry date list.

                    if (args[0] == "FullStats")
                        f1.FullStatsDataPump();
                    else if (args[0] == "OptionsStats")
                    {
                        f1.OptionsStatsTimer_Tick(null, null);
                        f1.OptionsStatsTimer.Start();
                    }
                    else if (args[0] == "OptionsTraded")
                    {
                        f1._optionsTradedTimer_Tick(null, null);
                        f1.OptionsTradedTimer.Start();
                    }
                    else
                    {
                        EmailManager.InvalidInputArgument(args[0]);
                        Application.Exit();
                    }

                    Application.Run();
                }

            }

In the above code snippet, OptionsTradedTimer / OptionsStatsTimer both poll for files and then begin processes that end with Application.Exit(). This runs perfectly but then afterwards it gets stuck in an infinite message loop. I thought that Application.Run() would be called immediately after the first timer ticks and thus when Application.Exit() eventually gets called it would end the message loop. But if I step through the code then after that Application.Exit() the program returns to the timer.tick() where it originated and then continues on to the Application.Run() at the bottom. The Application.Run() at the bottom is necessary as without it the timers will only tick once and then the app will exit.

So how do I correctly tell the application to exit? Or where should I be calling Application.Run()?

هل كانت مفيدة؟

المحلول 3

Can't delete the question so might as well answer it.

The problem only occurs if the timer reaches the Application.Exit() line the first time it runs. (i.e. if the file is available already when the program is run). In this case Application.Exit() is called before Application.Run() where as if the timer doesn't reach the Application.Exit() on its first run (i.e. file is not yet available) then Application.Run() gets called and Application.Exit() only gets called later.

So to solve this I just added a condition in the timers' tick methods to make sure they don't so anything on their first run.

I don't agree with restructuring the program as the way it stands I can run it through the task scheduler to download the files daily without a form and with the polling functionality and I can also run it through VS as a normal winforms app with buttons for testing, debugging and downloading files when something went wrong.

نصائح أخرى

That sounds somewhat weird - perhaps you should simply move the Application.exit to a seperate procedure and just change some boolean variable if you need to exit the program. In your main program you could wait for the boolean to change and then exit the program once. Additionally, you could set the boolean variable to false at the beginning, so that you doesnt need the run.

I don't think you need to use Application.Exit(). Your Main() method is the entry point to the application; when it returns, the application exits. Generally speaking, Application.Run() is used to start up a windows form that runs until closed. Give this code a try - I haven't tested it, but it should do what you want.

using System.Linq;
using System.Threading;

class MyApplication
{
    [STAThread]
    static void Main(string[] args)
    {
        const string ARG_SHOWFORM = "ShowForm";
        const string ARG_STATS = "OptionsStats";
        const string ARG_TRADED = "OptionsTraded";

        if (args.Contains(ARG_SHOWFORM) || args.Length == 0) {
            Application.Run(new Form1());  //This will block until the form is closed.

            //Make sure all your supporting logic is placed into the Form.Loaded event on the form (i.e.
            //get it out of the Main() method).

            return;
        }

        if (args.Contains(ARG_STATS))
            OptionsStatsMethod();

        else if (args.Contains(ARG_TRADED))
            OptionsTradedMethod();

        else
            EmailManager.InvalidInputArgument(args[0]);

    }

    private void OptionsTradedMethod()
    {
        while (true) {
            if (downloadSuccessful) //Use a method here that returns a boolean if the download succeeded.
                break;
            else
                Thread.Sleep(DEFAULT_WAIT_TIME_MS);
        }
    }

    private void OptionsStatsMethod()
    {
        while (true) {
            if (downloadSuccessful)  //Use a method here that returns a boolean if the download succeeded.
                break;
            else
                Thread.Sleep(DEFAULT_WAIT_TIME_MS);
        }
    }
}

To keep your main method running(keep it's thread alive) you can use Thread.Sleep instead of Application.Run(). Try this:

Thread.Sleep(System.Threading.Timeout.Infinite);

and instead of Application.Exit() use:

Process.GetCurrentProcess().Kill();

This way it works, but consider using windows sevices for this.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top