fix
修正了mcp的主线程调用问题
This commit is contained in:
1 parent
1fdcdefef1
commit
09f9d69d36
2 files changed
+64
-14
No files matched your search
@@ -50,7 +50,7 @@ extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
|
|||||||
void CR_SCGXCmdFnc();
|
void CR_SCGXCmdFnc();
|
||||||
void InitApplication()
|
void InitApplication()
|
||||||
{
|
{
|
||||||
mcp::close_mcp();
|
mcp::init_mcp();
|
||||||
|
|
||||||
acrxBuildClassHierarchy();
|
acrxBuildClassHierarchy();
|
||||||
AddCommand(_T("SHCRACKTOOLS"), _T("CR_SCGX"), _T("CR_SCGX"), ACRX_CMD_TRANSPARENT | ACRX_CMD_USEPICKSET, CR_SCGXCmdFnc);
|
AddCommand(_T("SHCRACKTOOLS"), _T("CR_SCGX"), _T("CR_SCGX"), ACRX_CMD_TRANSPARENT | ACRX_CMD_USEPICKSET, CR_SCGXCmdFnc);
|
||||||
|
|||||||
+63
-13
@@ -8,20 +8,24 @@
|
|||||||
|
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
|
||||||
|
#define WM_MCP_EXECUTE_TASK (WM_USER + 2048)
|
||||||
|
|
||||||
static std::thread g_serverThread;
|
static std::thread g_serverThread;
|
||||||
static std::atomic<bool> g_bRunning(false);
|
static std::atomic<bool> g_bRunning(false);
|
||||||
static SOCKET g_listenSocket = INVALID_SOCKET;
|
static SOCKET g_listenSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
static HWND g_hMsgWnd = NULL;
|
||||||
|
static const wchar_t* g_szMsgClassName = L"AutoAgentMcpMsgWndClass";
|
||||||
|
|
||||||
// 用于跨线程传递数据的结构体
|
// 用于跨线程传递数据的结构体
|
||||||
struct TaskData
|
struct TaskData
|
||||||
{
|
{
|
||||||
std::string rawJson;
|
std::string rawJson;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 真正执行绘图的回调函数 (此函数由 AutoCAD 主线程调度运行)
|
// 此函数在 AutoCAD 主 UI 线程运行,绝对安全.
|
||||||
static void MainThreadCallback(void *pData)
|
void ExecuteTaskInMainThread(TaskData *pTask)
|
||||||
{
|
{
|
||||||
TaskData *pTask = static_cast<TaskData *>(pData);
|
|
||||||
if (pTask == nullptr)
|
if (pTask == nullptr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -29,7 +33,6 @@ static void MainThreadCallback(void *pData)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 1. 解析 JSON 指令
|
|
||||||
auto j = nlohmann::json::parse(pTask->rawJson);
|
auto j = nlohmann::json::parse(pTask->rawJson);
|
||||||
if (j.contains("cmd") && j["cmd"] == "draw_circle")
|
if (j.contains("cmd") && j["cmd"] == "draw_circle")
|
||||||
{
|
{
|
||||||
@@ -37,13 +40,13 @@ static void MainThreadCallback(void *pData)
|
|||||||
double y = j.value("y", 0.0);
|
double y = j.value("y", 0.0);
|
||||||
double r = j.value("r", 100.0);
|
double r = j.value("r", 100.0);
|
||||||
|
|
||||||
// 2. 锁定当前活动文档 (跨线程操作后的绝对必要步骤)
|
|
||||||
AcApDocument *pDoc = acDocManager->curDocument();
|
AcApDocument *pDoc = acDocManager->curDocument();
|
||||||
if (pDoc)
|
if (pDoc)
|
||||||
{
|
{
|
||||||
acDocManager->lockDocument(pDoc, AcAp::kWrite, nullptr, nullptr, false);
|
// 此时在主线程,安全锁文档
|
||||||
|
Acad::ErrorStatus es = acDocManager->lockDocument(pDoc, AcAp::kWrite, nullptr, nullptr, false);
|
||||||
// 3. 常规 ObjectARX 绘图逻辑
|
if (es == Acad::eOk)
|
||||||
|
{
|
||||||
AcDbDatabase *pDb = pDoc->database();
|
AcDbDatabase *pDb = pDoc->database();
|
||||||
AcDbBlockTable *pBlockTable = nullptr;
|
AcDbBlockTable *pBlockTable = nullptr;
|
||||||
pDb->getBlockTable(pBlockTable, AcDb::kForRead);
|
pDb->getBlockTable(pBlockTable, AcDb::kForRead);
|
||||||
@@ -67,13 +70,27 @@ static void MainThreadCallback(void *pData)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
acutPrintf(_T("\n[MCP Server] JSON 解析或执行异常!\n"));
|
acutPrintf(_T("\n[MCP Server] JSON 解析或绘图异常!\n"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 清理由 Socket 线程在堆上分配的内存
|
// 隐式窗口的回调函数 (属于主线程)
|
||||||
delete pTask;
|
LRESULT CALLBACK McpWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (message == WM_MCP_EXECUTE_TASK)
|
||||||
|
{
|
||||||
|
TaskData *pTask = reinterpret_cast<TaskData *>(lParam);
|
||||||
|
if (pTask)
|
||||||
|
{
|
||||||
|
ExecuteTaskInMainThread(pTask);
|
||||||
|
delete pTask; // 执行完毕,清理内存
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCP 监听后台线程
|
// TCP 监听后台线程
|
||||||
@@ -114,8 +131,15 @@ static void TcpServerLoop()
|
|||||||
TaskData *pTask = new TaskData;
|
TaskData *pTask = new TaskData;
|
||||||
pTask->rawJson = recvBuf;
|
pTask->rawJson = recvBuf;
|
||||||
|
|
||||||
// 核心:委托 AutoCAD 主线程在下一个消息循环中执行回调
|
// 关键转变:通过 PostMessage 发送给主线程拥有的隐式窗口
|
||||||
acDocManager->executeInApplicationContext(MainThreadCallback, pTask);
|
if (g_hMsgWnd != NULL)
|
||||||
|
{
|
||||||
|
PostMessage(g_hMsgWnd, WM_MCP_EXECUTE_TASK, 0, reinterpret_cast<LPARAM>(pTask));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete pTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closesocket(clientSocket);
|
closesocket(clientSocket);
|
||||||
}
|
}
|
||||||
@@ -130,6 +154,24 @@ namespace mcp
|
|||||||
{
|
{
|
||||||
bool init_mcp()
|
bool init_mcp()
|
||||||
{
|
{
|
||||||
|
// 1. 在主线程注册并创建 Message-Only 窗口
|
||||||
|
WNDCLASSEX wc = { 0 };
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wc.lpfnWndProc = McpWndProc;
|
||||||
|
wc.hInstance = GetModuleHandle(NULL);
|
||||||
|
wc.lpszClassName = g_szMsgClassName;
|
||||||
|
RegisterClassEx(&wc);
|
||||||
|
|
||||||
|
g_hMsgWnd = CreateWindowEx(
|
||||||
|
0,
|
||||||
|
g_szMsgClassName,
|
||||||
|
L"AutoAgentMcpMsgWindow",
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
HWND_MESSAGE, // 纯消息窗口,无界面、无感知
|
||||||
|
NULL,
|
||||||
|
GetModuleHandle(NULL),
|
||||||
|
NULL
|
||||||
|
);
|
||||||
g_bRunning = true;
|
g_bRunning = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -153,6 +195,14 @@ namespace mcp
|
|||||||
{
|
{
|
||||||
g_serverThread.join();
|
g_serverThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_hMsgWnd != NULL)
|
||||||
|
{
|
||||||
|
DestroyWindow(g_hMsgWnd);
|
||||||
|
UnregisterClass(g_szMsgClassName, GetModuleHandle(NULL));
|
||||||
|
g_hMsgWnd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
acutPrintf(_T("\n[MCP Server] 插件已卸载,线程已关闭。\n"));
|
acutPrintf(_T("\n[MCP Server] 插件已卸载,线程已关闭。\n"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user