C#WinFormアプリケーションを再起動するにはどうすればよいですか?


86

C#.NET 2.0WinFormアプリケーションの開発。アプリケーションを閉じて再起動する必要があります。

Application.Restart();

上記の方法は信頼性が低いこと証明されています

アプリケーションを再起動するためのより良い方法は何ですか?


3
アプリを再起動する必要があるかどうか知りたいです。私は前にその必要性について考えたことがありませんあなたの状況は何ですか?
JeffH 2009

私たちの特定の状況-ループでいくつかの画像とフラッシュコンテンツを実行することになっているメディアプレーヤーアプリケーション。マシンを再起動せずに何日も実行する必要があり、キーボード/マウスがないため、ユーザーの操作はありません。プログラムがクラッシュした場合(未処理の例外)、プログラムを再起動する必要があります。終了したり、エラーを表示したりしないでください。 stackoverflow.com/questions/773768/… プログラムが防止できない例外を抱え続ける理由については、こちらをご覧ください。:(
Adam Nofsinger 2009

1
結局、私たちのアプリケーションのはるかに優れたソリューションは、メインアプリケーションから開始される(まだ実行されていない場合)小さなウォッチドッグアプリケーションを開発することでした。ウォッチドッグは、10秒ごとにチェックして、メインアプリケーションでまだプロセスが実行されているかどうかを確認し、実行されていない場合はプロセスを開始します。シンプルでエレガント、そしてメインアプリから再起動しようとするよりもはるかに頑丈です。
Adam Nofsinger 2011

2
再起動のもう1つの理由は、言語を変更したとき、または更新をダウンロードしたときです。
Andrew Truckle 2016年

1
しかし、もし...ウォッチドッグアプリケーションがクラッシュした場合はどうなりますか?
換喩2017年

回答:


40

残念ながら、Process.Start()を使用して現在実行中のプロセスのインスタンスを開始することはできません。Process.Start()のドキュメントによると、「プロセスがすでに実行されている場合、追加のプロセスリソースは開始されません...」

この手法は、VSデバッガーでは正常に機能しますが(VSはProcess.Startがプロセスをまだ実行していないと見なす何らかの魔法を実行するため)、デバッガーで実行しないと失敗します。(これはOS固有である可能性があることに注意してください。一部のテストでは、XPまたはVistaで動作したことを覚えているようですが、デバッガーで実行したことを覚えているだけかもしれません。)

この手法は、私が現在取り組んでいるプロジェクトの最後のプログラマーが使用した手法とまったく同じであり、かなり前からこの回避策を見つけようとしています。これまでのところ、解決策は1つしか見つかりませんでしたが、2番目のアプリケーションを起動し、最初のアプリケーションが終了するのをバックグラウンドで待機してから、最初のアプリケーションを再起動します。私はそれがうまくいくと確信しています、しかし、うん。

編集:2番目のアプリケーションの使用は機能します。2番目のアプリで行ったのは次のとおりです。

    static void RestartApp(int pid, string applicationName )
    {
        // Wait for the process to terminate
        Process process = null;
        try
        {
            process = Process.GetProcessById(pid);
            process.WaitForExit(1000);
        }
        catch (ArgumentException ex)
        {
            // ArgumentException to indicate that the 
            // process doesn't exist?   LAME!!
        }
        Process.Start(applicationName, "");
    }

(これは非常に単純化された例です。実際のコードには、多くのサニティチェック、エラー処理などがあります)


私はHiredMindに同意します。実際、答えを書いた直後に、同じ「ウォッチドッグプログラム」の実装を自分で行いました。申し訳ありませんが、ここに戻って更新する必要があります。私はそれがあまりにもひどく醜い/不機嫌/汚いと感じるべきではないと思います。ウォッチドッグプログラムパターンはかなり広く使用されています。
Adam Nofsinger 2009

実際にはディスク上に2番目のアプリケーションは必要ありません...スクリプトを使用して、一時的な名前でその場で生成できます...これにより、再起動のために2番目のアプリケーションを使用することに対する罪悪感が軽減されると思います。あなた自身の...それともでした「EMIT」全体C#アプリケーションは、それをコンパイルし、それをディスクに保存して(汚い、汚れた思考)それを実行...
Loudenvier

最初の段落は正しくありProcess.Startません:実行中のOSプロセスのリストを見ていません。このドキュメントステートメントでは、クラスのそのオブジェクトインスタンスについてのみ説明していますProcessProcessクラスは、実行中のプロセスに取り付けることができるが、それはまた、未開始状態にすることができます。私の意見では、これは設計の失敗です。ベストプラクティスであるIMOは、Process インスタンスを再利用 せず、作成後すぐに開始することです。理想的には、静的Process.Startメソッドを使用します 。そうすると、このドキュメントと設計上の欠陥が発生することはありません。
usr

ここに示されているコードも、のために信頼性がありませんWaitForExit(1000)。ただし、新しいプロセスを開始するために待機全体が必要なわけではありません。追加の動作が必要な場合もありますが、新しいプロセスを開始する必要はありません。
usr

今はわかりませんが、9年前(ええと)これは間違いなく正しかったです。:-)
HiredMind 2017

