#include "mcp_tool.h" #include "cadsdk.h" namespace { // UTF-8 转 宽字符 (std::wstring) std::wstring Utf8ToWString(const std::string &utf8Str) { if (utf8Str.empty()) return std::wstring(); // 第一次调用获取需要的宽字符缓冲区大小 int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), NULL, 0); std::wstring wstrTo(sizeNeeded, 0); // 第二次调用真正进行转换 MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), &wstrTo[0], sizeNeeded); return wstrTo; } std::string ReplaceTemplateArgs(std::string tpl, const nlohmann::json &args) { for (auto it = args.begin(); it != args.end(); ++it) { std::string placeholder = "{" + it.key() + "}"; std::string valueStr; if (it.value().is_string()) { valueStr = it.value().get(); } else if (it.value().is_boolean()) { valueStr = it.value().get() ? "T" : "nil"; // 适配 AutoLISP 的布尔逻辑 } else { valueStr = it.value().dump(); // 数字类型直接转字符串 } size_t pos = 0; while ((pos = tpl.find(placeholder, pos)) != std::string::npos) { tpl.replace(pos, placeholder.length(), valueStr); pos += valueStr.length(); } } return tpl; } } #pragma region mcp_Tool_LispInline nlohmann::json mcp_Tool_LispInline::Execute(const nlohmann::json &args) { std::string tpl = m_config["backend"].value("script_template", ""); std::string finalScript = ReplaceTemplateArgs(tpl, args) + " "; // 尾部加空格,等同于在 CAD 命令行敲回车 std::wstring wScript = Utf8ToWString(finalScript); // 异步推送到 AutoCAD 命令行执行 acDocManager->sendStringToExecute(acDocManager->curDocument(), wScript.c_str()); return mcp_Tool_Utility::make_text_result("LISP内联指令已下发执行 (异步)"); } #pragma endregion mcp_Tool_LispInline #pragma region mcp_Tool_LispFile nlohmann::json mcp_Tool_LispFile::Execute(const nlohmann::json &args) { std::string fileName = m_config["backend"].value("file_name", ""); std::string callTpl = m_config["backend"].value("call_template", ""); // 组装文件完整路径,并将反斜杠 \ 转换为 LISP 安全的正斜杠 / std::string fullPath = m_lispDir + "/" + fileName; std::replace(fullPath.begin(), fullPath.end(), '\\', '/'); // 组装前置加载命令,末尾的 nil 是为了防止文件不存在时 LISP 引擎报错弹窗 std::string loadCmd = "(load \"" + fullPath + "\" nil) "; std::string executeCmd = ReplaceTemplateArgs(callTpl, args) + " "; std::string finalScript = loadCmd + executeCmd; std::wstring wScript = Utf8ToWString(finalScript); acDocManager->sendStringToExecute(acDocManager->curDocument(), wScript.c_str()); return mcp_Tool_Utility::make_text_result("LISP外部文件已加载并下发执行 (异步)"); } #pragma endregion mcp_Tool_LispFile #pragma region mcp_Tool_DllProxy // RAII:基座销毁工具时,自动通知 DLL 释放内存,并卸载模块 mcp_Tool_DllProxy::~mcp_Tool_DllProxy() { if (m_pRealTool && m_destroyFunc) { m_destroyFunc(m_pRealTool); } if (m_hModule) { FreeLibrary(m_hModule); } } nlohmann::json mcp_Tool_DllProxy::Execute(const nlohmann::json &args) { if (m_pRealTool) { return m_pRealTool->Execute(args); // 完美转发 } return mcp_Tool_Utility::make_error(-32603, "底层 DLL 工具实例已失效"); } #pragma endregion mcp_Tool_DllProxy