/*
* 由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 { }
}
}
}