74

私のために働いたはるかに簡単なアプローチは次のとおりです。

Application.Restart();
Environment.Exit(0);

これにより、コマンドライン引数が保持され、通常はアプリケーションを閉じることができないイベントハンドラーにもかかわらず機能します。

restart()呼び出しは終了を試み、とにかく新しいインスタンスを開始して戻ります。その後、Exit()呼び出しは、イベントハンドラーに実行の機会を与えずにプロセスを終了します。両方のプロセスが実行されている期間は非常に短いので、私の場合は問題ありませんが、他の場合は問題になる可能性があります。

の終了コード0はEnvironment.Exit(0);、クリーンシャットダウンを指定します。1で終了して、発生したエラーを指定することもできます。


シンプルでありながら信頼性があります。これは受け入れられた答えでなければなりません。すべてのグローバル変数を空にして、アプリケーションが起動したばかりのように見えるサインアウト機能を実装しようとしていました。ログイン用のパネルを表示し、DBからの重要な情報を保持するすべてのグローバル変数をゼロにリセットするだけでした。これにより、生活がずっとシンプルになりました。ありがとう!
DavidG 2017

System.Windows.Forms.Application.Restart()は、WPFアプリケーションでも機能します。Windows 10OSでテスト済み。
nthDeveloper 2018年

わぁぁぁぁぁぁぁ!あなたはキッディン...そうですか?C#<3。これはデフォルトではOnClose()フォームイベントなどを発生させないことに注意してください。
F8ER

56

メインアプリのフォームを使用している場合は、

System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app

7
似ていますが、違います。Application.Exitは私からは機能せず、this.Close()がその役割を果たしました。
ダーカー2010

1
5月Enviorment.Exit(0)もその仕事をします。
dwza 2017

2
Enviorment.Exitこれは、アプリケーションのクリーンアップコードの実行を妨げるため、ダーティで非常に侵襲的な出口です。ほとんどの場合、正しい選択ではありません。
usr 2017

16

私はパーティーに遅れるかもしれませんが、これが私の簡単な解決策であり、私が持っているすべてのアプリケーションで魅力のように機能します:

        try
        {
            //run the program again and close this one
            Process.Start(Application.StartupPath + "\\blabla.exe"); 
            //or you can use Application.ExecutablePath

            //close this one
            Process.GetCurrentProcess().Kill();
        }
        catch
        { }

Win-7-x64およびWin-XP-x32で非常にうまく機能します。ドキュメントに制約については何も表示されません。これは受け入れられた答えでなければなりません。
ビターブルー2014

@Bitterblue投稿したドキュメントへのリンクには、「プロセスがすでに実行されている場合、追加のプロセスリソースは開始されていません」と記載されています。備考欄の3行目です。そうでなければいいのですが、そうです。
HiredMind 2015年

@HiredMind「制約」が私たち一人一人にとって何を意味するのかについて議論できると思います。ただし、このセクションのタイトルは「制約」ではなく「備考」です。だから私はそれと一緒に暮らすことができます。そして、なぜあなたそれがこのようでなかったらいいのに?それで何か問題がありましたか?私がしなかったので。私にとっては完璧に機能します。
ビターブルー2015年

