CreoOtkPluging/MFCCreoDll.cpp
root 0e98285a74 实现路径删除功能并修复编译问题
## 新增功能
- 新增PathDeleteManager类,实现按路径批量删除装配体组件
- 支持绝对和相对路径格式的智能解析
- 采用按装配体分组的抑制策略,确保上下文正确匹配
- 完善的异常处理和错误原因追踪机制

## 修复的技术问题
- 解决路径删除"Unknown exception during suppression operation"错误
- 修复特征ID与owner_assembly上下文不匹配问题
- 转换文件为CRLF行尾符,解决Visual Studio编译错误
- 添加UTF-8 BOM确保编码一致性
- 移除C++11语法实现传统C++兼容性

## API端点
- POST /api/creo/path/delete - 路径组件删除接口

## 文件变更
- 新增: PathDeleteManager.h, PathDeleteManager.cpp
- 修改: MFCCreoDll.cpp (集成路径删除接口)
- 修改: 项目配置文件
- 更新: CLAUDE.md (技术文档)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-08 12:29:58 +08:00

1460 lines
60 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// MFCCreoDll.cpp: 定义 DLL 的初始化例程。
//
#include "pch.h"
#include "framework.h"
#include "MFCCreoDll.h"
#include "HttpServer.h"
#include "CreoManager.h"
#include "ShellExportHandler.h"
#include "PathDeleteManager.h"
#include <wfcSession.h>
#include <wfcGlobal.h>
#include <string>
#include <sstream>
#include <regex>
#include <atomic>
#include <memory>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// --- 全局变量 ---
static std::unique_ptr<HttpServer> g_http_server;
static UINT_PTR timer_id = 0;
// 无锁消息队列项
struct MessageItem {
std::string type; // "SHOW_MESSAGE", "OPEN_MODEL_REQUEST", 或 "SHRINKWRAP_SHELL_REQUEST"
std::string data; // 消息内容或文件路径或JSON数据
std::string extra; // 额外参数如open_mode
volatile bool completed; // 完成标志
void* result_ptr; // 结果指针
MessageItem() : completed(false), result_ptr(nullptr) {}
};
// 无锁同步机制
static volatile MessageItem* pending_message_item = nullptr;
static std::atomic<bool> has_pending_item{false};
// --- 辅助函数:将 std::string 转换为 xstring ---
xstring ConvertStringToXstring(const std::string& str)
{
std::wstring wstr(str.begin(), str.end());
return xstring(wstr.c_str());
}
// 定时器回调函数,使用无锁消息机制处理消息
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
// 使用无锁机制检查待处理消息
if (has_pending_item.load() && pending_message_item) {
MessageItem* item = const_cast<MessageItem*>(pending_message_item);
try {
if (item->type == "OPEN_MODEL_REQUEST") {
OpenResult result = CreoManager::Instance().OpenModel(item->data, item->extra);
// 如果模式是active且模型成功打开激活窗口
if (result.success && item->extra == "active") {
try {
pfcSession_ptr session = pfcGetCurrentSession();
if (session) {
// 获取刚刚打开的模型
xstring filename_xstr = ConvertStringToXstring(result.model_name);
pfcModelDescriptor_ptr desc = pfcModelDescriptor::CreateFromFileName(filename_xstr);
pfcModel_ptr model = session->GetModelFromDescr(desc);
if (model) {
// 创建或激活模型窗口
pfcWindow_ptr modelWindow = session->CreateModelWindow(model);
if (modelWindow) {
try {
modelWindow->Activate();
model->Display();
modelWindow->Refresh();
}
catch (...) {
// 激活失败,尝试设置为当前窗口
try {
session->SetCurrentWindow(modelWindow);
}
catch (...) {
}
}
// 尝试刷新窗口
try {
modelWindow->Refresh();
}
catch (...) {
// 刷新失败不影响主要功能
}
}
}
}
}
catch (...) {
}
}
item->result_ptr = new OpenResult(result);
item->completed = true;
}
else if (item->type == "SHRINKWRAP_SHELL_REQUEST") {
// Shrinkwrap外壳导出处理
// 将JSON数据转换为HttpRequest格式
HttpRequest shrinkwrap_request;
shrinkwrap_request.method = "POST";
shrinkwrap_request.path = "/api/creo/shrinkwrap/shell";
shrinkwrap_request.body = item->data;
// 执行Shrinkwrap处理
HttpResponse response = ShellExportHandler::HandleShrinkwrapShellRequest(shrinkwrap_request);
// 保存结果
item->result_ptr = new HttpResponse(response);
item->completed = true;
}
else if (item->type == "SHOW_MESSAGE") {
// 消息显示处理
CreoManager::Instance().ShowMessage(item->data);
item->completed = true;
}
// 清理状态
pending_message_item = nullptr;
has_pending_item = false;
}
catch (...) {
// 异常处理
if (item->type == "OPEN_MODEL_REQUEST") {
OpenResult* error_result = new OpenResult();
error_result->success = false;
error_result->error_message = "Unexpected error during operation execution";
item->result_ptr = error_result;
}
else if (item->type == "SHRINKWRAP_SHELL_REQUEST") {
HttpResponse* error_response = new HttpResponse();
error_response->status_code = 500;
error_response->body = "{\"success\": false, \"error\": \"Unexpected error during shrinkwrap operation\"}";
item->result_ptr = error_response;
}
item->completed = true;
pending_message_item = nullptr;
has_pending_item = false;
}
}
}
// 测试路由处理器
HttpResponse TestHandler(const HttpRequest& request) {
bool creo_connected = false;
try {
pfcSession_ptr session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
creo_connected = (session != nullptr);
}
catch (...) {
creo_connected = false;
}
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"running\": " << (creo_connected ? "true" : "false") << ","
<< "\"message\": \"" << (creo_connected ? "CREOSON 与 Creo 均已启动" : "Creo 未连接") << "\""
<< "},"
<< "\"error\": null"
<< "}";
HttpResponse response;
response.body = json.str();
return response;
}
// 显示消息路由处理器
HttpResponse ShowMessageHandler(const HttpRequest& request) {
// 从查询参数获取消息
std::string message = "Default message";
size_t text_pos = request.query.find("text=");
if (text_pos != std::string::npos) {
text_pos += 5; // 跳过"text="
size_t end_pos = request.query.find("&", text_pos);
if (end_pos == std::string::npos) {
end_pos = request.query.length();
}
message = request.query.substr(text_pos, end_pos - text_pos);
}
// 使用无锁消息机制
MessageItem message_item;
message_item.type = "SHOW_MESSAGE";
message_item.data = message;
// 原子设置(无锁)
pending_message_item = &message_item;
has_pending_item = true;
// 等待主线程处理完成
while (!message_item.completed) {
Sleep(10);
}
HttpResponse response;
response.body = "{\"status\":\"ok\",\"message\":\"Message sent to Creo\"}";
return response;
}
// Creo状态检测路由处理器
HttpResponse CreoStatusHandler(const HttpRequest& request) {
CreoStatus status = CreoManager::Instance().GetCreoStatus();
std::ostringstream json;
json << "{"
<< "\"is_connected\":" << (status.is_connected ? "true" : "false") << ","
<< "\"version\":\"" << status.version << "\","
<< "\"build\":\"" << status.build << "\","
<< "\"working_directory\":\"" << status.working_directory << "\","
<< "\"session_id\":" << status.session_id
<< "}";
HttpResponse response;
response.body = json.str();
return response;
}
// 模型状态检测路由处理器
HttpResponse ModelStatusHandler(const HttpRequest& request) {
ModelStatus status = CreoManager::Instance().GetModelStatus();
std::ostringstream json;
if (status.has_model) {
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"name\": \"" << status.name << "\","
<< "\"filename\": \"" << status.filename << "\","
<< "\"type\": \"" << status.type << "\","
<< "\"software\": \"" << status.software << "\","
<< "\"version\": \"" << status.version << "\","
<< "\"connectionTime\": \"" << status.connection_time << "\","
<< "\"isAssembly\": " << (status.is_assembly ? "true" : "false") << ",";
if (status.is_assembly) {
json << "\"basicStats\": {"
<< "\"totalParts\": " << status.total_parts << ","
<< "\"assemblyLevels\": " << status.assembly_levels << ","
<< "\"fileSize\": \"" << status.file_size << "\""
<< "},";
}
json << "\"fileName\": \"" << status.filename << "\","
<< "\"sourceSoftware\": \"" << status.software << "\","
<< "\"partCount\": " << status.total_parts << ","
<< "\"assemblyLevel\": " << status.assembly_levels << ","
<< "\"connectionStatus\": \"" << status.connection_status << "\","
<< "\"openTime\": \"" << status.open_time << "\""
<< "},"
<< "\"error\": null"
<< "}";
} else {
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"No model is currently open\""
<< "}";
}
HttpResponse response;
response.body = json.str();
return response;
}
// 简单的JSON解析函数
std::string ExtractJsonValue(const std::string& json, const std::string& key) {
// 查找键值对 "key": "value"
std::string key_pattern = "\"" + key + "\"";
size_t key_pos = json.find(key_pattern);
if (key_pos != std::string::npos) {
// 找到冒号
size_t colon_pos = json.find(":", key_pos);
if (colon_pos != std::string::npos) {
// 跳过空格找到值的开始
size_t value_start = colon_pos + 1;
while (value_start < json.length() && (json[value_start] == ' ' || json[value_start] == '\t' || json[value_start] == '\n' || json[value_start] == '\r')) {
value_start++;
}
// 检查是否是字符串值(以双引号开始)
if (value_start < json.length() && json[value_start] == '"') {
size_t value_end = json.find('"', value_start + 1);
if (value_end != std::string::npos) {
return json.substr(value_start + 1, value_end - value_start - 1);
}
}
// 处理数字值(不以双引号开始)
else if (value_start < json.length()) {
size_t value_end = value_start;
while (value_end < json.length() &&
json[value_end] != ',' &&
json[value_end] != '}' &&
json[value_end] != ']' &&
json[value_end] != ' ' &&
json[value_end] != '\t' &&
json[value_end] != '\n' &&
json[value_end] != '\r') {
value_end++;
}
if (value_end > value_start) {
return json.substr(value_start, value_end - value_start);
}
}
}
}
return "";
}
bool ExtractJsonBool(const std::string& json, const std::string& key) {
std::regex pattern("\"" + key + "\"\s*:\s*(true|false)");
std::smatch match;
if (std::regex_search(json, match, pattern)) {
return match[1].str() == "true";
}
return false;
}
// 模型导出路由处理器
HttpResponse ExportModelHandler(const HttpRequest& request) {
if (request.method != "POST") {
HttpResponse response;
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
// 解析JSON请求体
std::string software_type = ExtractJsonValue(request.body, "software_type");
std::string format_type = ExtractJsonValue(request.body, "format_type");
std::string export_path = ExtractJsonValue(request.body, "export_path");
// 提取options中的geom_flags - 简化处理,避免正则表达式崩溃
std::string geom_flags = "solids"; // 默认值
// 简单的字符串查找方式,避免正则表达式
size_t options_pos = request.body.find("\"options\"");
if (options_pos != std::string::npos) {
size_t start_brace = request.body.find("{", options_pos);
if (start_brace != std::string::npos) {
size_t end_brace = request.body.find("}", start_brace);
if (end_brace != std::string::npos) {
std::string options_content = request.body.substr(start_brace + 1, end_brace - start_brace - 1);
std::string extracted_geom_flags = ExtractJsonValue(options_content, "geom_flags");
if (!extracted_geom_flags.empty()) {
geom_flags = extracted_geom_flags;
}
}
}
}
// 验证参数
if (software_type != "creo" || format_type != "step" || export_path.empty()) {
HttpResponse response;
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid parameters\"}";
return response;
}
// 执行导出
ExportResult result = CreoManager::Instance().ExportModelToSTEP(export_path, geom_flags);
HttpResponse response;
if (result.success) {
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"exportPath\": \"" << result.export_path << "\","
<< "\"fileSize\": \"" << result.file_size << "\","
<< "\"format\": \"" << result.format << "\","
<< "\"exportTime\": \"" << result.export_time << "\","
<< "\"software\": \"" << result.software << "\","
<< "\"originalFile\": \"" << result.original_file << "\","
<< "\"details\": {"
<< "\"dirname\": \"" << result.dirname << "\","
<< "\"filename\": \"" << result.filename << "\","
<< "\"creoson_response\": {"
<< "\"dirname\": \"" << result.dirname << "\","
<< "\"filename\": \"" << result.filename << "\","
<< "\"full_path\": \"" << result.export_path << "\""
<< "}" // 结束 creoson_response
<< "}" // 结束 details
<< "}," // 结束 data
<< "\"error\": null"
<< "}";
response.body = json.str();
} else {
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"" << result.error_message << "\""
<< "}";
response.body = json.str();
response.status_code = 500;
}
return response;
}
// JSON字符串转义函数
std::string EscapeJsonString(const std::string& str) {
std::string escaped = str;
// 替换反斜杠
size_t pos = 0;
while ((pos = escaped.find("\\", pos)) != std::string::npos) {
escaped.replace(pos, 1, "\\\\");
pos += 2;
}
// 替换双引号
pos = 0;
while ((pos = escaped.find("\"", pos)) != std::string::npos) {
escaped.replace(pos, 1, "\\\"");
pos += 2;
}
// 替换换行符
pos = 0;
while ((pos = escaped.find("\n", pos)) != std::string::npos) {
escaped.replace(pos, 1, "\\n");
pos += 2;
}
// 替换制表符
pos = 0;
while ((pos = escaped.find("\t", pos)) != std::string::npos) {
escaped.replace(pos, 1, "\\t");
pos += 2;
}
return escaped;
}
// JSON数组解析函数
std::vector<std::string> ExtractJsonArray(const std::string& json, const std::string& key) {
std::vector<std::string> result;
try {
// 查找键值对 "key": [...]
std::string key_pattern = "\"" + key + "\"";
size_t key_pos = json.find(key_pattern);
if (key_pos != std::string::npos) {
// 找到冒号
size_t colon_pos = json.find(":", key_pos);
if (colon_pos != std::string::npos) {
// 跳过空格找到数组开始
size_t array_start = colon_pos + 1;
while (array_start < json.length() && (json[array_start] == ' ' || json[array_start] == '\t' || json[array_start] == '\n' || json[array_start] == '\r')) {
array_start++;
}
// 检查是否是数组(以方括号开始)
if (array_start < json.length() && json[array_start] == '[') {
size_t array_end = json.find(']', array_start);
if (array_end != std::string::npos) {
std::string array_content = json.substr(array_start + 1, array_end - array_start - 1);
// 解析数组中的字符串元素
size_t pos = 0;
while (pos < array_content.length()) {
// 跳过空格和逗号
while (pos < array_content.length() && (array_content[pos] == ' ' || array_content[pos] == '\t' || array_content[pos] == '\n' || array_content[pos] == '\r' || array_content[pos] == ',')) {
pos++;
}
// 查找字符串开始
if (pos < array_content.length() && array_content[pos] == '"') {
size_t str_start = pos + 1;
size_t str_end = array_content.find('"', str_start);
if (str_end != std::string::npos) {
std::string element = array_content.substr(str_start, str_end - str_start);
if (!element.empty()) {
result.push_back(element);
}
pos = str_end + 1;
} else {
break;
}
} else {
break;
}
}
}
}
}
}
} catch (...) {
// 解析失败,返回空数组
}
return result;
}
// 按路径删除组件处理器
HttpResponse PathDeleteHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求参数
PathDeleteManager::PathDeleteRequest delete_request;
delete_request.software_type = ExtractJsonValue(request.body, "software_type");
delete_request.component_paths = ExtractJsonArray(request.body, "component_paths");
std::string force_delete_str = ExtractJsonValue(request.body, "force_delete");
delete_request.force_delete = (force_delete_str == "true");
// 参数验证
if (delete_request.software_type.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
return response;
}
if (delete_request.software_type != "creo") {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
return response;
}
if (delete_request.component_paths.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameter: component_paths\"}";
return response;
}
// 执行按路径删除
PathDeleteManager::PathDeleteResult result = PathDeleteManager::Instance().DeleteComponentsByPaths(delete_request);
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"successfully_deleted\": [";
// 构建成功删除列表
for (size_t i = 0; i < result.successfully_deleted.size(); i++) {
if (i > 0) json << ",";
json << "\"" << EscapeJsonString(result.successfully_deleted[i]) << "\"";
}
json << "],"
<< "\"failed_to_delete\": [";
// 构建失败删除列表
for (size_t i = 0; i < result.failed_to_delete.size(); i++) {
if (i > 0) json << ",";
json << "\"" << EscapeJsonString(result.failed_to_delete[i]) << "\"";
}
json << "],"
<< "\"deletion_summary\": {"
<< "\"total_requested\": " << result.total_requested << ","
<< "\"successful\": " << result.successful << ","
<< "\"failed\": " << result.failed
<< "},"
<< "\"deletion_reasons\": {";
// 构建删除原因映射
bool first_reason = true;
for (const auto& reason_pair : result.deletion_reasons) {
if (!first_reason) json << ",";
first_reason = false;
json << "\"" << EscapeJsonString(reason_pair.first) << "\": \""
<< EscapeJsonString(reason_pair.second) << "\"";
}
json << "}"
<< "},"
<< "\"error\": null"
<< "}";
response.status_code = 200;
response.body = json.str();
} else {
// 构建失败响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": {"
<< "\"successfully_deleted\": [],"
<< "\"failed_to_delete\": [";
// 构建失败删除列表
for (size_t i = 0; i < result.failed_to_delete.size(); i++) {
if (i > 0) json << ",";
json << "\"" << EscapeJsonString(result.failed_to_delete[i]) << "\"";
}
json << "],"
<< "\"deletion_summary\": {"
<< "\"total_requested\": " << result.total_requested << ","
<< "\"successful\": " << result.successful << ","
<< "\"failed\": " << result.failed
<< "},"
<< "\"deletion_reasons\": {";
// 构建删除原因映射
bool first_reason = true;
for (const auto& reason_pair : result.deletion_reasons) {
if (!first_reason) json << ",";
first_reason = false;
json << "\"" << EscapeJsonString(reason_pair.first) << "\": \""
<< EscapeJsonString(reason_pair.second) << "\"";
}
json << "}"
<< "},"
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
<< "}";
response.status_code = 500;
response.body = json.str();
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"Request processing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"Unknown error during path deletion\"}";
}
return response;
}
// 层级分析路由处理器
HttpResponse HierarchyAnalysisHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求
HierarchyAnalysisRequest analysis_request;
// 简单的JSON解析参考现有的ExtractJsonValue方法
analysis_request.software_type = ExtractJsonValue(request.body, "software_type");
analysis_request.project_name = ExtractJsonValue(request.body, "project_name");
analysis_request.include_geometry = ExtractJsonValue(request.body, "include_geometry") == "true";
// 解析max_depth参数保持兼容性但不实际使用
std::string max_depth_str = ExtractJsonValue(request.body, "max_depth");
if (!max_depth_str.empty()) {
try {
analysis_request.max_depth = std::stoi(max_depth_str);
} catch (...) {
analysis_request.max_depth = 0; // 0表示无限制
}
} else {
analysis_request.max_depth = 0; // 0表示无限制
}
// 执行层级分析
HierarchyAnalysisResult result = CreoManager::Instance().AnalyzeModelHierarchy(analysis_request);
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"message\": \"" << result.message << "\","
<< "\"data\": {"
<< "\"project_name\": \"" << EscapeJsonString(result.project_name) << "\","
<< "\"total_levels\": " << result.total_levels << ","
<< "\"total_components\": " << result.total_components << ","
<< "\"hierarchy\": [";
// 构建层级数据
for (size_t level = 0; level < result.hierarchy.size(); level++) {
if (level > 0) json << ",";
json << "{"
<< "\"level\": " << level << ","
<< "\"name\": \"" << (level == 0 ? "Main Assembly" :
level == 1 ? "Sub Assembly" :
level == 2 ? "Parts" :
"Level " + std::to_string(level + 1) + " Components") << "\","
<< "\"components\": [";
for (size_t comp = 0; comp < result.hierarchy[level].size(); comp++) {
if (comp > 0) json << ",";
const ComponentInfo& component = result.hierarchy[level][comp];
json << "{"
<< "\"id\": \"" << EscapeJsonString(component.id) << "\","
<< "\"name\": \"" << EscapeJsonString(component.name) << "\","
<< "\"type\": \"" << EscapeJsonString(component.type) << "\","
<< "\"level\": " << component.level << ","
<< "\"children_count\": " << component.children_count << ","
<< "\"path\": \"" << EscapeJsonString(component.full_path) << "\","
<< "\"file_size\": \"" << EscapeJsonString(component.file_size) << "\","
<< "\"deletion_safety\": \"" << EscapeJsonString(component.deletion_safety) << "\""
<< "}";
}
json << "]}";
}
json << "],"
<< "\"deletion_recommendations\": {"
<< "\"safe_deletions\": [],"
<< "\"risky_deletions\": [";
// 构建删除建议
for (size_t i = 0; i < result.risky_deletions.size(); i++) {
if (i > 0) json << ",";
const DeletionRecommendation& rec = result.risky_deletions[i];
json << "{"
<< "\"component_id\": \"" << EscapeJsonString(rec.component_id) << "\","
<< "\"component_name\": \"" << EscapeJsonString(rec.component_name) << "\","
<< "\"level\": " << rec.level << ","
<< "\"reason\": \"" << EscapeJsonString(rec.reason) << "\","
<< "\"risk_factors\": [";
for (size_t j = 0; j < rec.risk_factors.size(); j++) {
if (j > 0) json << ",";
json << "\"" << EscapeJsonString(rec.risk_factors[j]) << "\"";
}
json << "],"
<< "\"confidence\": " << rec.confidence
<< "}";
}
json << "]"
<< "}"
<< "}"
<< "}";
response.body = json.str();
} else {
// 构建失败响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"" << result.error_message << "\""
<< "}";
response.body = json.str();
response.status_code = 500;
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy analysis\"}";
}
return response;
}
// 层级删除路由处理器
HttpResponse HierarchyDeleteHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求
std::string software_type = ExtractJsonValue(request.body, "software_type");
std::string project_name = ExtractJsonValue(request.body, "project_name");
std::string target_level_str = ExtractJsonValue(request.body, "target_level");
if (software_type.empty() || project_name.empty() || target_level_str.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameters: software_type, project_name, target_level\"}";
return response;
}
int target_level;
try {
target_level = std::stoi(target_level_str);
} catch (...) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid target_level parameter\"}";
return response;
}
// 执行层级删除
CreoManager::HierarchyDeleteResult result = CreoManager::Instance().DeleteHierarchyComponents(project_name, target_level);
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"message\": \"" << EscapeJsonString(result.message) << "\","
<< "\"data\": {"
<< "\"original_levels\": " << result.original_levels << ","
<< "\"target_level\": " << result.target_level << ","
<< "\"final_levels\": " << result.final_levels << ","
<< "\"deleted_components\": {";
// 构建删除组件数据
bool first_level = true;
for (const auto& level_pair : result.deleted_components) {
if (!first_level) json << ",";
first_level = false;
json << "\"level_" << level_pair.first << "\": [";
bool first_component = true;
for (const auto& component : level_pair.second) {
if (!first_component) json << ",";
first_component = false;
json << "\"" << EscapeJsonString(component) << "\"";
}
json << "]";
}
json << "},"
<< "\"deletion_summary\": {"
<< "\"total_deleted\": " << result.total_deleted << ","
<< "\"successful\": " << result.successful << ","
<< "\"failed\": " << result.failed
<< "}"
<< "},"
<< "\"error\": null"
<< "}";
response.body = json.str();
} else {
// 构建错误响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"message\": \"" << EscapeJsonString(result.message) << "\","
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
<< "}";
response.status_code = 500;
response.body = json.str();
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy deletion\"}";
}
return response;
}
// 薄壳化分析处理器
HttpResponse ShellAnalysisHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求参数
CreoManager::ShellAnalysisRequest analysis_request;
// 必填参数
analysis_request.software_type = ExtractJsonValue(request.body, "software_type");
if (analysis_request.software_type.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
return response;
}
if (analysis_request.software_type != "creo") {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
return response;
}
// 可选参数解析
std::string project_name = ExtractJsonValue(request.body, "projectName");
if (!project_name.empty()) {
analysis_request.project_name = project_name;
}
std::string analysis_type = ExtractJsonValue(request.body, "analysisType");
if (!analysis_type.empty()) {
analysis_request.analysis_type = analysis_type;
}
std::string preserve_external = ExtractJsonValue(request.body, "preserveExternalSurfaces");
if (!preserve_external.empty()) {
analysis_request.preserve_external_surfaces = (preserve_external == "true");
}
std::string min_thickness = ExtractJsonValue(request.body, "minWallThickness");
if (!min_thickness.empty()) {
try {
analysis_request.min_wall_thickness = std::stod(min_thickness);
} catch (...) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid minWallThickness parameter\"}";
return response;
}
}
std::string confidence = ExtractJsonValue(request.body, "confidenceThreshold");
if (!confidence.empty()) {
try {
analysis_request.confidence_threshold = std::stod(confidence);
if (analysis_request.confidence_threshold < 0.0 || analysis_request.confidence_threshold > 1.0) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"confidenceThreshold must be between 0.0 and 1.0\"}";
return response;
}
} catch (...) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid confidenceThreshold parameter\"}";
return response;
}
}
// 执行薄壳化分析
CreoManager::ShellAnalysisResult result = CreoManager::Instance().AnalyzeShellFeatures(analysis_request);
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"safeDeletions\": [";
// 构建安全删除列表
bool first_item = true;
for (const auto& deletion : result.safe_deletions) {
if (!first_item) json << ",";
first_item = false;
json << "{"
<< "\"id\": " << deletion.id << ","
<< "\"name\": \"" << EscapeJsonString(deletion.name) << "\","
<< "\"type\": \"" << EscapeJsonString(deletion.type) << "\","
<< "\"reason\": \"" << EscapeJsonString(deletion.reason) << "\","
<< "\"confidence\": " << deletion.confidence << ","
<< "\"volumeReduction\": " << deletion.volume_reduction;
if (!deletion.part_file.empty()) {
json << ",\"partFile\": \"" << EscapeJsonString(deletion.part_file) << "\"";
}
if (!deletion.part_path.empty()) {
json << ",\"partPath\": \"" << EscapeJsonString(deletion.part_path) << "\"";
}
json << ",\"componentType\": \"" << EscapeJsonString(deletion.component_type) << "\""
<< "}";
}
json << "],"
<< "\"suggestedDeletions\": [";
// 构建建议删除列表
first_item = true;
for (const auto& deletion : result.suggested_deletions) {
if (!first_item) json << ",";
first_item = false;
json << "{"
<< "\"id\": " << deletion.id << ","
<< "\"name\": \"" << EscapeJsonString(deletion.name) << "\","
<< "\"type\": \"" << EscapeJsonString(deletion.type) << "\","
<< "\"reason\": \"" << EscapeJsonString(deletion.reason) << "\","
<< "\"confidence\": " << deletion.confidence << ","
<< "\"volumeReduction\": " << deletion.volume_reduction
<< "}";
}
json << "],"
<< "\"preserveList\": [";
// 构建保留列表
first_item = true;
for (const auto& preserve : result.preserve_list) {
if (!first_item) json << ",";
first_item = false;
json << "{"
<< "\"id\": " << preserve.id << ","
<< "\"name\": \"" << EscapeJsonString(preserve.name) << "\","
<< "\"type\": \"" << EscapeJsonString(preserve.type) << "\","
<< "\"reason\": \"" << EscapeJsonString(preserve.reason) << "\","
<< "\"confidence\": " << preserve.confidence << ","
<< "\"volumeReduction\": " << preserve.volume_reduction
<< "}";
}
json << "],"
<< "\"estimatedReduction\": {"
<< "\"volumeReduction\": \"" << EscapeJsonString(result.estimated_reduction.volume_reduction) << "\","
<< "\"fileSizeReduction\": \"" << EscapeJsonString(result.estimated_reduction.file_size_reduction) << "\","
<< "\"performanceImprovement\": \"" << EscapeJsonString(result.estimated_reduction.performance_improvement) << "\""
<< "},"
<< "\"analysisParameters\": {"
<< "\"preserveExternalSurfaces\": " << (result.analysis_parameters.preserve_external_surfaces ? "true" : "false") << ","
<< "\"minWallThickness\": " << result.analysis_parameters.min_wall_thickness << ","
<< "\"confidenceThreshold\": " << result.analysis_parameters.confidence_threshold << ","
<< "\"totalFeatures\": " << result.analysis_parameters.total_features << ","
<< "\"deletableFeatures\": " << result.analysis_parameters.deletable_features << ","
<< "\"preservedFeatures\": " << result.analysis_parameters.preserved_features << ","
<< "\"assemblyAnalysis\": " << (result.analysis_parameters.assembly_analysis ? "true" : "false") << ","
<< "\"analysisStrategy\": \"" << EscapeJsonString(result.analysis_parameters.analysis_strategy) << "\","
<< "\"surfaceCount\": " << result.analysis_parameters.surface_count << ","
<< "\"shellSurfaces\": " << result.analysis_parameters.shell_surfaces << ","
<< "\"internalSurfaces\": " << result.analysis_parameters.internal_surfaces << ","
<< "\"shellFeatureWhitelist\": " << result.analysis_parameters.shell_feature_whitelist;
// 添加层次分析信息
if (result.analysis_parameters.hierarchy_analysis.enabled) {
json << ","
<< "\"hierarchyAnalysis\": {"
<< "\"enabled\": true,"
<< "\"totalParts\": " << result.analysis_parameters.hierarchy_analysis.total_parts << ","
<< "\"outerParts\": " << result.analysis_parameters.hierarchy_analysis.outer_parts << ","
<< "\"internalParts\": " << result.analysis_parameters.hierarchy_analysis.internal_parts << ","
<< "\"containmentRelationships\": " << result.analysis_parameters.hierarchy_analysis.containment_relationships << ","
<< "\"performanceStats\": {";
bool first_stat = true;
for (const auto& stat : result.analysis_parameters.hierarchy_analysis.performance_stats) {
if (!first_stat) json << ",";
first_stat = false;
json << "\"" << EscapeJsonString(stat.first) << "\": \"" << EscapeJsonString(stat.second) << "\"";
}
json << "}"
<< "}";
}
json << "}," // 结束 hierarchyAnalysis (加逗号)
<< "}," // 结束 analysisParameters (加逗号)
<< "\"error\": null"
<< "}";
response.body = json.str();
} else {
// 构建错误响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
<< "}";
response.status_code = 500;
response.body = json.str();
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during shell analysis\"}";
}
return response;
}
// 保存模型路由处理器
HttpResponse SaveModelHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求参数
std::string software_type = ExtractJsonValue(request.body, "software_type");
// 参数验证
if (software_type.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
return response;
}
if (software_type != "creo") {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
return response;
}
// 执行保存操作
SaveResult result = CreoManager::Instance().SaveModel();
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"file_size\": \"" << EscapeJsonString(result.file_size) << "\","
<< "\"save_time\": \"" << EscapeJsonString(result.save_time) << "\","
<< "\"software\": \"" << EscapeJsonString(result.software) << "\","
<< "\"original_file\": \"" << EscapeJsonString(result.original_file) << "\""
<< "},"
<< "\"error\": null"
<< "}";
response.body = json.str();
} else {
// 构建错误响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
<< "}";
response.status_code = 500;
response.body = json.str();
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during save operation\"}";
}
return response;
}
// 关闭模型路由处理器
HttpResponse CloseModelHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求参数
std::string software_type = ExtractJsonValue(request.body, "software_type");
std::string force_close_str = ExtractJsonValue(request.body, "force_close");
// 参数验证
if (software_type.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
return response;
}
if (software_type != "creo") {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
return response;
}
// 解析force_close参数
bool force_close = (force_close_str == "true");
// 执行关闭操作
CloseResult result = CreoManager::Instance().CloseModel(force_close);
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\","
<< "\"was_modified\": " << (result.was_modified ? "true" : "false") << ","
<< "\"close_time\": \"" << EscapeJsonString(result.close_time) << "\""
<< "},"
<< "\"error\": null"
<< "}";
response.body = json.str();
} else {
// 构建错误响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
<< "}";
response.status_code = 500;
response.body = json.str();
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during close operation\"}";
}
return response;
}
// 打开模型路由处理器
HttpResponse OpenModelHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 解析JSON请求参数
std::string software_type = ExtractJsonValue(request.body, "software_type");
std::string file_path = ExtractJsonValue(request.body, "file_path");
std::string dirname = ExtractJsonValue(request.body, "dirname");
std::string filename = ExtractJsonValue(request.body, "filename");
std::string open_mode = ExtractJsonValue(request.body, "open_mode");
// 参数验证
if (software_type.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
return response;
}
// 支持两种路径格式完整路径或分离的dirname+filename
if (file_path.empty()) {
if (dirname.empty() || filename.empty()) {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Missing required parameters: either 'file_path' or both 'dirname' and 'filename'\"}";
return response;
}
// 组合dirname和filename为完整路径creoson风格
file_path = dirname + "/" + filename;
}
if (software_type != "creo") {
response.status_code = 400;
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
return response;
}
// 设置默认打开模式
if (open_mode.empty()) {
open_mode = "active";
}
// 使用无锁消息机制
MessageItem open_message_item;
open_message_item.type = "OPEN_MODEL_REQUEST";
open_message_item.data = file_path;
open_message_item.extra = open_mode;
// 原子设置(无锁)
pending_message_item = &open_message_item;
has_pending_item = true;
// 等待主线程完成操作(带超时)
int timeout_ms = 10000; // 10秒超时
while (!open_message_item.completed && timeout_ms > 0) {
Sleep(50);
timeout_ms -= 50;
}
OpenResult result;
if (open_message_item.completed && open_message_item.result_ptr) {
result = *static_cast<OpenResult*>(open_message_item.result_ptr);
delete static_cast<OpenResult*>(open_message_item.result_ptr); // 清理内存
} else {
// 超时处理
result.success = false;
result.error_message = "Operation timeout: OpenModel took too long to complete";
}
if (result.success) {
// 构建成功响应
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"data\": {"
<< "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\","
<< "\"model_type\": \"" << EscapeJsonString(result.model_type) << "\","
<< "\"file_path\": \"" << EscapeJsonString(result.file_path) << "\","
<< "\"file_size\": \"" << EscapeJsonString(result.file_size) << "\","
<< "\"open_time\": \"" << EscapeJsonString(result.open_time) << "\","
<< "\"is_assembly\": " << (result.is_assembly ? "true" : "false") << ","
<< "\"total_parts\": " << result.total_parts << ","
<< "\"model_in_session\": " << (result.model_in_session ? "true" : "false") << ","
<< "\"window_model_match\": " << (result.window_model_match ? "true" : "false")
<< "},"
<< "\"error\": null"
<< "}";
response.body = json.str();
} else {
// 构建错误响应
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"data\": null,"
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
<< "}";
response.status_code = 500;
response.body = json.str();
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during open operation\"}";
}
return response;
}
// Shrinkwrap外壳导出路由处理器
HttpResponse ShrinkwrapShellHandler(const HttpRequest& request) {
HttpResponse response;
if (request.method != "POST") {
response.status_code = 405;
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
return response;
}
try {
// 使用无锁消息机制
MessageItem shrinkwrap_message_item;
shrinkwrap_message_item.type = "SHRINKWRAP_SHELL_REQUEST";
shrinkwrap_message_item.data = request.body;
// 原子设置(无锁)
pending_message_item = &shrinkwrap_message_item;
has_pending_item = true;
// 等待主线程完成操作(带超时)
int timeout_ms = 30000; // 30秒超时Shrinkwrap操作可能需要更长时间
while (!shrinkwrap_message_item.completed && timeout_ms > 0) {
Sleep(100); // 稍长的间隔因为Shrinkwrap是重操作
timeout_ms -= 100;
}
if (shrinkwrap_message_item.completed && shrinkwrap_message_item.result_ptr) {
HttpResponse result = *static_cast<HttpResponse*>(shrinkwrap_message_item.result_ptr);
delete static_cast<HttpResponse*>(shrinkwrap_message_item.result_ptr); // 清理内存
return result;
} else {
// 超时处理
response.status_code = 504;
response.body = "{\"success\": false, \"error\": \"Operation timeout: Shrinkwrap export took too long to complete\"}";
return response;
}
} catch (const std::exception& e) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"Request processing error: " + std::string(e.what()) + "\"}";
} catch (...) {
response.status_code = 500;
response.body = "{\"success\": false, \"error\": \"Unknown error during shrinkwrap shell export\"}";
}
return response;
}
extern "C" int user_initialize(
int argc,
char* argv[],
char* version,
char* build,
wchar_t errbuf[80])
{
pfcSession_ptr Session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
wfcWSession_ptr wSession = wfcWSession::cast(Session);
xstring info = L"New HTTP Server Starting on port 12345";
wSession->UIShowMessageDialog(info, NULL);
// 启动定时器处理消息
timer_id = SetTimer(NULL, 0, 100, TimerProc);
// 创建并启动HTTP服务器
g_http_server = std::make_unique<HttpServer>();
// 设置路由
g_http_server->SetRouteHandler("/test", TestHandler);
g_http_server->SetRouteHandler("/show_message", ShowMessageHandler);
g_http_server->SetRouteHandler("/api/status/creo", CreoStatusHandler);
g_http_server->SetRouteHandler("/api/status/model", ModelStatusHandler);
g_http_server->SetRouteHandler("/api/export/model", ExportModelHandler);
g_http_server->SetRouteHandler("/api/creo/analysis/hierarchy", HierarchyAnalysisHandler);
g_http_server->SetRouteHandler("/api/creo/hierarchy/delete", HierarchyDeleteHandler);
g_http_server->SetRouteHandler("/api/analysis/shell-analysis", ShellAnalysisHandler);
g_http_server->SetRouteHandler("/api/model/save", SaveModelHandler);
g_http_server->SetRouteHandler("/api/model/close", CloseModelHandler);
g_http_server->SetRouteHandler("/api/model/open", OpenModelHandler);
g_http_server->SetRouteHandler("/api/creo/shrinkwrap/shell", ShrinkwrapShellHandler);
g_http_server->SetRouteHandler("/api/creo/component/delete-by-path", PathDeleteHandler);
if (g_http_server->Start()) {
return 0;
} else {
g_http_server.reset();
return 1;
}
}
// --- OTK 出口函数 ---
// 这个函数在卸载插件或关闭 Creo 时被调用,非常重要!
extern "C" void user_terminate()
{
if (g_http_server) {
g_http_server->Stop();
g_http_server.reset();
}
if (timer_id != 0) {
KillTimer(NULL, timer_id);
timer_id = 0;
}
}