Sfoglia il codice sorgente

限制程序最多只能打开3个

callm 2 giorni fa
parent
commit
7df8aedcfd

+ 17 - 0
UAS_MES_YDCY/.workbuddy/memory/2026-09-22.md

@@ -0,0 +1,17 @@
+# 2026-09-22
+
+## 限制程序最多同时运行三个实例
+- 位置:`Program.cs` 主入口。
+- 新增 `private const int MaxInstanceCount = 3;` + `static bool CheckInstanceLimit()`:
+  `Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName)` 计数(结果**含当前进程**),`count > 3` 时 `MessageBox` 提示「程序最多只能同时运行 3 个,请关闭其它窗口后再打开!」并返回 false。
+- **关键**:检测放在 `if (principal.IsInRole(WindowsBuiltInRole.Administrator))` 分支内部、`Application.Run(new Login())` 之前,
+  而不是 Main 最开头。原因——非管理员启动会走 `else` 分支用 `StartInfo.Verb="runas"` 重启自己(UAC 提权),
+  若在最开头检测,同一次启动会被父/子两个进程各数一次,边界情况下(已有 2 个在跑)子进程会数到 4 而误拦。
+  放在提权后分支里,保证每次真实启动只检测一次。
+- `catch (Exception) { return true; }`:统计进程失败时放行,避免程序完全打不开。
+- 用 `foreach (Process p in processes) p.Dispose();` 释放进程句柄。
+
+### 踩坑:改 Program.cs 时误删 `else`
+- 用 Edit 包裹 if 块时,old_string 里带上了 `else`、new_string 里没带 → `else` 被吃掉,
+  变成 `if(...){...}` 后跟一个裸 `{...}` 块(C# 语法合法能编译,但逻辑错:管理员跑完 Application.Run 后还会再走 runas 分支启动新进程)。
+- 教训:**改动控制流结构后必须立刻 Read 回看**,不要只看「编辑成功」;括起来的块要连 `else`/`else if` 一起核对。

+ 5 - 0
UAS_MES_YDCY/.workbuddy/memory/MEMORY.md

@@ -4,6 +4,11 @@
 - WinForms,.NET Framework,老式 csproj + packages.config;数据库为 Oracle。
 - 主程序集输出名 `UAS_MES_NEW.exe`(在 `bin/Debug/`)。
 
+## 启动入口(Program.cs)
+- `Main` 用 `WindowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator)` 判断:是管理员 → `Application.Run(new Login())`;否则用 `StartInfo.Verb="runas"` 重启自己走 UAC。
+- **实例数限制**:`MaxInstanceCount = 3` + `CheckInstanceLimit()`(按 `Process.GetProcessesByName` 计数,含自身),
+  检测**必须放在管理员分支内、Application.Run 之前**——否则 UAC 提权会让一次启动被数两次而误拦。
+
 ## 新增一个功能界面(标准步骤)
 1. 在 `FunctionCode/<模块>/` 下建 3 个文件:`Xxx.cs`、`Xxx.Designer.cs`、`Xxx.resx`。
    - resx 直接 `cp` 一个现有空模板(如 `Make_SplitBoard.resx`,5817 字节)即可。

+ 2 - 2
UAS_MES_YDCY/FunctionCode/Make/Make_Repair67F.cs

@@ -274,10 +274,10 @@ namespace UAS_MES_NEW.Make
                     {
                         //验证makeserial或者ms_firstsn表序列号是否存在
                         sql.Clear();
-                        sql.Append("select max(ms_id) ms_id,ms_makecode,ma_craftcode,ms_stepcode,ms_firstsn,ms_prodcode,ms_sncode,ma_bomversion,pr_detail,ms_craftcode,ms_checkno,ms_ifrework,ms_reworkcheckno ");
+                        sql.Append("select max(ms_id) ms_id,ms_makecode,ms_craftcode ma_craftcode,ms_stepcode,ms_firstsn,ms_prodcode,ms_sncode,ma_bomversion,pr_detail,ms_craftcode,ms_checkno,ms_ifrework,ms_reworkcheckno ");
                         sql.Append("from makeserial left join make on ms_makecode=ma_code left join product on pr_code=ms_prodcode where ms_makecode ='" + macode + "' and ms_sncode in(");
                         sql.Append("select '" + GetSNCode.Text + "' from dual union select firstsn from makesnrelation where ");
-                        sql.Append("sn='" + GetSNCode.Text + "') group by ms_makecode,ms_stepcode,ms_prodcode,ma_craftcode,ms_sncode,ma_bomversion,pr_detail,ms_firstsn,ms_craftcode,ms_checkno,ms_ifrework,ms_reworkcheckno");
+                        sql.Append("sn='" + GetSNCode.Text + "') group by ms_makecode,ms_stepcode,ms_prodcode,ms_craftcode,ms_sncode,ma_bomversion,pr_detail,ms_firstsn,ms_craftcode,ms_checkno,ms_ifrework,ms_reworkcheckno");
                         dt = (DataTable)dh.ExecuteSql(sql.GetString(), "select");
                         if (dt.Rows.Count > 0)
                         {

+ 40 - 0
UAS_MES_YDCY/Program.cs

@@ -68,7 +68,12 @@ namespace UAS_MES_NEW
                 FileStream fas = new FileStream(SystemInf.CacheFolder + "lblprocess.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
                 fas.Close();
                 if (principal.IsInRole(WindowsBuiltInRole.Administrator))
+                {
+                    //限制程序同时运行的实例数量
+                    if (!CheckInstanceLimit())
+                        return;
                     Application.Run(new Login());
+                }
                 else
                 {
                     //创建启动对象
@@ -89,6 +94,41 @@ namespace UAS_MES_NEW
             }
         }
 
+        /// <summary>
+        /// 允许程序同时运行的最大实例数
+        /// </summary>
+        private const int MaxInstanceCount = 3;
+
+        /// <summary>
+        /// 检测同名进程数量,超出上限时提示并禁止启动
+        /// </summary>
+        /// <returns>允许启动返回 true</returns>
+        static bool CheckInstanceLimit()
+        {
+            try
+            {
+                //GetProcessesByName 的统计结果包含当前进程本身
+                System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(
+                    System.Diagnostics.Process.GetCurrentProcess().ProcessName);
+                int count = processes.Length;
+                foreach (System.Diagnostics.Process p in processes)
+                {
+                    p.Dispose();
+                }
+                if (count > MaxInstanceCount)
+                {
+                    MessageBox.Show("程序最多只能同时运行 " + MaxInstanceCount + " 个,请关闭其它窗口后再打开!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+                    return false;
+                }
+                return true;
+            }
+            catch (Exception)
+            {
+                //统计进程失败时不拦截,避免程序无法启动
+                return true;
+            }
+        }
+
         //处理线程的异常
         static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
         {