@HiredMindこれは個人的なことでも何でもありませんが、C#アプリを再起動するためだけに2番目のアプリまたはスクリプトを使用するという考えは私には忌み嫌われます。Win7は、これまでのところ、リリースモードでこのメソッドを問題なく実行しています(ユーザーが言語を変更したときにアプリを再起動するために使用しています=重要ではありません)。そのため、自分で承認していない方法を使用するよりも、手動でアプリを再起動するようにユーザーに指示したいと思います。私は過去にスクリプトを使用したことがありますが、まったく気に入らなかったのです。
ビターブルー2015年

@BitterBlue私は、2番目のアプリを使用するのは面倒だということに同意します-私は答えの中でそう言いました。しかし、デバッガーの外部で単一アプリの方法を試しましたか?この回答を残したとき、Windowsの一部のバージョンでは機能せず、リリースモードまたはデバッグモードはそれとは何の関係もありませんでした。それがあなたのために働くなら、素晴らしいです!しかし、私はこの問題に噛まれ、何百人もの怒っているユーザーがいました。
HiredMind 2015年

13

私もまったく同じ問題を抱えており、インスタンスの重複を防ぐ必要がありました。HiredMindが提案しているソリューションの代替ソリューションを提案します(これは正常に機能します)。

私が行っているのは、古いプロセス(再起動をトリガーするプロセス)のprocessIdをcmd行引数として使用して新しいプロセスを開始することです。

// Shut down the current app instance.
Application.Exit();

// Restart the app passing "/restart [processId]" as cmd line args
Process.Start(Application.ExecutablePath, "/restart" + Process.GetCurrentProcess().Id);

次に、新しいアプリが起動したら、最初にcm行の引数を解析し、processIdで再起動フラグが存在するかどうかを確認してから、そのプロセスが終了するのを待ちます。

if (_isRestart)
{
   try
   {
      // get old process and wait UP TO 5 secs then give up!
      Process oldProcess = Process.GetProcessById(_restartProcessId);
      oldProcess.WaitForExit(5000);
   }
   catch (Exception ex)
   { 
      // the process did not exist - probably already closed!
      //TODO: --> LOG
   }
}

私は明らかに、私が実施しているすべての安全チェックなどを示していません。

理想的ではない場合でも、これは有効な代替手段であるため、再起動を処理するためだけに別のアプリを配置する必要はありません。


1
これにはきちんとした解決策があると私見。また、単一のインスタンスを持ち、ユーザーがアプリケーションを再起動できるようにする必要があります(たとえば、クラッシュしたとき)。私はあなたのソリューションをほぼ実装しましたが複数のインスタンスを実行できるようにする別のコマンドライン引数を追加する方がよいと思いました。
デニス

うーん、あなたは論理を逆転させています-私はそれが好きです!唯一の問題は、誰かが複数のインスタンスを許可するcmd行の引数を
見つけた

さて、ユーザーが要望していた機能だったので、WIN-WINでした。私は彼ら/allowMultipleInstancesがかなり奇妙な/restartものよりも旗を「見つける」ことを望みます。
デニス

ええ、確かにより良い解決策である複数のインスタンスを許可する場合:)
JohnIdol 2011年

@JohnIdolニース。フラグを「-waitForProcessToExit」などに変更すると思いますが、それ以外の場合は、より洗練されたソリューションです。現在、あるEXEを別のEXEから参照する際のClickOnceの問題に取り組んでいますが、これで解決します。
HiredMind 2015年

6

開始/終了メソッド

// Get the parameters/arguments passed to program if any
string arguments = string.Empty;
string[] args = Environment.GetCommandLineArgs();
for (int i = 1; i < args.Length; i++) // args[0] is always exe path/filename
    arguments += args[i] + " ";

// Restart current application, with same arguments/parameters
Application.Exit();
System.Diagnostics.Process.Start(Application.ExecutablePath, arguments);

これは、Application.Restart()よりもうまく機能するようです。

