diff --git a/CreoManager.cpp b/CreoManager.cpp index bcb1980..85f8d77 100644 --- a/CreoManager.cpp +++ b/CreoManager.cpp @@ -499,9 +499,9 @@ std::string CreoManager::GetFileSize(const std::string& filepath) { size.LowPart = fileInfo.nFileSizeLow; double file_size_mb = static_cast(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(); } diff --git a/CreoUtilities.cpp b/CreoUtilities.cpp new file mode 100644 index 0000000..d23bc05 --- /dev/null +++ b/CreoUtilities.cpp @@ -0,0 +1,212 @@ +#include "pch.h" +#include "CreoUtilities.h" +#include +#include +#include + +// 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(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(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; +} diff --git a/CreoUtilities.h b/CreoUtilities.h new file mode 100644 index 0000000..481829e --- /dev/null +++ b/CreoUtilities.h @@ -0,0 +1,47 @@ +#pragma once + +// Creo OTK headers +#include +#include +#include +#include + +// Standard library headers +#include +#include + +// 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); +}; diff --git a/MFCCreoDll.vcxproj b/MFCCreoDll.vcxproj index b922c07..6b092cd 100644 --- a/MFCCreoDll.vcxproj +++ b/MFCCreoDll.vcxproj @@ -209,6 +209,7 @@ ws2_32.lib;%(AdditionalDependencies) + @@ -240,6 +241,7 @@ ws2_32.lib;%(AdditionalDependencies) + diff --git a/MFCCreoDll.vcxproj.filters b/MFCCreoDll.vcxproj.filters index d1b8de4..c08c2a0 100644 --- a/MFCCreoDll.vcxproj.filters +++ b/MFCCreoDll.vcxproj.filters @@ -93,6 +93,9 @@ 源文件\src\creo + + 源文件\src\utils + @@ -178,6 +181,9 @@ 源文件\src\creo + + 源文件\src\utils +