/* * 由SharpDevelop创建。 * 用户: 099978 * 日期: 2026-08-25 * 时间: 20:59 * * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件 */ using System; using System.IO; using System.Runtime.InteropServices; using System.Windows.Forms; namespace 成套报价软件 { /// /// Class with program entry point. /// internal sealed class Program { /// 主程序单实例互斥锁名。 private const string SingleInstanceMutexName = "成套报价软件_SingleInstance"; /// 二次实例向首实例转发导入命令的文件(覆盖式=只保留最新一条)。 internal static string 导入命令文件路径 { get { return Path.Combine(Path.GetTempPath(), "成套报价软件_导入命令.txt"); } } [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); // 9=SW_RESTORE [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern int ShellExecuteW(IntPtr hWnd, string verb, string file, string parameters, string directory, int showCmd); /// /// Program entry point. /// [STAThread] private static void Main(string[] args) { // ★ 单实例:主程序窗口只允许一个(用户要求) bool createdNew; var mutex = new System.Threading.Mutex(true, SingleInstanceMutexName, out createdNew); if (!createdNew) { // 二次启动:转发导入命令(如果有)→激活已有窗口→退出,不新开窗口 try { 二次实例写日志("被判定为二次实例(锁已被占): args=" + (args != null && args.Length > 0 ? args[0] : "(无)")); if (args != null && args.Length > 0 && !string.IsNullOrWhiteSpace(args[0])) File.WriteAllText(导入命令文件路径, args[0], System.Text.Encoding.UTF8); 激活已有主窗口(); } catch { } return; } // ★ 全局异常捕获(迁移自旧 主窗口.Main):只写日志不弹窗 Application.ThreadException += (s, e) => { try { File.AppendAllText( Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"logs\thread_exception.log"), "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "] UI线程异常" + (e.Exception != null ? "\r\n" + e.Exception : "\r\n(无异常对象)") + "\r\n\r\n"); } catch { } }; AppDomain.CurrentDomain.UnhandledException += (s, e) => { try { File.AppendAllText( Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"logs\thread_exception.log"), "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "] 非UI线程异常" + (e.ExceptionObject != null ? "\r\n" + e.ExceptionObject : "\r\n(无异常对象)") + "\r\n\r\n"); } catch { } }; try { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // ★ 启动先登录(用户要求):登录成功才进主窗口;取消/关闭登录窗=退出程序。 // 登录窗 Load 会自动回填"记住密码"的账号,勾着的用户点一下登录即可。 var 登录窗 = new 登录(); if (登录窗.ShowDialog() != System.Windows.Forms.DialogResult.OK) return; MainForm.当前登录手机号 = 登录窗.登录手机号; MainForm.当前会员类型 = 登录窗.登录会员类型; MainForm.当前有效期 = 登录窗.登录有效期; MainForm.当前登录密码 = 登录窗.登录密码; // 新版项目云协议需要(仅内存) Application.Run(new MainForm(args.Length > 0 ? args[0] : null)); } catch (Exception ex) { File.WriteAllText( Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "crash.log"), ex.ToString()); MessageBox.Show("启动失败:\n\n" + ex, "成套报价软件", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { try { mutex.ReleaseMutex(); } catch { } mutex.Dispose(); // ★改密重启(2026-09-26 用户要求:改密成功=关闭主窗口→弹登录窗):主窗体已关闭、 // 单实例锁已释放,此刻启动新实例(新实例启动先弹登录窗,用新密码重新登录)。 // 用 ShellExecuteW(与 OpenClawHost 同款 P/Invoke 通道) if (MainForm.改密重启) { try { int rc = ShellExecuteW(System.IntPtr.Zero, "open", System.Windows.Forms.Application.ExecutablePath, null, null, 1); // 1=SW_NORMAL if (rc <= 32) System.Windows.Forms.MessageBox.Show("密码已修改。请重新打开成套报价软件,用新密码登录。", "成套报价软件", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); } catch { } } } } /// 找到已运行的主程序进程并把它带到前台(最小化时先还原)。 private static void 激活已有主窗口() { try { int selfId = System.Diagnostics.Process.GetCurrentProcess().Id; foreach (var p in System.Diagnostics.Process.GetProcessesByName("成套报价软件")) { if (p.Id == selfId || p.MainWindowHandle == IntPtr.Zero) continue; ShowWindowAsync(p.MainWindowHandle, 9); // 还原(最小化时) SetForegroundWindow(p.MainWindowHandle); // 前台 break; } } catch { } } /// 二次实例诊断日志(与主日志同目录;排查"要双击两次才启动":首启慢时第二次双击会被单实例机制吞掉)。 private static void 二次实例写日志(string msg) { try { string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs"); Directory.CreateDirectory(dir); File.AppendAllText(Path.Combine(dir, "diag_" + DateTime.Now.ToString("yyyy-MM-dd") + ".log"), DateTime.Now.ToString("HH:mm:ss.fff") + " [二次实例] " + msg + "\r\n"); } catch { } } } }