プログラムが複数のインスタンスから保護されている場合、これがどのように処理されるかわからない。私の推測では、メインアプリケーションを一時停止してから起動する2番目の.exeを起動したほうがよいでしょう。


2
アプリケーションが複数のインスタンスから保護されている場合、これは機能しない可能性があります。
majkinetor 2009

ええ、Application.Exit()を呼び出すと、ポンプする必要のあるメッセージがキューに追加されるだけなので、私の回答の2番目のコードはおそらく実際には機能しません。
Adam Nofsinger 2009

残念ながら、この手法は機能しません(機能したいのですが、私のソリューションよりもはるかに簡単です)。Visual Studioデバッガー内で機能しますが、実際には機能しません。デバッガーの外部で機能する厄介なソリューションについては、私の答えを参照してください。
HiredMind 2009

HiredMindは正しいかもしれません。結局、ウォッチドッグパターンソリューションを使用することになりました。
Adam Nofsinger 2010

6

そのシンプルさは、Application.Restart()再起動するためにアプリケーションを呼び出す傾向があるメソッドを呼び出す必要があるだけです。ただし、エラーコードを使用してローカル環境を終了する必要があります。

Application.Restart();
Environment.exit(int errorcode);

エラーコードの列挙を作成して、効率的に使用することができます。
もう1つの方法は、アプリケーションを終了して、実行可能パスを持つプロセスを開始することです。

Application.exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);

私にとってはうまくいきました。私の場合はウォッチドッグアプリは必要ありません。
user685590 2013年

3

このコードを試してください:

bool appNotRestarted = true;

このコードは、次の関数にも含まれている必要があります。

if (appNotRestarted == true) {
    appNotRestarted = false;
    Application.Restart();
    Application.ExitThread();
}

3

私は別の解決策を考え出しました、おそらく誰でもそれを使うことができます。

string batchContent = "/c \"@ECHO OFF & timeout /t 6 > nul & start \"\" \"$[APPPATH]$\" & exit\"";
batchContent = batchContent.Replace("$[APPPATH]$", Application.ExecutablePath);
Process.Start("cmd", batchContent);
Application.Exit();

コードは単純化されているので、例外などに注意してください;)


2

現在実行中のインスタンスに渡されたコマンドラインオプション/パラメータを忘れています。それらを渡さない場合は、実際の再起動を行っていません。Process.StartInfoプロセスのパラメータのクローンを使用してを設定してから、開始します。

たとえば、プロセスがとして開始されたmyexe -f -nosplash myfile.txt場合、メソッドはmyexeこれらすべてのフラグとパラメーターなしでのみ実行されます。


2

古いアプリケーションがシャットダウンした後、新しいアプリケーションを起動したかったのです。

process.WaitForExit()を使用して、独自のプロセスがシャットダウンするのを待つことは意味がありません。常にタイムアウトします。

したがって、私のアプローチは、Application.Exit()を使用して待機することですが、一定期間、イベントの処理を許可します。次に、古いものと同じ引数を使用して新しいアプリケーションを起動します。

static void restartApp() {
    string commandLineArgs = getCommandLineArgs();
    string exePath = Application.ExecutablePath;
    try {
        Application.Exit();
        wait_allowingEvents( 1000 );
    } catch( ArgumentException ex ) {
        throw;
    }
    Process.Start( exePath, commandLineArgs );
}

static string getCommandLineArgs() {
    Queue<string> args = new Queue<string>( Environment.GetCommandLineArgs() );
    args.Dequeue(); // args[0] is always exe path/filename
    return string.Join( " ", args.ToArray() );
}

static void wait_allowingEvents( int durationMS ) {
    DateTime start = DateTime.Now;
    do {
        Application.DoEvents();
    } while( start.Subtract( DateTime.Now ).TotalMilliseconds > durationMS );
}

2

リスタータを使用することもできます。

リスタータは、クラッシュまたはハングしたプログラムやアプリケーションを自動的に監視して再起動するアプリケーションです。もともとはゲームサーバーを監視して再起動するために開発されましたが、コンソールまたはフォームベースのプログラムやアプリケーションで機能します


