2009-10-30 72 views
0

當我調用Application.Restart()方法時,出現錯誤,檢測應用程序當前是否正在運行。有沒有辦法解決?C# - 重新啓動應用程序與「程序已在運行」錯誤衝突

static void Main(string[] args) 
    { 
     string proc = Process.GetCurrentProcess().ProcessName; 
     Process[] processes = Process.GetProcessesByName(proc); 
     if (processes.Length > 1) 
     { 
      MessageBox.Show("Program is already running.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     } 
     else 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
     } 
    } 
+0

請注意,如果您的用戶重命名該exe文件,他們仍然可以啓動多個副本。 – SLaks 2009-10-30 03:20:38

回答

0

最簡單的方法是在退出前添加延遲。

換句話說,

string proc = Process.GetCurrentProcess().ProcessName; 
if (Process.GetProcessesByName(proc).Length > 1) { 
    Thread.Sleep(500);  //500 milliseconds; you might need to wait longer 
    if (Process.GetProcessesByName(proc).Length > 1) { 
     MessageBox.Show("Program is already running.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     return; 
    } 
} //no else 
+0

爲什麼這會降低投票率? – SLaks 2009-10-30 03:41:29

+0

對不起,但投票與睡眠真的很難看。我不會爲任何目的推薦它。 – 2009-10-30 03:42:43

+0

我沒有說這是最好的;我說這是最簡單的。最好的解決辦法是我的其他答案。 – SLaks 2009-10-30 03:44:27

0

您可以嘗試重啓代碼掛接到Application.ApplicationExit事件作爲一個監聽器方法。然後你會調用Application.Exit來使代碼間接運行。

編輯:添加代碼示例:

例如,當用戶點擊重新啓動按鈕或應用決定重新啓動,調用此RestartMeSmartly()方法。你不必擔心欺騙 - 它會起作用。

void RestartMeSmartly() { 
    Application.ApplicationExit += BeforeExiting; 
    Application.Exit(); 
} 

void BeforeExiting(object sender, EventArgs args) { 
    Application.Restart(); 
} 
+0

實際上,最好在程序執行的最後一個託管代碼'Main'方法結束時重新啓動程序。 (終結者除外)然而,即便如此,這將是非確定性的,我不會推薦它。 – SLaks 2009-10-30 03:27:25

+0

我們如何知道Application.ApplicationExit事件沒有在Main方法的末尾被調用,甚至後來被運行時調用?也許ApplicationExit更好。 – 2009-10-30 03:36:25

+0

在調用Application.Run期間,消息循環退出時調用Application.Exit。 – SLaks 2009-10-30 03:39:38

1

我有一個類似的問題,但我的是無法管理的內存泄漏,我無法找到一個必須全天候運行的應用程序。對於客戶,我同意如果內存消耗超過定義的值,則重新啓動應用程序的安全時間爲上午03:00。

我試過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); 
    } 
}