diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 01705bd..c5e2598 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index e6a35cd..c70cbca 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -4587,6 +4587,12 @@ BOOL CALLBACK CMy2015RemoteDlg::OfflineProc(CONTEXT_OBJECT* ContextObject) if (!g_2015RemoteDlg || g_2015RemoteDlg->isClosed) return FALSE; + // Web 终端的 shell 子上下文断开:通知 WebService 清理 session(含通知前端)。 + // 在 RemoveFromHostList 之前做,避免 ctx 被释放后 WebService 还持有悬空指针。 + if (WebService().IsRunning() && WebService().IsTerminalContext(ContextObject)) { + WebService().OnTerminalClosed(ContextObject); + } + SOCKET nSocket = ContextObject->sClientSocket; CDialogBase* p = (CDialogBase*)ContextObject->hDlg; @@ -4918,6 +4924,19 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) unsigned cmd = ContextObject->InDeCompressedBuffer.GetBYTE(0); LPBYTE szBuffer = ContextObject->InDeCompressedBuffer.GetBuffer(); unsigned len = ContextObject->InDeCompressedBuffer.GetBufferLen(); + + // ===== Web 终端的 shell 子上下文:被 WebService 接管时,所有数据走 OnTerminalData ===== + // 这里覆盖一个特殊路径:Web 接管的 shell 子上下文不开 MFC 对话框,hDlg 一直为 NULL, + // 因此每个数据包都会走到这个 MessageHandle。我们把字节直接转发给 WebService。 + if (WebService().IsRunning() && WebService().IsTerminalContext(ContextObject)) { + if (len == 1 && cmd == TOKEN_TERMINAL_CLOSE) { + WebService().OnTerminalClosed(ContextObject); + } else { + WebService().OnTerminalData(ContextObject, szBuffer, len); + } + return; + } + // 【L】:主机上下线和授权 // 【x】:对话框相关功能 switch (cmd) { @@ -5676,11 +5695,25 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) g_2015RemoteDlg->SendMessage(WM_OPENTALKDIALOG, 0, (LPARAM)ContextObject); break; } - case TOKEN_SHELL_START: { // Windows 远程终端 + case TOKEN_SHELL_START: { // Windows 老 cmd 管道终端 + // 如果是 Web 触发的 term_open,把 shell 子上下文交给 WebService 而不是开 MFC dialog + uint64_t devId = ContextObject->GetClientID(); + if (WebService().IsRunning() && WebService().IsTermPending(devId)) { + WebService().RegisterTerminalContext(devId, ContextObject, /*isPty*/false); + // hDlg 留 NULL:后续数据继续走 MessageHandle 顶部的 IsTerminalContext 分支 + break; + } g_2015RemoteDlg->SendMessage(WM_OPENSHELLDIALOG, 0, (LPARAM)ContextObject); break; } - case TOKEN_TERMINAL_START: { // Linux PTY 终端 (WebView2 + xterm.js) + case TOKEN_TERMINAL_START: { // 现代 PTY 终端 (Linux/macOS/Windows ConPTY) + // 同上:Web 触发优先级最高,直接 WebService 接管 + uint64_t devId = ContextObject->GetClientID(); + if (WebService().IsRunning() && WebService().IsTermPending(devId)) { + WebService().RegisterTerminalContext(devId, ContextObject, /*isPty*/true); + break; + } + // 三个前置条件,缺任何一个都回退到经典终端,并把原因贴到信息列表。 // SYSTEM 场景:WebView2 不支持 LocalSystem token,会出现"窗口能弹但页面空白", // 显式拦截一次,避免用户误以为是 bug。 diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 45c6567..0749146 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -601,6 +601,11 @@ + + + + + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 20c26e6..15ac41e 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -340,4 +340,9 @@ {17217547-dc35-4a87-859c-e8559529a909} + + + + + \ No newline at end of file diff --git a/server/2015Remote/WebPage.h b/server/2015Remote/WebPage.h index 25e0da3..44e151a 100644 --- a/server/2015Remote/WebPage.h +++ b/server/2015Remote/WebPage.h @@ -22,6 +22,8 @@ inline std::string GetWebPageHTML() { + +