1
提供されたリンクは機能しなくなりましたが、これはCNET上の同じアプリケーションだと思います:download.cnet.com/Restarter/3000-2094_4-75810552.html
Surfbutler 2015年

2
public static void appReloader()
    {
        //Start a new instance of the current program
        Process.Start(Application.ExecutablePath);

        //close the current application process
        Process.GetCurrentProcess().Kill();
    }

Application.ExecutablePathは、アプリケーションの.exeファイルパスを返します。呼び出しの順序に従ってください。try-catch句に配置することをお勧めします。


1

batファイルを作成し、閉じる前にバッチファイルを実行してから、現在のインスタンスを閉じてはどうでしょうか。

バッチファイルはこれを行います:

  1. ループで待機して、プロセスが終了したかどうかを確認します。
  2. プロセスを開始します。

これは貧乏人のウォッチドッグアプリケーションであり、これについてはもう少し詳しく説明します。実際のウォッチドッグアプリケーションの主な利点は、元のアプリが何かをスピンオフできずに停止した場合でも処理できることです。
Adam Nofsinger 2011

@AdamNofsinger私は今見ています。私はそのコメントを逃した。使用しているソリューションを使用して投稿を編集することをお勧めします。
AZ。

1

これが私の2セントです:

Start New Instance-> Close Current Instanceのシーケンスは、複数のコピーを同時に実行することを許可しないアプリケーションでも機能するはずです。この場合、新しいインスタンスにコマンドライン引数が渡され、再起動が進行中であることを示します。したがって、実行中の他のインスタンスをチェックする必要はありません。2つのインスタンスが並行して実行されていないことが絶対に必要な場合は、最初のインスタンスが実際に終了するのを待つことも実装されます。


1

Application.Restart()を使用する際の問題は、新しいプロセスを開始するが、「古い」プロセスがまだ残っていることです。そのため、次のコードスニペットを使用して古いプロセスを強制終了することにしました。

            if(Condition){
            Application.Restart();
            Process.GetCurrentProcess().Kill();
            }

そして、それは適切に機能します。私の場合、MATLABとC#アプリケーションは同じSQLiteデータベースを共有しています。MATLABがデータベースを使用している場合、MATLABがデータベースのビジービットをリセットするまで、Form-Appは再起動(+カウントダウン)する必要があります。(サイド情報のためだけに)


1

Processを使用してアプリケーション全体を再起動すると、問題に間違った方法でアプローチするのではないかと心配しています。

より簡単な方法は、Program.csファイルを変更して再起動することです。

    static bool restart = true; // A variable that is accessible from program
    static int restartCount = 0; // Count the number of restarts
    static int maxRestarts = 3;  // Maximum restarts before quitting the program

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        while (restart && restartCount < maxRestarts)
        {
           restart = false; // if you like.. the program can set it to true again
           restartCount++;  // mark another restart,
                            // if you want to limit the number of restarts
                            // this is useful if your program is crashing on 
                            // startup and cannot close normally as it will avoid
                            // a potential infinite loop

           try {
              Application.Run(new YourMainForm());
           }
           catch {  // Application has crashed
              restart = true;
           }
        }
    }

1
このソリューションを使用すると、アプリケーションをX回再起動してから、アプリケーションを終了して無限ループを回避できることに注意してください。
RooiWillie 2018

@RooiWillieに感謝します。プログラムが正常に終了できない場合に備えて、これを行うためのカウンターを追加しました。
アンドリュー

0

私も同様の問題を抱えていましたが、24時間年中無休で実行する必要のあるアプリでは見つけることができなかった管理不能なメモリリークに関連していました。お客様との間で、メモリ消費量が定義された値を超えた場合、アプリを再起動する安全な時間は午前3時であることに同意しました。

試しましたがApplication.Restart、すでに実行中に新しいインスタンスを起動するメカニズムを使用しているようですので、別のスキームを選びました。私は、ファイルシステムが処理するトリックを使用して、それらを作成したプロセスが停止するまで存続します。そのため、アプリケーションから、ファイルをディスクにドロップしましたがDispose()、ハンドルはありませんでした。このファイルを使用して、「myself」実行可能ファイルと開始ディレクトリも送信しました(柔軟性を高めるため)。

