feat: add CreoUtilities class for working directory management
Implement SetWorkingDirectory method with OTK API integration: - GetCurrentDirectory() to retrieve current path - ChangeDirectory() to switch working directory - Intelligent comparison: only changes if target differs from current - Path normalization for Windows (case-insensitive, backslash handling) - Comprehensive error handling with detailed result structure Also includes minor code cleanup in CreoManager.cpp formatting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d5f87e5457
commit
a02b68c7e3
@ -499,9 +499,9 @@ std::string CreoManager::GetFileSize(const std::string& filepath) {
|
||||
size.LowPart = fileInfo.nFileSizeLow;
|
||||
|
||||
double file_size_mb = static_cast<double>(size.QuadPart) / (1024.0 * 1024.0);
|
||||
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(1) << file_size_mb << "MB";
|
||||
oss << file_size_mb << "MB";
|
||||
return oss.str();
|
||||
} else {
|
||||
DWORD error = GetLastError();
|
||||
@ -674,8 +674,9 @@ std::string CreoManager::CalculateAssemblyTotalSize(pfcModel_ptr model) {
|
||||
|
||||
// 转换为MB并返回
|
||||
double total_mb = total_size_bytes / (1024.0 * 1024.0);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(1) << total_mb << "MB (from " << processed_count << " files)";
|
||||
oss << total_mb << "MB (from " << processed_count << " files)";
|
||||
return oss.str();
|
||||
|
||||
}
|
||||
|
||||
212
CreoUtilities.cpp
Normal file
212
CreoUtilities.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
#include "pch.h"
|
||||
#include "CreoUtilities.h"
|
||||
#include <windows.h>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
|
||||
// Set Creo working directory
|
||||
ChangeDirectoryResult CreoUtilities::SetWorkingDirectory(const std::string& target_directory) {
|
||||
ChangeDirectoryResult result;
|
||||
result.target_directory = target_directory;
|
||||
|
||||
try {
|
||||
// Validate input
|
||||
if (target_directory.empty()) {
|
||||
result.success = false;
|
||||
result.error_message = "Target directory cannot be empty";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get Creo session
|
||||
pfcSession_ptr session = nullptr;
|
||||
try {
|
||||
session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
|
||||
} catch (...) {
|
||||
session = nullptr;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
result.success = false;
|
||||
result.error_message = "Failed to get Creo session. Creo may not be running.";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get current working directory
|
||||
xstring current_dir_xstr;
|
||||
try {
|
||||
current_dir_xstr = session->GetCurrentDirectory();
|
||||
result.original_directory = XStringToString(current_dir_xstr);
|
||||
} catch (...) {
|
||||
result.success = false;
|
||||
result.error_message = "Failed to get current directory";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Normalize and compare paths
|
||||
std::string normalized_current = NormalizePath(result.original_directory);
|
||||
std::string normalized_target = NormalizePath(target_directory);
|
||||
|
||||
// Check if directories are the same
|
||||
if (PathsAreEqual(normalized_current, normalized_target)) {
|
||||
// Already at target directory, no change needed
|
||||
result.success = true;
|
||||
result.directory_changed = false;
|
||||
result.current_directory = result.original_directory;
|
||||
result.message = "Already at target directory, no change needed";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Directories are different, need to change
|
||||
try {
|
||||
xstring target_dir_xstr = StringToXString(target_directory);
|
||||
session->ChangeDirectory(target_dir_xstr);
|
||||
} catch (...) {
|
||||
result.success = false;
|
||||
result.error_message = "Failed to change directory (directory may not exist or is invalid)";
|
||||
result.current_directory = result.original_directory;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Verify the change by reading current directory again
|
||||
try {
|
||||
xstring new_dir_xstr = session->GetCurrentDirectory();
|
||||
result.current_directory = XStringToString(new_dir_xstr);
|
||||
} catch (...) {
|
||||
result.current_directory = target_directory; // Assume success if we can't verify
|
||||
}
|
||||
|
||||
// Check if change was successful
|
||||
std::string normalized_new = NormalizePath(result.current_directory);
|
||||
if (PathsAreEqual(normalized_new, normalized_target)) {
|
||||
result.success = true;
|
||||
result.directory_changed = true;
|
||||
result.message = "Working directory changed successfully";
|
||||
} else {
|
||||
result.success = false;
|
||||
result.directory_changed = false;
|
||||
result.error_message = "Directory change operation completed but verification failed";
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
result.success = false;
|
||||
result.error_message = std::string("Unexpected exception: ") + e.what();
|
||||
result.current_directory = result.original_directory;
|
||||
} catch (...) {
|
||||
result.success = false;
|
||||
result.error_message = "Unexpected unknown exception occurred";
|
||||
result.current_directory = result.original_directory;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert xstring to std::string
|
||||
std::string CreoUtilities::XStringToString(const xstring& xstr) {
|
||||
try {
|
||||
// Check for null xstring
|
||||
if (xstr.IsNull()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::wstring wstr(xstr);
|
||||
if (wstr.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Length check to prevent memory issues
|
||||
if (wstr.length() > 32767) { // Windows API limit
|
||||
return "";
|
||||
}
|
||||
|
||||
// Use WideCharToMultiByte for proper UTF-8 encoding conversion
|
||||
int wstr_len = static_cast<int>(wstr.length());
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr_len, NULL, 0, NULL, NULL);
|
||||
if (size_needed <= 0 || size_needed > 65535) { // Safety boundary check
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string result(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr_len, &result[0], size_needed, NULL, NULL);
|
||||
|
||||
return result;
|
||||
} catch (...) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Convert std::string to xstring
|
||||
xstring CreoUtilities::StringToXString(const std::string& str) {
|
||||
try {
|
||||
if (str.empty()) {
|
||||
return xstring();
|
||||
}
|
||||
|
||||
// Length check to prevent memory issues
|
||||
if (str.length() > 65535) { // Reasonable length limit
|
||||
return xstring();
|
||||
}
|
||||
|
||||
// Validate input string for invalid characters
|
||||
for (char c : str) {
|
||||
if (c == '\0' && &c != &str.back()) { // Null character in the middle
|
||||
return xstring();
|
||||
}
|
||||
}
|
||||
|
||||
// Use MultiByteToWideChar for proper UTF-8 decoding conversion
|
||||
int str_len = static_cast<int>(str.length());
|
||||
int size_needed = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), str_len, NULL, 0);
|
||||
if (size_needed <= 0 || size_needed > 32767) { // Safety boundary check
|
||||
return xstring();
|
||||
}
|
||||
|
||||
std::wstring wstr(size_needed, 0);
|
||||
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), str_len, &wstr[0], size_needed);
|
||||
|
||||
return xstring(wstr.c_str());
|
||||
} catch (...) {
|
||||
return xstring();
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize path for comparison
|
||||
std::string CreoUtilities::NormalizePath(const std::string& path) {
|
||||
if (path.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string normalized = path;
|
||||
|
||||
// Replace forward slashes with backslashes (Windows standard)
|
||||
std::replace(normalized.begin(), normalized.end(), '/', '\\');
|
||||
|
||||
// Remove trailing backslash if present (except for root paths like "C:\")
|
||||
if (normalized.length() > 3 && normalized.back() == '\\') {
|
||||
normalized.pop_back();
|
||||
}
|
||||
|
||||
// Convert to lowercase for case-insensitive comparison (Windows)
|
||||
std::transform(normalized.begin(), normalized.end(), normalized.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// Compare two paths for equality
|
||||
bool CreoUtilities::PathsAreEqual(const std::string& path1, const std::string& path2) {
|
||||
// Both empty
|
||||
if (path1.empty() && path2.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// One empty, one not
|
||||
if (path1.empty() || path2.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare normalized paths
|
||||
std::string norm1 = NormalizePath(path1);
|
||||
std::string norm2 = NormalizePath(path2);
|
||||
|
||||
return norm1 == norm2;
|
||||
}
|
||||
47
CreoUtilities.h
Normal file
47
CreoUtilities.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
// Creo OTK headers
|
||||
#include <pfcGlobal.h>
|
||||
#include <pfcSession.h>
|
||||
#include <wfcSession.h>
|
||||
#include <pfcExceptions.h>
|
||||
|
||||
// Standard library headers
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
// Working directory change result structure
|
||||
struct ChangeDirectoryResult {
|
||||
bool success = false;
|
||||
std::string original_directory; // Original working directory before operation
|
||||
std::string target_directory; // Target directory requested by user
|
||||
std::string current_directory; // Actual working directory after operation
|
||||
bool directory_changed = false; // Whether directory was actually changed
|
||||
std::string message; // Success message or informational text
|
||||
std::string error_message; // Error details if operation failed
|
||||
};
|
||||
|
||||
// Creo Utilities - Common utility functions for Creo operations
|
||||
class CreoUtilities {
|
||||
public:
|
||||
// Set Creo working directory
|
||||
// Only changes directory if target is different from current directory
|
||||
// Parameters:
|
||||
// target_directory - The desired working directory path
|
||||
// Returns:
|
||||
// ChangeDirectoryResult with detailed operation status
|
||||
static ChangeDirectoryResult SetWorkingDirectory(const std::string& target_directory);
|
||||
|
||||
private:
|
||||
// Private constructor - this is a static utility class
|
||||
CreoUtilities() = delete;
|
||||
~CreoUtilities() = delete;
|
||||
CreoUtilities(const CreoUtilities&) = delete;
|
||||
CreoUtilities& operator=(const CreoUtilities&) = delete;
|
||||
|
||||
// Helper methods for internal use
|
||||
static std::string XStringToString(const xstring& xstr);
|
||||
static xstring StringToXString(const std::string& str);
|
||||
static std::string NormalizePath(const std::string& path);
|
||||
static bool PathsAreEqual(const std::string& path1, const std::string& path2);
|
||||
};
|
||||
@ -209,6 +209,7 @@ ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ClCompile Include="AuthManager.cpp" />
|
||||
<ClCompile Include="ComponentChildrenManager.cpp" />
|
||||
<ClCompile Include="CreoManager.cpp" />
|
||||
<ClCompile Include="CreoUtilities.cpp" />
|
||||
<ClCompile Include="GeometryAnalyzer.cpp" />
|
||||
<ClCompile Include="HierarchyStatisticsAnalyzer.cpp" />
|
||||
<ClCompile Include="HttpRouter.cpp" />
|
||||
@ -240,6 +241,7 @@ ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ClInclude Include="ComponentChildrenManager.h" />
|
||||
<ClInclude Include="Config.h" />
|
||||
<ClInclude Include="CreoManager.h" />
|
||||
<ClInclude Include="CreoUtilities.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="GeometryAnalyzer.h" />
|
||||
<ClInclude Include="HierarchyStatisticsAnalyzer.h" />
|
||||
|
||||
@ -93,6 +93,9 @@
|
||||
<ClCompile Include="ComponentChildrenManager.cpp">
|
||||
<Filter>源文件\src\creo</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CreoUtilities.cpp">
|
||||
<Filter>源文件\src\utils</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="MFCCreoDll.def">
|
||||
@ -178,6 +181,9 @@
|
||||
<ClInclude Include="ComponentChildrenManager.h">
|
||||
<Filter>源文件\src\creo</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CreoUtilities.h">
|
||||
<Filter>源文件\src\utils</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MFCCreoDll.rc">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user