Feature: Add list_files and get_screenshot MCP tools

Add the two P2c MCP tools on top of the P2b protocol. list_files lists
drives (COMMAND_LIST_DRIVE -> TOKEN_DRIVE_LIST) or a directory (follow-up
COMMAND_LIST_FILES -> TOKEN_FILE_LIST on the same one-shot sub-link);
get_screenshot reuses the screen-preview RPC with a per-host reqId
correlation so stale or MFC-preview responses fall through to the MFC
path untouched. Both share the P2b single-flight pending registry.

Fix file/process name encoding: the client reads process names, paths and
file names via the ANSI (A) APIs, so they are GBK on Windows regardless of
the CLIENT_CAP_UTF8 capability bit (which governs window titles only).
Decode by clientType (LNX/MAC = UTF-8, Windows = 936) rather than
GetClientEncoding, and convert the list_files path to the client ANSI code
page before sending. Sync Mcp_Phase2_Design.md with the P2c design and the
encoding correction.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxiang
2026-08-19 13:27:32 +02:00
parent bcde74368d
commit 61089e5fae
4 changed files with 545 additions and 22 deletions

View File

@@ -6190,6 +6190,12 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
// IO 线程不接触 UIclientId 用于循环快照路由到对应窗口)。
// 不用 WPARAM 携带 ID32 位 Windows 上 WPARAM 是 32 位,会截 64 位 clientID。
if (len < sizeof(ScreenPreviewRspHeader)) break;
// P2cMCP 挂起时接管(屏幕预览 = 主连接 RPC不能 CancelIO
// reqId 关联:命中 MCP 的 expectedReqId 才取走,避免误吞 MFC 预览在途响应。
uint64_t previewDevId = ContextObject->GetClientID();
const ScreenPreviewRspHeader* previewHdr = reinterpret_cast<const ScreenPreviewRspHeader*>(szBuffer);
if (McpServer().TakePreviewResponse(previewDevId, previewHdr->reqId, szBuffer, len))
break;
auto* msg = new CMy2015RemoteDlg::PreviewRspMsg{
ContextObject->GetClientID(),
std::vector<BYTE>(szBuffer, szBuffer + len)
@@ -6316,10 +6322,29 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
break;
}
case TOKEN_DRIVE_LIST: { // 文件管理【x】
// P2cMCP 挂起时接管。列盘 = 取走数据后用完即关;列目录 = 转向下发
// COMMAND_LIST_FILES、等 TOKEN_FILE_LIST此时不关子链接交给 TOKEN_FILE_LIST 分支收尾)。
uint64_t devId = ContextObject->GetClientID();
if (McpServer().IsPending(devId)) {
if (McpServer().OnDriveList(devId, ContextObject, szBuffer, len))
ContextObject->CancelIO(); // 只列盘 → 用完即关一次性子链接
break;
}
ContextObject->EnableZstdContext(6);
g_2015RemoteDlg->SendMessage(WM_OPENFILEMANAGERDIALOG, 0, (LPARAM)ContextObject);
break;
}
case TOKEN_FILE_LIST: { // 文件列表【P2c仅 MCP 无头路径会到达】
// 正常文件管理由 FileManagerDlg 的 hDlg 接管TOKEN_FILE_LIST 不进此分派;
// 到达此处只有 MCP 无头列目录这一种情形。挂起命中则取数据,否则(超时迟到)
// 直接关掉孤儿子链接,避免泄漏。
uint64_t devId = ContextObject->GetClientID();
if (McpServer().IsPending(devId)) {
McpServer().TakeMainResponse(devId, ContextObject->GetBuffer(0), ContextObject->GetBufferLength());
}
ContextObject->CancelIO(); // 无论是否命中,用完即关(无 MFC 对话框接管此子链接)
break;
}
case TOKEN_TALK_START: { // 发送消息【x】
g_2015RemoteDlg->SendMessage(WM_OPENTALKDIALOG, 0, (LPARAM)ContextObject);
break;