コード:

_restartInProgress = true;
string dropFilename = Path.Combine(Application.StartupPath, "restart.dat");
StreamWriter sw = new StreamWriter(new FileStream(dropFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite));
sw.WriteLine(Application.ExecutablePath);
sw.WriteLine(Application.StartupPath);
sw.Flush();
Process.Start(new ProcessStartInfo
{
    FileName = Path.Combine(Application.StartupPath, "VideoPhill.Restarter.exe"),
    WorkingDirectory = Application.StartupPath,
    Arguments = string.Format("\"{0}\"", dropFilename)
});
Close();

Close()最後にアプリのシャットダウンが開始され、StreamWriterここで使用したファイルハンドルは、プロセスが実際に停止するまで開いたままになります。次に...

restarter.exeが動作します。排他モードでファイルを読み取ろうとし、メインアプリが停止しなくなるまでファイルにアクセスできないようにしてから、メインアプリを起動し、ファイルを削除して存在します。私はそれがもっと簡単になることはできないと思います:

static void Main(string[] args)
{
    string filename = args[0];
    DateTime start = DateTime.Now;
    bool done = false;
    while ((DateTime.Now - start).TotalSeconds < 30 && !done)
    {
        try
        {
            StreamReader sr = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite));
            string[] runData = new string[2];
            runData[0] = sr.ReadLine();
            runData[1] = sr.ReadLine();
            Thread.Sleep(1000);
            Process.Start(new ProcessStartInfo { FileName = runData[0], WorkingDirectory = runData[1] });
            sr.Dispose();
            File.Delete(filename);
            done = true;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Thread.Sleep(1000);
    }
}

0

私は以下を使用し、それはあなたが探しているものを正確に実行します:

ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
UpdateCheckInfo info = null;
info = ad.CheckForDetailedUpdate();
if (info.IsUpdateRequired)
{
    ad.UpdateAsync(); // I like the update dialog
    MessageBox.Show("Application was upgraded and will now restart.");
    Environment.Exit(0);
}

0

ログアウトとして使用するには、RAMキャッシュからすべてのアプリを終了する必要があるため、最初にアプリケーションを閉じてから再実行します

//ログアウトボタンをクリックすると

foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
        {
            frm.Close();
        }
System.Diagnostics.Process.Start(Application.ExecutablePath);

0

コードを関数内に含めることができ、再起動が必要な場合は、関数を呼び出すだけです。


0

たとえば、次のようなアプリケーションを考えてみましょう。

  1. アプリケーションが登録されていない間; (起動時に)アプリケーションは、ユーザーにアプリケーションの登録とログインアカウントの作成を求めるプロンプトを表示する必要があります。

  2. 登録が送信され、ログイン資格情報が作成されると、アプリケーションを再起動し、登録を確認して、挿入された資格情報を使用してログインするようにユーザーに求める必要があります(ユーザーがすべてのアプリケーション機能にアクセスできるようにするため)。

問題: VisualStudioからアプリケーションをビルドして起動する。以下の4つの選択肢のいずれも、必要なタスクを実行できません。

/*
 * Note(s):
 * Take into consideration that the lines bellow don't represent a code block.
 * They are just a representation of possibilities,
 * that can be used to restart the application.
 */

Application.Restart();
Application.Exit();
Environment.Exit(int errorCode);
Process.GetCurrentProcess().Kill();

何が起こるか:登録を作成した後、ログインしてApplication.Restart();を呼び出します。アプリケーションは(奇妙なことに)登録フォームを再度開き、データベース内のデータをスキップします(リソースが「新しい場合はコピー」に設定されている場合でも)。

解決: アプリケーションのバッチビルドは、(私にとって)上記の行のいずれかが実際に期待どおりに機能していることの証明でした。VisualStudioでアプリケーションをビルドして実行するときだけではありません。

そもそも、アプリケーションをバッチビルドしてみます。Visual Studioの外部で実行し、Application.Restart()が実際に期待どおりに機能するかどうかを確認します。

また、このスレッドの件名に関する詳細情報を確認してください: C#WinFormアプリケーションを再起動するにはどうすればよいですか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.