C # .NET 2.0 WinForm 응용 프로그램 개발. 응용 프로그램을 닫고 자체적으로 다시 시작해야합니다.
Application.Restart();
위의 방법은 신뢰할 수없는 것으로 입증되었습니다 .
응용 프로그램을 다시 시작하는 더 좋은 방법은 무엇입니까?
C # .NET 2.0 WinForm 응용 프로그램 개발. 응용 프로그램을 닫고 자체적으로 다시 시작해야합니다.
Application.Restart();
위의 방법은 신뢰할 수없는 것으로 입증되었습니다 .
응용 프로그램을 다시 시작하는 더 좋은 방법은 무엇입니까?
답변:
불행히도 Process.Start ()를 사용하여 현재 실행중인 프로세스의 인스턴스를 시작할 수 없습니다. Process.Start () 문서에 따르면 "프로세스가 이미 실행 중이면 추가 프로세스 리소스가 시작되지 않습니다 ..."
이 기술은 VS 디버거에서 잘 작동하지만 (VS는 Process.Start가 프로세스가 아직 실행 중이 아니라고 생각하게하는 일종의 마법을 수행하기 때문에) 디버거에서 실행되지 않으면 실패합니다. (이것은 OS에 따라 다를 수 있습니다. 일부 테스트에서는 XP 또는 Vista에서 작동했지만 디버거에서 실행 한 것을 기억하고있을 수 있습니다.)
이 기술은 제가 현재 작업하고있는 프로젝트의 마지막 프로그래머가 사용한 것과 정확히 일치하며 꽤 오랫동안 이에 대한 해결 방법을 찾으려고 노력해 왔습니다. 지금까지 한 가지 해결책 만 찾았는데, 그저 더럽고 칙칙한 느낌이 듭니다. 첫 번째 애플리케이션이 종료 될 때까지 백그라운드에서 대기하는 두 번째 애플리케이션을 시작한 다음 첫 번째 애플리케이션을 다시 시작합니다. 나는 그것이 작동 할 것이라고 확신하지만, 쉿.
편집 : 두 번째 응용 프로그램을 사용하면 작동합니다. 두 번째 앱에서 제가 한 것은 다음과 같습니다.
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, "");
}
(이것은 매우 간단한 예제입니다. 실제 코드에는 온 전성 검사, 오류 처리 등이 많이 있습니다.)
Process.Start않습니다. 실행중인 OS 프로세스 목록을 보지 않습니다. 이 문서 문 은 클래스 의 해당 객체 인스턴스 에 대해서만 설명합니다 Process. Process클래스는 실행중인 프로세스에 첨부 할 수 있지만 또한 시작하지 않은 상태가 될 수 있습니다. 제 생각에는 이것은 디자인이 망가진 것입니다. 모범 사례 인 IMO는 Process 인스턴스를 재사용하지 않고 생성 후 즉시 시작하는 것입니다. 이상적으로는 정적 Process.Start방법을 사용하십시오 . 그러면이 문서 및 디자인 결함이 작동하지 않습니다.
WaitForExit(1000). 그러나 새로운 프로세스를 시작하기 위해 전체 대기가 필요하지는 않습니다. 원하는 추가 동작 일 수 있지만 새 프로세스를 시작할 필요는 없습니다.
나를 위해 일한 훨씬 간단한 접근 방식은 다음과 같습니다.
Application.Restart();
Environment.Exit(0);
이렇게하면 명령 줄 인수가 유지되고 일반적으로 응용 프로그램이 닫히지 않도록하는 이벤트 처리기가 있더라도 작동합니다.
Restart () 호출은 종료를 시도하고 어쨌든 새 인스턴스를 시작하고 반환합니다. 그런 다음 Exit () 호출은 이벤트 처리기에 실행할 기회를주지 않고 프로세스를 종료합니다. 두 프로세스가 모두 실행되는 매우 짧은 기간이 있습니다. 제 경우에는 문제가되지 않지만 다른 경우에는 가능합니다.
종료 코드 0 입력은 Environment.Exit(0);완전 종료 를 지정합니다. 1로 종료하여 오류가 발생했음을 지정할 수도 있습니다.
OnClose()양식 이벤트 및 유사 항목을 발생 시키지 않습니다 .
메인 앱 형태라면 사용 해보세요
System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app
Enviorment.Exit(0)도 그 일을 할 것입니다.
Enviorment.Exit응용 프로그램 정리 코드가 실행되는 것을 방지하기 때문에 더럽고 침략적인 종료입니다. 대부분의 경우 올바른 선택이 아닙니다.
나는 파티에 늦을 수도 있지만 여기에 내 간단한 해결책이 있으며 내가 가진 모든 응용 프로그램에서 매력처럼 작동합니다.
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
{ }
저도 똑같은 문제를 겪었고 중복 인스턴스를 방지해야한다는 요구 사항도있었습니다. 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
}
}
나는 내가 가지고있는 모든 안전 점검 등을 분명히 보여주지 않고있다.
이상적이지 않더라도-나는 이것이 유효한 대안이라고 생각하므로 다시 시작을 처리하기 위해 별도의 앱을 배치 할 필요가 없습니다.
/allowMultipleInstances이상한 깃발보다 깃발 을 '찾는'것을 선호합니다 /restart.
// 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 ();보다 잘 작동하는 것 같습니다.
프로그램이 다중 인스턴스로부터 보호하는 경우 이것이 어떻게 처리되는지 확실하지 않습니다. 제 생각에는 두 번째 .exe를 실행하는 것이 더 나을 것입니다.
간단합니다 Application.Restart(). 다시 시작하기 위해 응용 프로그램을 호출하는 경향이 있는 메서드를 호출하면됩니다. 그러나 오류 코드를 사용하여 로컬 환경을 종료해야합니다.
Application.Restart();
Environment.exit(int errorcode);
효율적으로 사용할 수 있도록 오류 코드 열거를 만들 수 있습니다.
또 다른 방법은 응용 프로그램을 종료하고 실행 경로가있는 프로세스를 시작하는 것입니다.
Application.exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);
이 코드를 시도하십시오.
bool appNotRestarted = true;
이 코드는 함수에 있어야합니다.
if (appNotRestarted == true) {
appNotRestarted = false;
Application.Restart();
Application.ExitThread();
}
나는 또 다른 해결책을 찾았다. 아마도 누구나 그것을 사용할 수있을 것이다.
string batchContent = "/c \"@ECHO OFF & timeout /t 6 > nul & start \"\" \"$[APPPATH]$\" & exit\"";
batchContent = batchContent.Replace("$[APPPATH]$", Application.ExecutablePath);
Process.Start("cmd", batchContent);
Application.Exit();
코드가 단순화되었으므로 예외 및 항목을 처리하십시오.)
이전 애플리케이션이 종료 된 후 새 애플리케이션이 시작되기를 원했습니다.
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 );
}
Restarter 를 사용할 수도 있습니다 .
Restarter는 충돌하거나 중단 된 프로그램 및 응용 프로그램을 자동으로 모니터링하고 다시 시작하는 응용 프로그램입니다. 원래 게임 서버를 모니터링하고 다시 시작하기 위해 개발되었지만 모든 콘솔 또는 양식 기반 프로그램 또는 응용 프로그램에 대한 작업을 수행합니다.
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 절에 배치 할 수 있습니다.
bat 파일을 만들고 닫기 전에 배치 파일을 실행 한 다음 현재 인스턴스를 닫는 방법은 어떻습니까?
배치 파일은 다음을 수행합니다.
여기 내 2 센트입니다.
새 인스턴스 시작-> 현재 인스턴스 닫기 시퀀스는 여러 복사본을 동시에 실행하는 것을 허용하지 않는 응용 프로그램에서도 작동해야합니다.이 경우 새 인스턴스에 다시 시작이 진행 중임을 나타내는 명령 줄 인수를 전달할 수 있습니다 따라서 실행중인 다른 인스턴스를 확인할 필요가 없습니다. 두 인스턴스가 병렬로 실행되지 않는 것이 절대적으로 필수적인 경우 첫 번째 인스턴스가 실제로 구현을 완료 할 때까지 기다립니다.
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;
}
}
}
비슷한 문제가 있었지만 24/7 실행해야하는 앱에서는 찾을 수없는 관리 할 수없는 메모리 누수와 관련이있었습니다. 고객과 함께 메모리 사용량이 정의 된 값을 초과하면 앱을 다시 시작할 수있는 안전한 시간이 오전 3 시라는 데 동의했습니다.
시도 Application.Restart했지만 이미 실행중인 동안 새 인스턴스를 시작하는 메커니즘을 사용하는 것 같기 때문에 다른 계획을 시도했습니다. 나는 파일 시스템이 그들을 생성 한 프로세스가 죽을 때까지 처리하는 트릭을 사용했다. 그래서 응용 프로그램에서 파일을 디스크 Dispose()에 놓았고 핸들 이 없었 습니다. 파일을 사용하여 '내 자신'실행 파일과 시작 디렉터리도 전송했습니다 (유연성을 추가하기 위해).
암호:
_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);
}
}
나는 다음을 사용하고 정확히 원하는 것을 수행합니다.
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);
}
로그 아웃으로 사용하려면 Ram Cache에서 모든 앱을 종료해야하므로 먼저 애플리케이션을 닫은 다음 다시 실행해야합니다.
// 로그 아웃 버튼 클릭시
foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
{
frm.Close();
}
System.Diagnostics.Process.Start(Application.ExecutablePath);
Application.Restart () 사용의 문제는 새 프로세스를 시작하지만 "이전"프로세스가 여전히 남아 있다는 것입니다. 따라서 다음 코드 스 니펫을 사용하여 이전 프로세스를 종료하기로 결정했습니다.
if(Condition){
Application.Restart();
Process.GetCurrentProcess().Kill();
}
그리고 그것은 잘 작동합니다. 제 경우에는 MATLAB과 C # 응용 프로그램이 동일한 SQLite 데이터베이스를 공유하고 있습니다. MATLAB이 데이터베이스를 사용하는 경우 MATLAB이 데이터베이스에서 사용중인 비트를 재설정 할 때까지 Form-App을 다시 시작해야합니다 (+ 카운트 다운). (부수 정보 만)