本帖最后由 Princess 于 2020-11-3 15:49 编辑
前提:一般操作硬件类型的软件,都需要独占硬件,所以这个时候对软件有一个要求就是只能运行一个实例,那么用户如果没有注意到程序已经运行再次去点击呢?如果没有做过防护那么很容易出现各种初始化异常问题,所以这个时候我们会考虑通过加入互斥体来解决该问题:
- bool bFlag;
- Mutex mutex = new Mutex(true, "_Demo1_", out bFlag);
- if (!bFlag)
- {
- //检测到程序已经运行,一般情况下是弹窗提示不能重复运行
- return;
- }
- mutex.ReleaseMutex();;
复制代码
这个是最早的雏形,当然这个问题也解决了,但是却不是很友好!
那么有没有更好的一种方式呢?有的,我们可以迭代进程看看能否找到对应名称的进程,如果找到再将它打开并且显示,是不是就友好多了。
那么我们需要在Progress.cs添加以下内容:
命名空间引用:
- using System.Diagnostics;
- using System.Reflection;
- using System.Runtime.InteropServices;
复制代码
Main函数内部改造:
- Process instance = RunningInstance();
- if (null != instance)
- {
- HandleRunningInstance(instance);
- }
- else
- {
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new Form1());
- }
复制代码
这句代码的意思就是如果找到了进程就直接打开运行中的实例,否则正常开启。
下面是上面实现的核心函数,添加在Main函数下面即可。
- static Process RunningInstance()
- {
- Process current = Process.GetCurrentProcess();
- Process[] processes = Process.GetProcessesByName(current.ProcessName);
- foreach (Process process in processes)
- {
- if (process.Id != current.Id)
- {
- if (Assembly.GetExecutingAssembly().Location.Replace("/ ", "\\ ") == current.MainModule.FileName)
- {
- return process;
- }
- }
- }
- return null;//第一次运行,返回null
- }
- public static void HandleRunningInstance(Process instance)
- {
- ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL); //置窗口为正常状态
- SetForegroundWindow(instance.MainWindowHandle);
- }
- #region 调用系统api
- [DllImport("User32.dll ")]
- private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
- [DllImport("User32.dll ")]
- private static extern bool SetForegroundWindow(IntPtr hWnd);
- private const int WS_SHOWNORMAL = 1;
- #endregion
复制代码
这里要注意,不要调试测试,因为current.ProcessName在调试下的进程是带了虚拟机标识的,比如Demo1.vshost这样的名称,实际运行是没有的。
所以直接编译生成文件,到生成的目录下运行exe两次就可以看到效果。
|