C# 程序单一进程化与实现程序重启的冲突问题
思路借鉴
需求描述:
- 程序运行过程中,不能有多个实例运行,进程唯一SingletonProcess
- 程序自己可以重启(重新运行),或者发生网络错误等严重错误时,程序重新启动,回到登录自检前的状态
需求分析:
程序重新启动时,需要先启动一个新的Process,然后再退出当前程序。
这样便与在Program.cs里遇到禁止多重启动的逻辑冲突。代码如下:
Process.Start(Process.GetCurrentProcess().ProcessName + ".exe");
Application.Exit();
解决方案
- 解决方案一:借助另一个程序实现重启功能(具体过程略)
- 解决方案二:重新启动时传递一个参数,用以表示目前需要执行重启逻辑,绕过SingletonProcess判断以此达到重启目的
程序重启函数
public static void RestartProgram()
{
//释放资源
//释放资源
//释放资源
System.Diagnostics.Process.Start(Application.ExecutablePath, "false");
System.Threading.Thread.Sleep(300);
//这里暴力杀死进程,不建议
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
Program.cs
static class Program
{
static readonly CommonLogger.Logger logger = new CommonLogger.Logger(typeof(Program));
public static bool createNew = true;
[STAThread]
static void Main(string[] str)
{
if (str != null && str.Length > 0)
{
if (str[0].Equals("false"))
{
createNew = false;
}
else
{
createNew = true;
}
}
else
{
createNew = true;
}
using (System.Threading.Mutex m = new System.Threading.Mutex(true, Application.ProductName/*,out xxx*/))
{
try
{
if (createNew)
{
Process instance = RunningInstance();
if (instance == null)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmLoading());
}
else
{
HandleRunningInstance(instance);
}
}
else
{
//重启时
//启动新的进程杀掉旧的进程
//并将重启标识复位
createNew = true;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmLoading());
}
}
catch (Exception e)
{
logger.Error("" + e);
}
}
logger.Info("STAThread Main End " + GlobalInfo.MianID);
//单一逻辑时会执行到此处,确保新的进程没有启动,也不存在资源占用的后台进程
Environment.Exit(0);
}
#region 进程唯一
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
private static void HandleRunningInstance(Process instance)
{
// 确保窗口没有被最小化或最大化
// ShowWindowAsync(instance.MainWindowHandle, 4);
ShowWindowAsync(instance.MainWindowHandle, 4);
// 设置真实例程为foreground window
SetForegroundWindow(instance.MainWindowHandle);// 放到最前端
}
private static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
if (process.Id != current.Id)
{
// 确保例程从EXE文件运行
if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
{
return process;
}
}
}
return null;
}
#endregion
}