diff --git a/插件库/Lskj.Main/FrmLogin.cs b/插件库/Lskj.Main/FrmLogin.cs
index 6de4ef2..4515a2b 100644
--- a/插件库/Lskj.Main/FrmLogin.cs
+++ b/插件库/Lskj.Main/FrmLogin.cs
@@ -1284,7 +1284,7 @@ namespace Lskj.Main
DialogResult result = MessageUtil.Show(ResourceKeys.IsExit, MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
- Process[] p = Process.GetProcessesByName("Ls_ERP");
+ Process[] p = Manager.GetApplicationProcesses();
foreach (Process item in p)
{
try
@@ -1920,4 +1920,4 @@ namespace Lskj.Main
isPlaintextPwd = !isPlaintextPwd;
}
}
-}
\ No newline at end of file
+}
diff --git a/插件库/Lskj.Main/FrmSubSystem.cs b/插件库/Lskj.Main/FrmSubSystem.cs
index 19c6e15..1e22645 100644
--- a/插件库/Lskj.Main/FrmSubSystem.cs
+++ b/插件库/Lskj.Main/FrmSubSystem.cs
@@ -546,7 +546,7 @@ namespace Lskj.Main
//记录登出日志
LogUtil.WriteDebug("", "退出软件", "软件退出", "系统登录");
- Process[] p = Process.GetProcessesByName("Ls_ERP");
+ Process[] p = Manager.GetApplicationProcesses();
foreach (Process item in p)
{
try
@@ -716,4 +716,4 @@ namespace Lskj.Main
}
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/插件库/Lskj.Main/Hosting/IExternalMainShell.cs b/插件库/Lskj.Main/Hosting/IExternalMainShell.cs
new file mode 100644
index 0000000..53d0ef0
--- /dev/null
+++ b/插件库/Lskj.Main/Hosting/IExternalMainShell.cs
@@ -0,0 +1,19 @@
+using System.Windows.Forms;
+
+namespace Lskj.Main.Hosting
+{
+ ///
+ /// 旧启动流程与可选新主界面之间的中立扩展点。
+ /// 此接口只使用 .NET Framework 4.0/WinForms 基础类型,不引用 WPF 或 DevExpress 25.2。
+ ///
+ public interface IExternalMainShell
+ {
+ bool IsOpen { get; }
+
+ DialogResult ShowDialog();
+
+ void RequestRelogin();
+
+ void RequestExit(string message);
+ }
+}
diff --git a/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs b/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs
new file mode 100644
index 0000000..febbf40
--- /dev/null
+++ b/插件库/Lskj.Main/Hosting/LegacyApplicationHost.cs
@@ -0,0 +1,29 @@
+using System;
+using Lskj.Main.Model;
+
+namespace Lskj.Main.Hosting
+{
+ ///
+ /// 为独立的新启动程序公开原 Ls_ERP 初始化和登录流程。
+ ///
+ public static class LegacyApplicationHost
+ {
+ public static void Run(string[] args, IExternalMainShell externalMainShell)
+ {
+ if (externalMainShell == null)
+ throw new ArgumentNullException("externalMainShell");
+ if (Manager.ExternalMainShell != null)
+ throw new InvalidOperationException("旧程序已经由另一个外部主界面托管。");
+
+ Manager.ExternalMainShell = externalMainShell;
+ try
+ {
+ Program.RunFromExternalHost(args);
+ }
+ finally
+ {
+ Manager.ExternalMainShell = null;
+ }
+ }
+ }
+}
diff --git a/插件库/Lskj.Main/Hosting/README.md b/插件库/Lskj.Main/Hosting/README.md
new file mode 100644
index 0000000..0673a43
--- /dev/null
+++ b/插件库/Lskj.Main/Hosting/README.md
@@ -0,0 +1,35 @@
+# 外部主界面兼容层
+
+这个目录只为旧 `.NET Framework 4.0` 启动流程提供一个可选扩展点,不引用 WPF 或 DevExpress 25.2。
+
+## 默认路线
+
+直接运行 `Ls_ERP.exe` 时,`Manager.ExternalMainShell` 为 `null`:
+
+```text
+Program.Main
+ -> Manager.StartForm
+ -> FrmLogin
+ -> Manager.RunMainForm
+ -> FrmMain
+```
+
+这条路线不加载任何 WPF 程序集,并保持 DevExpress WinForms 15.2。
+
+## 外部宿主路线
+
+`.NET Framework 4.8` 的独立启动程序通过 `LegacyApplicationHost.Run` 注入 `IExternalMainShell`。旧程序仍负责 CEF、全局异常、配置、数据库、登录和子系统选择,只在 `RunMainForm` 位置回调外部主界面。
+
+`IExternalMainShell` 当前承担:
+
+- 同步显示外部主窗口;
+- 返回普通关闭或重新登录结果;
+- 处理旧插件发起的重新登录;
+- 在强制下线时通知外部主窗口退出。
+
+## 修改规则
+
+- 此层必须继续可以在 .NET Framework 4.0 下编译。
+- 禁止引用 `Lserp.Wpf.*`、WPF 类型或 DevExpress 25.2。
+- 新界面特有实现放在独立 WPF 解决方案的 `Lserp.Wpf.Legacy.WinForms`。
+- 新增兼容能力时优先扩展中立接口,不要在旧工程中直接调用 WPF。
diff --git a/插件库/Lskj.Main/Lskj.Main.csproj b/插件库/Lskj.Main/Lskj.Main.csproj
index 1bc8efc..355288c 100644
--- a/插件库/Lskj.Main/Lskj.Main.csproj
+++ b/插件库/Lskj.Main/Lskj.Main.csproj
@@ -276,6 +276,8 @@
+
+
diff --git a/插件库/Lskj.Main/Model/Manager.cs b/插件库/Lskj.Main/Model/Manager.cs
index de4de7b..f34e07f 100644
--- a/插件库/Lskj.Main/Model/Manager.cs
+++ b/插件库/Lskj.Main/Model/Manager.cs
@@ -15,6 +15,7 @@ using Lskj.Control;
using Lskj.Control.Model;
using Lskj.Core;
using Lskj.Data;
+using Lskj.Main.Hosting;
using Lskj.Model;
using Lskj.Util;
using Lskj.Web.Core.Util;
@@ -55,6 +56,10 @@ namespace Lskj.Main.Model
public static int isAwaitTime = 10;
public static int RefreshTime = 0;
///
+ /// 由外部启动程序提供的可选主界面。默认为 null,旧 Ls_ERP.exe 仍打开 FrmMain。
+ ///
+ public static IExternalMainShell ExternalMainShell { get; internal set; }
+ ///
/// 默认下载地址
///
private static string filePath = string.Empty;
@@ -190,7 +195,12 @@ namespace Lskj.Main.Model
if (isStart)
{
// 直接进入主界面
- RunMainForm();
+ result = RunMainForm();
+ if (result == DialogResult.Retry)
+ {
+ StartForm();
+ return;
+ }
if (ERPInfo.Instance.SubMenuCount > 1)
{
ReStartMain();
@@ -686,6 +696,10 @@ namespace Lskj.Main.Model
/// DialogResult.
private static DialogResult RunMainForm()
{
+ IExternalMainShell externalMainShell = ExternalMainShell;
+ if (externalMainShell != null)
+ return externalMainShell.ShowDialog();
+
_frmMain = new FrmMain();
return _frmMain.ShowDialog();
}
@@ -909,6 +923,11 @@ namespace Lskj.Main.Model
}
}));
}
+ else if (ExternalMainShell != null && ExternalMainShell.IsOpen)
+ {
+ ExternalMainShell.RequestExit($"当前用户在另一电脑登录\r\nClientIp:{clientip}\r\nMacAdress:{loginMacAdress}\r\n当前系统即将关闭");
+ isClose = true;
+ }
else if (_frmMain != null && _frmMain.Visible == true)
{
_frmMain.Invoke(new Action(() =>
@@ -953,7 +972,7 @@ namespace Lskj.Main.Model
}
//记录登出日志
LogUtil.WriteDebug("", "退出软件", "软件退出", "系统登录");
- Process[] p = Process.GetProcessesByName("Ls_ERP");
+ Process[] p = GetApplicationProcesses();
foreach (Process item in p)
{
try
@@ -1107,6 +1126,12 @@ namespace Lskj.Main.Model
///
public static void ReLogin()
{
+ IExternalMainShell externalMainShell = ExternalMainShell;
+ if (externalMainShell != null && externalMainShell.IsOpen)
+ {
+ externalMainShell.RequestRelogin();
+ return;
+ }
if (_frmMain != null)
{
if (ERPInfo.Instance.WatermarkForm != null)
@@ -1121,5 +1146,16 @@ namespace Lskj.Main.Model
StartForm();
}
+ ///
+ /// 返回当前启动路线需要退出的主进程。
+ /// 旧入口保持原有 Ls_ERP 进程名语义,外部宿主只退出当前 WPF 进程。
+ ///
+ internal static Process[] GetApplicationProcesses()
+ {
+ return ExternalMainShell == null
+ ? Process.GetProcessesByName("Ls_ERP")
+ : new[] { Process.GetCurrentProcess() };
+ }
+
}
-}
\ No newline at end of file
+}
diff --git a/插件库/Lskj.Main/Program.cs b/插件库/Lskj.Main/Program.cs
index 6a1afc1..9956002 100644
--- a/插件库/Lskj.Main/Program.cs
+++ b/插件库/Lskj.Main/Program.cs
@@ -92,6 +92,14 @@ namespace Lskj.Main
}
}
+ ///
+ /// 允许 .NET Framework 4.8 外部宿主复用原程序的 CEF、皮肤、异常、注册和登录初始化。
+ /// 正常启动 Ls_ERP.exe 仍由 Main 直接进入,不经过此方法。
+ ///
+ internal static void RunFromExternalHost(string[] args)
+ {
+ Main(args ?? new string[0]);
+ }
#region 浏览器处理类
///
/// 说明:浏览器处理类