mcp 功能初步
This commit is contained in:
1 parent
9c41e1d91c
commit
5289689737
4 files changed
+161
-1
No files matched your search
@@ -1,6 +1,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "resource.h"
|
||||
#include "cadsdk.h"
|
||||
#include "mcp.h"
|
||||
|
||||
HINSTANCE _hdllInstance = NULL ;
|
||||
|
||||
@@ -49,8 +50,9 @@ extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
|
||||
void CR_SCGXCmdFnc();
|
||||
void InitApplication()
|
||||
{
|
||||
acrxBuildClassHierarchy();
|
||||
mcp::close_mcp();
|
||||
|
||||
acrxBuildClassHierarchy();
|
||||
AddCommand(_T("SHCRACKTOOLS"), _T("CR_SCGX"), _T("CR_SCGX"), ACRX_CMD_TRANSPARENT | ACRX_CMD_USEPICKSET, CR_SCGXCmdFnc);
|
||||
|
||||
}
|
||||
@@ -58,6 +60,7 @@ void InitApplication()
|
||||
void UnloadApplication()
|
||||
{
|
||||
acedRegCmds->removeGroup(_T("SHCRACKTOOLS"));
|
||||
mcp::close_mcp();
|
||||
}
|
||||
|
||||
void AddCommand(const TCHAR* cmdGroup, const TCHAR* cmdInt, const TCHAR* cmdLoc,
|
||||
|
||||
@@ -10,6 +10,7 @@ set(SOURCES
|
||||
"command.cpp"
|
||||
"stdafx.cpp"
|
||||
"AutoAgent.rc"
|
||||
"mcp.cpp"
|
||||
)
|
||||
add_def_file_name(SOURCES "${PROJECT_NAME}")
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#include "StdAfx.h"
|
||||
#include "cadsdk.h"
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
static std::thread g_serverThread;
|
||||
static std::atomic<bool> g_bRunning(false);
|
||||
static SOCKET g_listenSocket = INVALID_SOCKET;
|
||||
|
||||
// 用于跨线程传递数据的结构体
|
||||
struct TaskData
|
||||
{
|
||||
std::string rawJson;
|
||||
};
|
||||
|
||||
// 真正执行绘图的回调函数 (此函数由 AutoCAD 主线程调度运行)
|
||||
static void MainThreadCallback(void *pData)
|
||||
{
|
||||
TaskData *pTask = static_cast<TaskData *>(pData);
|
||||
if (pTask == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 解析 JSON 指令
|
||||
auto j = nlohmann::json::parse(pTask->rawJson);
|
||||
if (j.contains("cmd") && j["cmd"] == "draw_circle")
|
||||
{
|
||||
double x = j.value("x", 0.0);
|
||||
double y = j.value("y", 0.0);
|
||||
double r = j.value("r", 100.0);
|
||||
|
||||
// 2. 锁定当前活动文档 (跨线程操作后的绝对必要步骤)
|
||||
AcApDocument *pDoc = acDocManager->curDocument();
|
||||
if (pDoc)
|
||||
{
|
||||
acDocManager->lockDocument(pDoc, AcAp::kWrite, nullptr, nullptr, false);
|
||||
|
||||
// 3. 常规 ObjectARX 绘图逻辑
|
||||
AcDbDatabase *pDb = pDoc->database();
|
||||
AcDbBlockTable *pBlockTable = nullptr;
|
||||
pDb->getBlockTable(pBlockTable, AcDb::kForRead);
|
||||
|
||||
AcDbBlockTableRecord *pBTR = nullptr;
|
||||
pBlockTable->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForWrite);
|
||||
pBlockTable->close();
|
||||
|
||||
AcGePoint3d center(x, y, 0.0);
|
||||
AcGeVector3d normal(0.0, 0.0, 1.0);
|
||||
AcDbCircle *pCircle = new AcDbCircle(center, normal, r);
|
||||
|
||||
AcDbObjectId circleId;
|
||||
pBTR->appendAcDbEntity(circleId, pCircle);
|
||||
|
||||
pBTR->close();
|
||||
pCircle->close();
|
||||
|
||||
acDocManager->unlockDocument(pDoc);
|
||||
acutPrintf(_T("\n[MCP Server] 成功在坐标(%.2f, %.2f)绘制了半径为%.2f的圆\n"), x, y, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
acutPrintf(_T("\n[MCP Server] JSON 解析或执行异常!\n"));
|
||||
}
|
||||
|
||||
// 4. 清理由 Socket 线程在堆上分配的内存
|
||||
delete pTask;
|
||||
}
|
||||
|
||||
// TCP 监听后台线程
|
||||
static void TcpServerLoop()
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
|
||||
g_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
sockaddr_in serverAddr = { 0 };
|
||||
serverAddr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
|
||||
serverAddr.sin_port = htons(8080);
|
||||
|
||||
bind(g_listenSocket, (sockaddr *)&serverAddr, sizeof(serverAddr));
|
||||
listen(g_listenSocket, SOMAXCONN);
|
||||
|
||||
while (g_bRunning)
|
||||
{
|
||||
// 使用 select 模型实现带超时的轮询,确保插件卸载时线程能正常退出
|
||||
fd_set readSet;
|
||||
FD_ZERO(&readSet);
|
||||
FD_SET(g_listenSocket, &readSet);
|
||||
|
||||
timeval timeout = { 1, 0 }; // 1秒超时机制
|
||||
int ret = select(0, &readSet, nullptr, nullptr, &timeout);
|
||||
|
||||
if (ret > 0 && FD_ISSET(g_listenSocket, &readSet))
|
||||
{
|
||||
SOCKET clientSocket = accept(g_listenSocket, nullptr, nullptr);
|
||||
if (clientSocket != INVALID_SOCKET)
|
||||
{
|
||||
char recvBuf[2048] = { 0 };
|
||||
int bytesReceived = recv(clientSocket, recvBuf, sizeof(recvBuf) - 1, 0);
|
||||
if (bytesReceived > 0)
|
||||
{
|
||||
// 将数据拷贝到堆内存,准备派发给主线程
|
||||
TaskData *pTask = new TaskData;
|
||||
pTask->rawJson = recvBuf;
|
||||
|
||||
// 核心:委托 AutoCAD 主线程在下一个消息循环中执行回调
|
||||
acDocManager->executeInApplicationContext(MainThreadCallback, pTask);
|
||||
}
|
||||
closesocket(clientSocket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(g_listenSocket);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
namespace mcp
|
||||
{
|
||||
bool init_mcp()
|
||||
{
|
||||
g_bRunning = true;
|
||||
g_serverThread = std::thread(TcpServerLoop);
|
||||
acutPrintf(_T("\n[MCP Server] 后台 TCP 监听线程已启动 (端口: 8080)...\n"));
|
||||
}
|
||||
|
||||
bool close_mcp()
|
||||
{
|
||||
g_bRunning = false;
|
||||
if (g_serverThread.joinable())
|
||||
{
|
||||
g_serverThread.join();
|
||||
}
|
||||
acutPrintf(_T("\n[MCP Server] 插件已卸载,线程已关闭。\n"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace mcp
|
||||
{
|
||||
bool init_mcp();
|
||||
bool close_mcp();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user