UP 彩色日志 动态界面 立即回收
parent
7b6c87f2b0
commit
0ab3543aa4
|
@ -28,6 +28,7 @@ public:
|
|||
char command_input[256]{};
|
||||
char send_command[256]{};
|
||||
bool auto_scroll_logs;
|
||||
bool enable_colored_logs;
|
||||
int max_log_lines;
|
||||
char web_url[256]{};
|
||||
|
||||
|
|
|
@ -45,6 +45,10 @@ public:
|
|||
void SetEnvironmentVariables(const std::map<std::string, std::string>& env_vars);
|
||||
void SetOutputEncoding(OutputEncoding encoding);
|
||||
|
||||
// 新增:工作目录设置
|
||||
void SetWorkingDirectory(const std::string& working_dir);
|
||||
std::string GetWorkingDirectory() const;
|
||||
|
||||
void Start(const std::string& command);
|
||||
void Stop();
|
||||
void Restart(const std::string& command);
|
||||
|
@ -69,6 +73,11 @@ public:
|
|||
static std::string GetEncodingName(OutputEncoding encoding);
|
||||
static std::vector<std::pair<OutputEncoding, std::string>> GetSupportedEncodings();
|
||||
|
||||
// 新增:工作目录相关静态方法
|
||||
static std::string ExtractDirectoryFromCommand(const std::string& command);
|
||||
static std::string GetAbsolutePath(const std::string& path);
|
||||
static bool DirectoryExists(const std::string& path);
|
||||
|
||||
private:
|
||||
void ReadOutput();
|
||||
void CloseProcessHandles();
|
||||
|
@ -117,6 +126,11 @@ private:
|
|||
// 编码相关
|
||||
mutable std::mutex encoding_mutex_;
|
||||
OutputEncoding output_encoding_;
|
||||
|
||||
// 新增:工作目录相关
|
||||
mutable std::mutex working_dir_mutex_;
|
||||
std::string working_directory_;
|
||||
bool use_auto_working_dir_;
|
||||
};
|
||||
|
||||
#endif // CLIPROCESS_H
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
#include "AppState.h"
|
||||
#include "TrayIcon.h"
|
||||
// 系统头文件
|
||||
#include <memory>
|
||||
|
||||
// 第三方库头文件
|
||||
#include "imgui.h"
|
||||
|
||||
// 平台相关头文件
|
||||
#ifdef USE_WIN32_BACKEND
|
||||
#include <d3d11.h>
|
||||
#include <windows.h>
|
||||
|
@ -26,86 +29,143 @@
|
|||
#include "imgui_impl_opengl3.h"
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
// 项目头文件
|
||||
#include "AppState.h"
|
||||
#include "TrayIcon.h"
|
||||
|
||||
class Manager {
|
||||
public:
|
||||
// 构造函数和析构函数
|
||||
Manager();
|
||||
~Manager();
|
||||
|
||||
bool Initialize();
|
||||
void Run();
|
||||
void Shutdown();
|
||||
// 核心生命周期管理
|
||||
bool Initialize(); // 初始化应用程序
|
||||
void Run(); // 运行主循环
|
||||
void Shutdown(); // 关闭应用程序
|
||||
|
||||
void OnTrayShowWindow();
|
||||
void OnTrayExit();
|
||||
|
||||
AppState m_app_state;
|
||||
// 托盘事件回调
|
||||
void OnTrayShowWindow(); // 托盘显示窗口事件
|
||||
void OnTrayExit(); // 托盘退出事件
|
||||
|
||||
// 公共成员变量
|
||||
AppState m_app_state; // 应用程序状态
|
||||
|
||||
private:
|
||||
// UI渲染
|
||||
void RenderUI();
|
||||
void RenderMenuBar();
|
||||
void RenderMainContent();
|
||||
void RenderSettingsMenu();
|
||||
void RenderStopCommandSettings();
|
||||
void RenderEnvironmentVariablesSettings();
|
||||
void RenderOutputEncodingSettings();
|
||||
// 枚举类型定义
|
||||
enum class LayoutPreset {
|
||||
Classic, // 经典布局
|
||||
Development, // 开发布局
|
||||
Monitoring // 监控布局
|
||||
};
|
||||
|
||||
// 事件处理
|
||||
void HandleMessages();
|
||||
bool ShouldExit() const;
|
||||
void ShowMainWindow();
|
||||
void HideMainWindow();
|
||||
// 结构体定义
|
||||
struct ColoredTextSegment {
|
||||
std::string text; // 文本内容
|
||||
ImVec4 color; // 文本颜色
|
||||
};
|
||||
|
||||
// 平台相关初始化
|
||||
// UI渲染相关方法
|
||||
void RenderUI(); // 渲染主UI
|
||||
void RenderMenuBar(); // 渲染菜单栏
|
||||
void RenderMainContent(); // 渲染主内容区域
|
||||
void RenderSettingsMenu(); // 渲染设置菜单
|
||||
void RenderStopCommandSettings(); // 渲染停止命令设置
|
||||
void RenderEnvironmentVariablesSettings(); // 渲染环境变量设置
|
||||
void RenderOutputEncodingSettings(); // 渲染输出编码设置
|
||||
void RenderControlPanel(float buttonWidth, float buttonHeight, float inputWidth); // 渲染控制面板
|
||||
void RenderCommandPanel(float buttonWidth, float inputWidth); // 渲染命令面板
|
||||
void RenderLogPanel(); // 渲染日志面板
|
||||
void RenderCommandHistory(); // 渲染命令历史
|
||||
void RenderStatusMessages(); // 渲染状态消息
|
||||
|
||||
// 布局管理相关方法
|
||||
void SetupDefaultDockingLayout(ImGuiID dockspace_id); // 设置默认停靠布局
|
||||
void RenderLayoutMenu(); // 渲染布局菜单
|
||||
static void ApplyPresetLayout(LayoutPreset preset); // 应用预设布局
|
||||
void SaveCurrentLayout(); // 保存当前布局
|
||||
void LoadSavedLayout(); // 加载已保存布局
|
||||
|
||||
// 日志颜色处理方法
|
||||
ImVec4 GetLogLevelColor(const std::string& log); // 获取日志级别颜色
|
||||
void RenderColoredLogLine(const std::string& log); // 渲染彩色日志行
|
||||
std::vector<ColoredTextSegment> ParseAnsiColorCodes(const std::string& text); // 解析ANSI颜色代码
|
||||
std::pair<ImVec4, bool> ParseAnsiColorCode(const std::string& code, const ImVec4& currentColor, bool currentBold); // 解析单个ANSI颜色代码
|
||||
ImVec4 GetAnsiColor(int colorIndex, bool bright); // 获取ANSI颜色
|
||||
|
||||
// 事件处理相关方法
|
||||
void HandleMessages(); // 处理消息
|
||||
bool ShouldExit() const; // 检查是否应该退出
|
||||
static void ContentScaleCallback(GLFWwindow *window, float xscale, float yscale); // 内容缩放回调
|
||||
|
||||
// 窗口管理相关方法
|
||||
void ShowMainWindow(); // 显示主窗口
|
||||
void HideMainWindow(); // 隐藏主窗口
|
||||
|
||||
// DPI相关方法
|
||||
void UpdateDPIScale(); // 更新DPI缩放
|
||||
void ReloadFonts() const; // 重新加载字体
|
||||
|
||||
// 平台相关初始化方法
|
||||
#ifdef USE_WIN32_BACKEND
|
||||
bool InitializeWin32();
|
||||
bool InitializeDirectX11();
|
||||
void CleanupWin32();
|
||||
void CleanupDirectX11();
|
||||
static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
HWND m_hwnd = nullptr;
|
||||
WNDCLASSEX m_wc = {};
|
||||
ID3D11Device* m_pd3dDevice = nullptr;
|
||||
ID3D11DeviceContext* m_pd3dDeviceContext = nullptr;
|
||||
IDXGISwapChain* m_pSwapChain = nullptr;
|
||||
ID3D11RenderTargetView* m_mainRenderTargetView = nullptr;
|
||||
bool InitializeWin32(); // 初始化Win32
|
||||
bool InitializeDirectX11(); // 初始化DirectX11
|
||||
void CleanupWin32(); // 清理Win32
|
||||
void CleanupDirectX11(); // 清理DirectX11
|
||||
static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // 窗口过程
|
||||
#else
|
||||
bool InitializeGLFW();
|
||||
void CleanupGLFW();
|
||||
static void GlfwErrorCallback(int error, const char* description);
|
||||
|
||||
GLFWwindow* m_window = nullptr;
|
||||
const char* m_glsl_version = nullptr;
|
||||
bool InitializeGLFW(); // 初始化GLFW
|
||||
void CleanupGLFW(); // 清理GLFW
|
||||
static void GlfwErrorCallback(int error, const char* description); // GLFW错误回调
|
||||
#endif
|
||||
|
||||
// 托盘相关
|
||||
bool InitializeTray();
|
||||
void CleanupTray();
|
||||
// 托盘相关方法
|
||||
bool InitializeTray(); // 初始化托盘
|
||||
void CleanupTray(); // 清理托盘
|
||||
#ifdef _WIN32
|
||||
static HWND CreateHiddenWindow();
|
||||
HWND m_tray_hwnd = nullptr;
|
||||
static HWND CreateHiddenWindow(); // 创建隐藏窗口
|
||||
#endif
|
||||
|
||||
std::unique_ptr<TrayIcon> m_tray;
|
||||
// 平台相关成员变量
|
||||
#ifdef USE_WIN32_BACKEND
|
||||
HWND m_hwnd = nullptr; // 窗口句柄
|
||||
WNDCLASSEX m_wc = {}; // 窗口类
|
||||
ID3D11Device* m_pd3dDevice = nullptr; // D3D11设备
|
||||
ID3D11DeviceContext* m_pd3dDeviceContext = nullptr; // D3D11设备上下文
|
||||
IDXGISwapChain* m_pSwapChain = nullptr; // 交换链
|
||||
ID3D11RenderTargetView* m_mainRenderTargetView = nullptr; // 主渲染目标视图
|
||||
#else
|
||||
GLFWwindow* m_window = nullptr; // GLFW窗口
|
||||
const char* m_glsl_version = nullptr; // GLSL版本
|
||||
#endif
|
||||
|
||||
// 托盘相关成员变量
|
||||
std::unique_ptr<TrayIcon> m_tray; // 托盘图标
|
||||
#ifdef _WIN32
|
||||
HWND m_tray_hwnd = nullptr; // 托盘窗口句柄
|
||||
#endif
|
||||
|
||||
// 控制标志
|
||||
bool m_should_exit = false;
|
||||
bool m_initialized = false;
|
||||
bool m_should_exit = false; // 是否应该退出
|
||||
bool m_initialized = false; // 是否已初始化
|
||||
|
||||
// DPI缩放因子
|
||||
float m_dpi_scale = 1.0f;
|
||||
// DPI缩放相关
|
||||
float m_dpi_scale = 1.0f; // 当前DPI缩放
|
||||
float m_last_dpi_scale = 1.0f; // 上次DPI缩放
|
||||
|
||||
// 环境变量UI状态
|
||||
char env_key_input_[256] = {};
|
||||
char env_value_input_[512] = {};
|
||||
bool show_env_settings_ = false;
|
||||
// 布局相关成员变量
|
||||
bool m_apply_preset_layout = false; // 是否需要应用预设布局
|
||||
LayoutPreset m_pending_preset = LayoutPreset::Classic; // 待应用的预设布局
|
||||
bool m_reset_layout = false; // 是否重置布局
|
||||
bool m_show_save_success = false; // 是否显示保存成功消息
|
||||
bool m_show_load_success = false; // 是否显示加载成功消息
|
||||
float m_save_success_timer = 0.0f; // 保存成功消息计时器
|
||||
float m_load_success_timer = 0.0f; // 加载成功消息计时器
|
||||
|
||||
// 编码设置UI状态
|
||||
bool show_encoding_settings_ = false;
|
||||
// 历史命令UI状态
|
||||
bool show_command_history_;
|
||||
// UI状态相关成员变量
|
||||
char env_key_input_[256] = {}; // 环境变量键输入缓冲区
|
||||
char env_value_input_[512] = {}; // 环境变量值输入缓冲区
|
||||
bool show_env_settings_ = false; // 是否显示环境变量设置
|
||||
bool show_encoding_settings_ = false; // 是否显示编码设置
|
||||
bool show_command_history_ = false; // 是否显示命令历史
|
||||
};
|
|
@ -191,6 +191,9 @@ void AppState::LoadSettings() {
|
|||
else if (key == "AutoScrollLogs") {
|
||||
auto_scroll_logs = (value == "1");
|
||||
}
|
||||
else if (key == "EnableColoredLogs") {
|
||||
enable_colored_logs = (value == "1");
|
||||
}
|
||||
else if (key == "AutoStart") {
|
||||
auto_start = (value == "1");
|
||||
}
|
||||
|
@ -238,6 +241,7 @@ void AppState::SaveSettings() {
|
|||
file << "CommandInput=" << command_input << "\n";
|
||||
file << "MaxLogLines=" << max_log_lines << "\n";
|
||||
file << "AutoScrollLogs=" << (auto_scroll_logs ? "1" : "0") << "\n";
|
||||
file << "EnableColoredLogs=" << (enable_colored_logs ? "1" : "0") << "\n";
|
||||
file << "AutoStart=" << (auto_start ? "1" : "0") << "\n";
|
||||
file << "WebUrl=" << web_url << "\n";
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "CLIProcess.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Units.h"
|
||||
|
@ -20,17 +21,122 @@ CLIProcess::CLIProcess() {
|
|||
process_pid_ = -1;
|
||||
pipe_stdout_[0] = pipe_stdout_[1] = -1;
|
||||
pipe_stdin_[0] = pipe_stdin_[1] = -1;
|
||||
process__running_ = false;
|
||||
process_running_ = false;
|
||||
#endif
|
||||
max_log_lines_ = 1000;
|
||||
stop_timeout_ms_ = 5000;
|
||||
output_encoding_ = OutputEncoding::AUTO_DETECT;
|
||||
use_auto_working_dir_ = true; // 新增:默认启用自动工作目录
|
||||
}
|
||||
|
||||
CLIProcess::~CLIProcess() {
|
||||
Stop();
|
||||
CleanupResources();
|
||||
}
|
||||
|
||||
// 新增:设置工作目录
|
||||
void CLIProcess::SetWorkingDirectory(const std::string& working_dir) {
|
||||
std::lock_guard<std::mutex> lock(working_dir_mutex_);
|
||||
if (working_dir.empty()) {
|
||||
use_auto_working_dir_ = true;
|
||||
working_directory_.clear();
|
||||
} else {
|
||||
if (DirectoryExists(working_dir)) {
|
||||
working_directory_ = GetAbsolutePath(working_dir);
|
||||
use_auto_working_dir_ = false;
|
||||
AddLog("工作目录已设置为: " + working_directory_);
|
||||
} else {
|
||||
AddLog("警告: 指定的工作目录不存在: " + working_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:获取当前工作目录设置
|
||||
std::string CLIProcess::GetWorkingDirectory() const {
|
||||
std::lock_guard<std::mutex> lock(working_dir_mutex_);
|
||||
return working_directory_;
|
||||
}
|
||||
|
||||
// 新增:从命令中提取目录路径
|
||||
std::string CLIProcess::ExtractDirectoryFromCommand(const std::string& command) {
|
||||
if (command.empty()) return "";
|
||||
|
||||
std::string trimmed_command = command;
|
||||
|
||||
// 移除前后空格
|
||||
size_t start = trimmed_command.find_first_not_of(" \t\r\n");
|
||||
if (start == std::string::npos) return "";
|
||||
|
||||
size_t end = trimmed_command.find_last_not_of(" \t\r\n");
|
||||
trimmed_command = trimmed_command.substr(start, end - start + 1);
|
||||
|
||||
std::string executable_path;
|
||||
|
||||
// 处理引号包围的路径
|
||||
if (trimmed_command[0] == '"') {
|
||||
size_t quote_end = trimmed_command.find('"', 1);
|
||||
if (quote_end != std::string::npos) {
|
||||
executable_path = trimmed_command.substr(1, quote_end - 1);
|
||||
}
|
||||
} else {
|
||||
// 找到第一个空格前的部分作为可执行文件路径
|
||||
size_t space_pos = trimmed_command.find(' ');
|
||||
if (space_pos != std::string::npos) {
|
||||
executable_path = trimmed_command.substr(0, space_pos);
|
||||
} else {
|
||||
executable_path = trimmed_command;
|
||||
}
|
||||
}
|
||||
|
||||
if (executable_path.empty()) return "";
|
||||
|
||||
// 使用 std::filesystem 来处理路径
|
||||
try {
|
||||
std::filesystem::path path(executable_path);
|
||||
|
||||
// 如果是相对路径,转换为绝对路径
|
||||
if (path.is_relative()) {
|
||||
path = std::filesystem::absolute(path);
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
if (std::filesystem::exists(path) && std::filesystem::is_regular_file(path)) {
|
||||
return path.parent_path().string();
|
||||
}
|
||||
|
||||
// 如果文件不存在,但路径看起来像一个文件路径,返回其父目录
|
||||
if (path.has_parent_path()) {
|
||||
auto parent = path.parent_path();
|
||||
if (std::filesystem::exists(parent) && std::filesystem::is_directory(parent)) {
|
||||
return parent.string();
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
// 路径解析失败,返回当前工作目录
|
||||
return std::filesystem::current_path().string();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// 新增:获取绝对路径
|
||||
std::string CLIProcess::GetAbsolutePath(const std::string& path) {
|
||||
try {
|
||||
return std::filesystem::absolute(path).string();
|
||||
} catch (const std::exception&) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:检查目录是否存在
|
||||
bool CLIProcess::DirectoryExists(const std::string& path) {
|
||||
try {
|
||||
return std::filesystem::exists(path) && std::filesystem::is_directory(path);
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置输出编码
|
||||
void CLIProcess::SetOutputEncoding(OutputEncoding encoding) {
|
||||
std::lock_guard<std::mutex> lock(encoding_mutex_);
|
||||
|
@ -228,7 +334,7 @@ void CLIProcess::SetEnvironmentVariables(const std::map<std::string, std::string
|
|||
if (!environment_variables_.empty()) {
|
||||
// AddLog("已设置 " + std::to_string(environment_variables_.size()) + " 个有效环境变量");
|
||||
for (const auto& pair : environment_variables_) {
|
||||
AddLog(" " + pair.first + "=" + pair.second);
|
||||
// AddLog(" " + pair.first + "=" + pair.second);
|
||||
}
|
||||
} else {
|
||||
// AddLog("已清空所有自定义环境变量");
|
||||
|
@ -275,6 +381,25 @@ void CLIProcess::ClearEnvironmentVariables() {
|
|||
|
||||
void CLIProcess::Start(const std::string& command) {
|
||||
Stop();
|
||||
|
||||
// 确定工作目录
|
||||
std::string working_dir;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(working_dir_mutex_);
|
||||
if (use_auto_working_dir_) {
|
||||
working_dir = ExtractDirectoryFromCommand(command);
|
||||
if (working_dir.empty()) {
|
||||
working_dir = std::filesystem::current_path().string();
|
||||
}
|
||||
// AddLog("自动检测工作目录: " + working_dir);
|
||||
} else {
|
||||
working_dir = working_directory_;
|
||||
if (!working_dir.empty()) {
|
||||
// AddLog("使用指定工作目录: " + working_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
|
@ -329,24 +454,122 @@ void CLIProcess::Start(const std::string& command) {
|
|||
env_block += '\0';
|
||||
}
|
||||
|
||||
BOOL bSuccess = CreateProcessA(
|
||||
// 处理工作目录 - 支持Unicode路径
|
||||
const char* working_dir_ptr = nullptr;
|
||||
std::wstring working_dir_wide;
|
||||
|
||||
if (!working_dir.empty()) {
|
||||
// 验证工作目录是否存在
|
||||
if (!DirectoryExists(working_dir)) {
|
||||
// AddLog("警告: 工作目录不存在,使用当前目录: " + working_dir);
|
||||
working_dir = std::filesystem::current_path().string();
|
||||
}
|
||||
|
||||
// 转换为绝对路径
|
||||
working_dir = GetAbsolutePath(working_dir);
|
||||
working_dir_ptr = working_dir.c_str();
|
||||
|
||||
// 如果路径包含非ASCII字符,需要使用CreateProcessW
|
||||
bool hasNonAscii = false;
|
||||
for (char c : working_dir) {
|
||||
if (static_cast<unsigned char>(c) > 127) {
|
||||
hasNonAscii = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNonAscii) {
|
||||
// 转换为宽字符用于CreateProcessW
|
||||
int wideSize = MultiByteToWideChar(CP_UTF8, 0, working_dir.c_str(), -1, nullptr, 0);
|
||||
if (wideSize > 0) {
|
||||
working_dir_wide.resize(wideSize);
|
||||
MultiByteToWideChar(CP_UTF8, 0, working_dir.c_str(), -1, &working_dir_wide[0], wideSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL bSuccess = FALSE;
|
||||
|
||||
// 如果工作目录包含Unicode字符,使用CreateProcessW
|
||||
if (!working_dir_wide.empty()) {
|
||||
// 转换命令为宽字符
|
||||
int cmdWideSize = MultiByteToWideChar(CP_UTF8, 0, command.c_str(), -1, nullptr, 0);
|
||||
if (cmdWideSize > 0) {
|
||||
std::wstring command_wide(cmdWideSize, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, command.c_str(), -1, &command_wide[0], cmdWideSize);
|
||||
|
||||
// 转换环境变量为宽字符
|
||||
std::wstring env_block_wide;
|
||||
if (!env_block.empty()) {
|
||||
int envWideSize = MultiByteToWideChar(CP_UTF8, 0, env_block.c_str(), static_cast<int>(env_block.size()), nullptr, 0);
|
||||
if (envWideSize > 0) {
|
||||
env_block_wide.resize(envWideSize);
|
||||
MultiByteToWideChar(CP_UTF8, 0, env_block.c_str(), static_cast<int>(env_block.size()), &env_block_wide[0], envWideSize);
|
||||
}
|
||||
}
|
||||
|
||||
STARTUPINFOW siStartInfoW;
|
||||
ZeroMemory(&siStartInfoW, sizeof(STARTUPINFOW));
|
||||
siStartInfoW.cb = sizeof(STARTUPINFOW);
|
||||
siStartInfoW.hStdError = hWriteTmp;
|
||||
siStartInfoW.hStdOutput = hWriteTmp;
|
||||
siStartInfoW.hStdInput = hReadTmp_stdin;
|
||||
siStartInfoW.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
bSuccess = CreateProcessW(
|
||||
nullptr,
|
||||
&command_wide[0],
|
||||
nullptr,
|
||||
nullptr,
|
||||
TRUE,
|
||||
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
|
||||
env_block_wide.empty() ? nullptr : (LPVOID)env_block_wide.data(),
|
||||
working_dir_wide.c_str(),
|
||||
&siStartInfoW,
|
||||
&piProcInfo);
|
||||
}
|
||||
} else {
|
||||
// 使用ANSI版本
|
||||
bSuccess = CreateProcessA(
|
||||
nullptr,
|
||||
const_cast<char*>(command.c_str()),
|
||||
nullptr,
|
||||
nullptr,
|
||||
TRUE,
|
||||
CREATE_NO_WINDOW,
|
||||
env_block.empty() ? nullptr : (LPVOID)env_block.data(),
|
||||
nullptr,
|
||||
env_block.empty() ? nullptr : static_cast<LPVOID>(env_block.data()),
|
||||
working_dir_ptr,
|
||||
&siStartInfo,
|
||||
&piProcInfo);
|
||||
}
|
||||
|
||||
CloseHandle(hWriteTmp);
|
||||
CloseHandle(hReadTmp_stdin);
|
||||
|
||||
if (!bSuccess) {
|
||||
DWORD error = GetLastError();
|
||||
CloseHandle(hReadTmp);
|
||||
CloseHandle(hWriteTmp_stdin);
|
||||
AddLog("启动进程失败,错误代码: " + std::to_string(error));
|
||||
|
||||
// 提供更详细的错误信息
|
||||
switch (error) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
AddLog("错误: 找不到指定的文件或程序");
|
||||
break;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
AddLog("错误: 找不到指定的路径");
|
||||
break;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
AddLog("错误: 访问被拒绝,可能需要管理员权限");
|
||||
break;
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
AddLog("错误: 无效的参数");
|
||||
break;
|
||||
default:
|
||||
AddLog("错误: 未知错误,请检查命令和路径是否正确");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -356,15 +579,21 @@ void CLIProcess::Start(const std::string& command) {
|
|||
hReadPipe_ = hReadTmp;
|
||||
hWritePipe_stdin_ = hWriteTmp_stdin;
|
||||
|
||||
AddLog("进程已启动,PID: " + std::to_string(piProcInfo.dwProcessId));
|
||||
if (!working_dir.empty()) {
|
||||
AddLog("工作目录: " + working_dir);
|
||||
}
|
||||
|
||||
// Start output reading thread
|
||||
output_thread_ = std::thread(&CLIProcess::ReadOutput, this);
|
||||
|
||||
#else
|
||||
// Unix/Linux implementation using posix_spawn
|
||||
// Unix/Linux implementation
|
||||
int pipe_out[2];
|
||||
int pipe_in[2];
|
||||
|
||||
if (pipe(pipe_out) < 0 || pipe(pipe_in) < 0) {
|
||||
AddLog("创建管道失败: " + std::string(strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -380,12 +609,28 @@ void CLIProcess::Start(const std::string& command) {
|
|||
dup2(pipe_in[0], STDIN_FILENO);
|
||||
close(pipe_in[0]);
|
||||
|
||||
// 设置工作目录
|
||||
if (!working_dir.empty()) {
|
||||
if (!DirectoryExists(working_dir)) {
|
||||
fprintf(stderr, "警告: 工作目录不存在: %s\n", working_dir.c_str());
|
||||
working_dir = std::filesystem::current_path().string();
|
||||
}
|
||||
|
||||
if (chdir(working_dir.c_str()) != 0) {
|
||||
fprintf(stderr, "无法切换到工作目录: %s, 错误: %s\n",
|
||||
working_dir.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare environment variables
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(env_mutex_);
|
||||
if (!environment_variables_.empty()) {
|
||||
for (const auto& kv : environment_variables_) {
|
||||
setenv(kv.first.c_str(), kv.second.c_str(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
execl("/bin/sh", "sh", "-c", command.c_str(), (char*)nullptr);
|
||||
_exit(127);
|
||||
|
@ -403,8 +648,19 @@ void CLIProcess::Start(const std::string& command) {
|
|||
|
||||
process_running_ = true;
|
||||
|
||||
AddLog("进程已启动,PID: " + std::to_string(pid));
|
||||
if (!working_dir.empty()) {
|
||||
AddLog("工作目录: " + working_dir);
|
||||
}
|
||||
|
||||
// Start output reading thread
|
||||
output_thread_ = std::thread(&CLIProcess::ReadOutput, this);
|
||||
} else {
|
||||
AddLog("fork失败,无法启动进程: " + std::string(strerror(errno)));
|
||||
close(pipe_out[0]);
|
||||
close(pipe_out[1]);
|
||||
close(pipe_in[0]);
|
||||
close(pipe_in[1]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
1026
app/src/Manager.cpp
1026
app/src/Manager.cpp
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue