mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-05-10 02:09:46 +08:00
feat: 新增系统/用户变量分离、搜索、拖拽和清理功能
- 将单一列表拆分为系统和用户变量两个标签页 - 新增搜索框支持实时过滤路径 - 支持拖拽文件夹直接添加到列表 - 新增一键清理功能移除无效和重复路径 - 增加注册表备份机制和删除确认 - 优化界面布局和权限提示逻辑
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,11 +10,21 @@ int btn_browse_cb(Ihandle* self);
|
|||||||
int btn_del_cb(Ihandle *self);
|
int btn_del_cb(Ihandle *self);
|
||||||
int btn_up_cb(Ihandle *self);
|
int btn_up_cb(Ihandle *self);
|
||||||
int btn_down_cb(Ihandle *self);
|
int btn_down_cb(Ihandle *self);
|
||||||
|
int btn_clean_cb(Ihandle *self);
|
||||||
int btn_ok_cb(Ihandle *self);
|
int btn_ok_cb(Ihandle *self);
|
||||||
int btn_cancel_cb(Ihandle *self);
|
int btn_cancel_cb(Ihandle *self);
|
||||||
int btn_help_cb(Ihandle *self);
|
int btn_help_cb(Ihandle *self);
|
||||||
|
|
||||||
|
// 搜索回调
|
||||||
|
int txt_search_cb(Ihandle *self);
|
||||||
|
|
||||||
// 双击回调
|
// 双击回调
|
||||||
int list_dblclick_cb(Ihandle *self, int item, char *text);
|
int list_dblclick_cb(Ihandle *self, int item, char *text);
|
||||||
|
|
||||||
|
// 拖拽回调
|
||||||
|
int list_dropfiles_cb(Ihandle *self, const char *filename, int num, int x, int y);
|
||||||
|
|
||||||
|
// 键盘按键回调
|
||||||
|
int list_k_any_cb(Ihandle *self, int c);
|
||||||
|
|
||||||
#endif // CALLBACKS_H
|
#endif // CALLBACKS_H
|
||||||
+22
-2
@@ -4,12 +4,15 @@
|
|||||||
#include <iup.h>
|
#include <iup.h>
|
||||||
|
|
||||||
// 注册表路径常量
|
// 注册表路径常量
|
||||||
#define REG_PATH L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
|
#define REG_PATH_SYS L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
|
||||||
|
#define REG_PATH_USER L"Environment"
|
||||||
#define REG_VALUE L"Path"
|
#define REG_VALUE L"Path"
|
||||||
|
|
||||||
// 全局控件句柄声明
|
// 全局控件句柄声明
|
||||||
extern Ihandle *dlg; // 主对话框句柄
|
extern Ihandle *dlg; // 主对话框句柄
|
||||||
extern Ihandle *list_path; // 路径列表控件句柄
|
extern Ihandle *tabs_main; // 标签页容器
|
||||||
|
extern Ihandle *list_sys; // 系统变量列表
|
||||||
|
extern Ihandle *list_user; // 用户变量列表
|
||||||
extern Ihandle *lbl_status; // 状态标签句柄
|
extern Ihandle *lbl_status; // 状态标签句柄
|
||||||
extern Ihandle *btn_new; // 新增按钮句柄
|
extern Ihandle *btn_new; // 新增按钮句柄
|
||||||
extern Ihandle *btn_edit; // 编辑按钮句柄
|
extern Ihandle *btn_edit; // 编辑按钮句柄
|
||||||
@@ -17,8 +20,25 @@ extern Ihandle *btn_browse; // 浏览按钮句柄
|
|||||||
extern Ihandle *btn_del; // 删除按钮句柄
|
extern Ihandle *btn_del; // 删除按钮句柄
|
||||||
extern Ihandle *btn_up; // 上移按钮句柄
|
extern Ihandle *btn_up; // 上移按钮句柄
|
||||||
extern Ihandle *btn_down; // 下移按钮句柄
|
extern Ihandle *btn_down; // 下移按钮句柄
|
||||||
|
extern Ihandle *btn_clean; // 一键清理按钮句柄
|
||||||
extern Ihandle *btn_ok; // 确认按钮句柄
|
extern Ihandle *btn_ok; // 确认按钮句柄
|
||||||
extern Ihandle *btn_cancel; // 取消按钮句柄
|
extern Ihandle *btn_cancel; // 取消按钮句柄
|
||||||
extern Ihandle *btn_help; // 帮助按钮句柄
|
extern Ihandle *btn_help; // 帮助按钮句柄
|
||||||
|
extern Ihandle *txt_search; // 搜索框
|
||||||
|
|
||||||
|
// 简单字符串列表结构,用于搜索缓存
|
||||||
|
typedef struct {
|
||||||
|
char **items;
|
||||||
|
int count;
|
||||||
|
int capacity;
|
||||||
|
} StringList;
|
||||||
|
|
||||||
|
extern StringList raw_sys_paths;
|
||||||
|
extern StringList raw_user_paths;
|
||||||
|
|
||||||
|
// 缓存操作函数声明
|
||||||
|
void init_string_list(StringList *list);
|
||||||
|
void add_string_list(StringList *list, const char *str);
|
||||||
|
void clear_string_list(StringList *list);
|
||||||
|
|
||||||
#endif // GLOBALS_H
|
#endif // GLOBALS_H
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
#ifndef REGISTRY_H
|
#ifndef REGISTRY_H
|
||||||
#define REGISTRY_H
|
#define REGISTRY_H
|
||||||
|
|
||||||
// 从注册表加载PATH到列表控件
|
// 从注册表加载所有PATH到列表控件
|
||||||
void load_path();
|
void load_all_paths();
|
||||||
|
|
||||||
// 将列表控件中的PATH保存回注册表
|
// 将列表控件中的PATH保存回注册表
|
||||||
void save_path();
|
void save_all_paths();
|
||||||
|
|
||||||
#endif // REGISTRY_H
|
#endif // REGISTRY_H
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
#include <iup.h>
|
||||||
|
|
||||||
// 宽字符转UTF-8
|
// 宽字符转UTF-8
|
||||||
char* wide_to_utf8(const wchar_t* wstr);
|
char* wide_to_utf8(const wchar_t* wstr);
|
||||||
@@ -13,7 +14,17 @@ wchar_t* utf8_to_wide(const char* str);
|
|||||||
// 检查管理员权限
|
// 检查管理员权限
|
||||||
int check_admin();
|
int check_admin();
|
||||||
|
|
||||||
|
// 检查路径是否有效(存在且为目录)
|
||||||
|
int is_path_valid(const char *path);
|
||||||
|
|
||||||
// 刷新列表样式(斑马纹)
|
// 刷新列表样式(斑马纹)
|
||||||
void refresh_list_style();
|
void refresh_list_style();
|
||||||
|
void refresh_single_list_style(Ihandle *list);
|
||||||
|
|
||||||
|
// 备份注册表
|
||||||
|
void backup_registry();
|
||||||
|
|
||||||
|
// 不区分大小写的字符串查找
|
||||||
|
char *stristr(const char *haystack, const char *needle);
|
||||||
|
|
||||||
#endif // UTILS_H
|
#endif // UTILS_H
|
||||||
+258
-38
@@ -27,8 +27,8 @@ int show_custom_input_dialog(const char *title, const char *label_text, char *bu
|
|||||||
text,
|
text,
|
||||||
IupHbox(
|
IupHbox(
|
||||||
IupFill(),
|
IupFill(),
|
||||||
IupButton("确定", "1"), // "1" will be returned by IupPopup
|
IupButton("确定", "1"), // "1" 会被返回
|
||||||
IupButton("取消", "0"), // "0" will be returned by IupPopup
|
IupButton("取消", "0"), // "0" 会被返回
|
||||||
NULL),
|
NULL),
|
||||||
NULL));
|
NULL));
|
||||||
|
|
||||||
@@ -132,6 +132,20 @@ int custom_input_dialog(const char *title, const char *label_text, char *buffer,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 辅助函数:获取当前选中的列表
|
||||||
|
Ihandle *get_current_list()
|
||||||
|
{
|
||||||
|
// 获取当前选中的 Tab 索引
|
||||||
|
// 注意:IupTabs 的 VALUE 属性在某些版本可能返回 handle,某些版本返回 pos
|
||||||
|
// 这里使用 IupGetInt(tabs_main, "VALUEPOS") 更稳妥
|
||||||
|
int pos = IupGetInt(tabs_main, "VALUEPOS");
|
||||||
|
if (pos == 0)
|
||||||
|
return list_sys;
|
||||||
|
if (pos == 1)
|
||||||
|
return list_user;
|
||||||
|
return list_sys; // 默认
|
||||||
|
}
|
||||||
|
|
||||||
// 按钮回调:新建
|
// 按钮回调:新建
|
||||||
int btn_new_cb(Ihandle *self)
|
int btn_new_cb(Ihandle *self)
|
||||||
{
|
{
|
||||||
@@ -140,13 +154,14 @@ int btn_new_cb(Ihandle *self)
|
|||||||
{
|
{
|
||||||
if (strlen(buffer) > 0)
|
if (strlen(buffer) > 0)
|
||||||
{
|
{
|
||||||
int count = IupGetInt(list_path, "COUNT");
|
Ihandle *current_list = get_current_list();
|
||||||
|
int count = IupGetInt(current_list, "COUNT");
|
||||||
count++;
|
count++;
|
||||||
IupSetAttributeId(list_path, "", count, buffer);
|
IupSetAttributeId(current_list, "", count, buffer);
|
||||||
IupSetInt(list_path, "COUNT", count);
|
IupSetInt(current_list, "COUNT", count);
|
||||||
IupSetInt(list_path, "VALUE", count);
|
IupSetInt(current_list, "VALUE", count);
|
||||||
|
|
||||||
refresh_list_style();
|
refresh_single_list_style(current_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
@@ -155,11 +170,12 @@ int btn_new_cb(Ihandle *self)
|
|||||||
// 按钮回调:编辑
|
// 按钮回调:编辑
|
||||||
int btn_edit_cb(Ihandle *self)
|
int btn_edit_cb(Ihandle *self)
|
||||||
{
|
{
|
||||||
int selected = IupGetInt(list_path, "VALUE");
|
Ihandle *current_list = get_current_list();
|
||||||
|
int selected = IupGetInt(current_list, "VALUE");
|
||||||
if (selected == 0)
|
if (selected == 0)
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
|
|
||||||
char *current_val = IupGetAttributeId(list_path, "", selected);
|
char *current_val = IupGetAttributeId(current_list, "", selected);
|
||||||
char buffer[4096]; // 假设单个路径不超过4096
|
char buffer[4096]; // 假设单个路径不超过4096
|
||||||
if (current_val)
|
if (current_val)
|
||||||
{
|
{
|
||||||
@@ -175,8 +191,8 @@ int btn_edit_cb(Ihandle *self)
|
|||||||
{
|
{
|
||||||
if (strlen(buffer) > 0)
|
if (strlen(buffer) > 0)
|
||||||
{
|
{
|
||||||
IupSetAttributeId(list_path, "", selected, buffer);
|
IupSetAttributeId(current_list, "", selected, buffer);
|
||||||
refresh_list_style();
|
refresh_single_list_style(current_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
@@ -185,11 +201,11 @@ int btn_edit_cb(Ihandle *self)
|
|||||||
// 双击回调
|
// 双击回调
|
||||||
int list_dblclick_cb(Ihandle *self, int item, char *text)
|
int list_dblclick_cb(Ihandle *self, int item, char *text)
|
||||||
{
|
{
|
||||||
// 这里的 item 是点击的行号
|
// 这里的 self 就是触发双击的列表控件
|
||||||
if (item > 0)
|
if (item > 0)
|
||||||
{
|
{
|
||||||
// 选中该行
|
// 选中该行
|
||||||
IupSetInt(list_path, "VALUE", item);
|
IupSetInt(self, "VALUE", item);
|
||||||
// 调用编辑逻辑
|
// 调用编辑逻辑
|
||||||
btn_edit_cb(NULL);
|
btn_edit_cb(NULL);
|
||||||
}
|
}
|
||||||
@@ -210,42 +226,100 @@ int btn_browse_cb(Ihandle *self)
|
|||||||
char *value = IupGetAttribute(filedlg, "VALUE");
|
char *value = IupGetAttribute(filedlg, "VALUE");
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
int count = IupGetInt(list_path, "COUNT");
|
Ihandle *current_list = get_current_list();
|
||||||
|
int count = IupGetInt(current_list, "COUNT");
|
||||||
count++;
|
count++;
|
||||||
IupSetAttributeId(list_path, "", count, value);
|
IupSetAttributeId(current_list, "", count, value);
|
||||||
IupSetInt(list_path, "COUNT", count);
|
IupSetInt(current_list, "COUNT", count);
|
||||||
IupSetInt(list_path, "VALUE", count);
|
IupSetInt(current_list, "VALUE", count);
|
||||||
|
|
||||||
refresh_list_style();
|
refresh_single_list_style(current_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IupDestroy(filedlg);
|
IupDestroy(filedlg);
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 辅助函数:从 raw_data 中删除指定字符串
|
||||||
|
static void remove_from_raw_data(StringList *list, const char *str)
|
||||||
|
{
|
||||||
|
if (!list || !str)
|
||||||
|
return;
|
||||||
|
for (int i = 0; i < list->count; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(list->items[i], str) == 0)
|
||||||
|
{
|
||||||
|
free(list->items[i]);
|
||||||
|
// 移动后续元素
|
||||||
|
for (int j = i; j < list->count - 1; j++)
|
||||||
|
{
|
||||||
|
list->items[j] = list->items[j + 1];
|
||||||
|
}
|
||||||
|
list->count--;
|
||||||
|
break; // 假设没有重复,只删除第一个匹配
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 按钮回调:删除
|
// 按钮回调:删除
|
||||||
int btn_del_cb(Ihandle *self)
|
int btn_del_cb(Ihandle *self)
|
||||||
{
|
{
|
||||||
int selected = IupGetInt(list_path, "VALUE");
|
Ihandle *current_list = get_current_list();
|
||||||
|
int selected = IupGetInt(current_list, "VALUE");
|
||||||
|
|
||||||
if (selected == 0)
|
if (selected == 0)
|
||||||
|
{
|
||||||
|
IupMessage("提示", "请先选择要删除的项");
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
IupSetAttribute(list_path, "REMOVEITEM", "SELECTED");
|
// 获取当前要删除的内容
|
||||||
|
char *val = IupGetAttributeId(current_list, "", selected);
|
||||||
|
|
||||||
|
// 确认删除
|
||||||
|
// char msg[1024];
|
||||||
|
// snprintf(msg, sizeof(msg), "确定要删除以下路径吗?\n\n%s", val ? val : "(空)");
|
||||||
|
// if (IupAlarm("确认删除", msg, "是", "否", NULL) != 1)
|
||||||
|
// return IUP_DEFAULT;
|
||||||
|
|
||||||
|
// 从 raw_data 缓存中同步删除
|
||||||
|
int pos = IupGetInt(tabs_main, "VALUEPOS");
|
||||||
|
StringList *raw_data = (pos == 0) ? &raw_sys_paths : &raw_user_paths;
|
||||||
|
|
||||||
|
// 注意:必须先保存 val 的副本,因为 REMOVEITEM 可能会导致 val 指针失效(如果它是指向列表内部缓冲区的)
|
||||||
|
char *val_copy = val ? _strdup(val) : NULL;
|
||||||
|
|
||||||
|
// 先从界面删除
|
||||||
|
// IupSetAttribute(current_list, "REMOVEITEM", "SELECTED");
|
||||||
|
// 改为按索引删除,防止失去焦点导致 SELECTED 失效
|
||||||
|
IupSetInt(current_list, "REMOVEITEM", selected);
|
||||||
|
|
||||||
|
// 再从缓存删除
|
||||||
|
if (val_copy && raw_data)
|
||||||
|
{
|
||||||
|
remove_from_raw_data(raw_data, val_copy);
|
||||||
|
free(val_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新刷新
|
||||||
|
refresh_single_list_style(current_list);
|
||||||
|
|
||||||
|
// 更新状态栏,告知用户删除了什么
|
||||||
|
IupSetAttribute(lbl_status, "TITLE", "状态: 已删除选中项");
|
||||||
|
|
||||||
// 重新刷新,因为删除了中间项,后面的奇偶性变了
|
|
||||||
refresh_list_style();
|
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按钮回调:上移
|
// 按钮回调:上移
|
||||||
int btn_up_cb(Ihandle *self)
|
int btn_up_cb(Ihandle *self)
|
||||||
{
|
{
|
||||||
int selected = IupGetInt(list_path, "VALUE");
|
Ihandle *current_list = get_current_list();
|
||||||
|
int selected = IupGetInt(current_list, "VALUE");
|
||||||
if (selected <= 1)
|
if (selected <= 1)
|
||||||
return IUP_DEFAULT; // 已经是第一个或未选中
|
return IUP_DEFAULT; // 已经是第一个或未选中
|
||||||
|
|
||||||
char *current = IupGetAttributeId(list_path, "", selected);
|
char *current = IupGetAttributeId(current_list, "", selected);
|
||||||
char *prev = IupGetAttributeId(list_path, "", selected - 1);
|
char *prev = IupGetAttributeId(current_list, "", selected - 1);
|
||||||
|
|
||||||
// 交换内容
|
// 交换内容
|
||||||
char buf_curr[4096], buf_prev[4096];
|
char buf_curr[4096], buf_prev[4096];
|
||||||
@@ -254,26 +328,27 @@ int btn_up_cb(Ihandle *self)
|
|||||||
strncpy(buf_prev, prev, 4096);
|
strncpy(buf_prev, prev, 4096);
|
||||||
buf_prev[4095] = '\0';
|
buf_prev[4095] = '\0';
|
||||||
|
|
||||||
IupSetAttributeId(list_path, "", selected, buf_prev);
|
IupSetAttributeId(current_list, "", selected, buf_prev);
|
||||||
IupSetAttributeId(list_path, "", selected - 1, buf_curr);
|
IupSetAttributeId(current_list, "", selected - 1, buf_curr);
|
||||||
|
|
||||||
IupSetInt(list_path, "VALUE", selected - 1);
|
IupSetInt(current_list, "VALUE", selected - 1);
|
||||||
|
|
||||||
// 刷新样式(虽然颜色不需要变,但为了保险)
|
// 刷新样式(虽然颜色不需要变,但为了保险)
|
||||||
refresh_list_style();
|
refresh_single_list_style(current_list);
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按钮回调:下移
|
// 按钮回调:下移
|
||||||
int btn_down_cb(Ihandle *self)
|
int btn_down_cb(Ihandle *self)
|
||||||
{
|
{
|
||||||
int selected = IupGetInt(list_path, "VALUE");
|
Ihandle *current_list = get_current_list();
|
||||||
int count = IupGetInt(list_path, "COUNT");
|
int selected = IupGetInt(current_list, "VALUE");
|
||||||
|
int count = IupGetInt(current_list, "COUNT");
|
||||||
if (selected == 0 || selected >= count)
|
if (selected == 0 || selected >= count)
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
|
|
||||||
char *current = IupGetAttributeId(list_path, "", selected);
|
char *current = IupGetAttributeId(current_list, "", selected);
|
||||||
char *next = IupGetAttributeId(list_path, "", selected + 1);
|
char *next = IupGetAttributeId(current_list, "", selected + 1);
|
||||||
|
|
||||||
char buf_curr[4096], buf_next[4096];
|
char buf_curr[4096], buf_next[4096];
|
||||||
strncpy(buf_curr, current, 4096);
|
strncpy(buf_curr, current, 4096);
|
||||||
@@ -281,19 +356,164 @@ int btn_down_cb(Ihandle *self)
|
|||||||
strncpy(buf_next, next, 4096);
|
strncpy(buf_next, next, 4096);
|
||||||
buf_next[4095] = '\0';
|
buf_next[4095] = '\0';
|
||||||
|
|
||||||
IupSetAttributeId(list_path, "", selected, buf_next);
|
IupSetAttributeId(current_list, "", selected, buf_next);
|
||||||
IupSetAttributeId(list_path, "", selected + 1, buf_curr);
|
IupSetAttributeId(current_list, "", selected + 1, buf_curr);
|
||||||
|
|
||||||
IupSetInt(list_path, "VALUE", selected + 1);
|
IupSetInt(current_list, "VALUE", selected + 1);
|
||||||
|
|
||||||
refresh_list_style();
|
refresh_single_list_style(current_list);
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮回调:一键清理
|
||||||
|
int btn_clean_cb(Ihandle *self)
|
||||||
|
{
|
||||||
|
Ihandle *current_list = get_current_list();
|
||||||
|
int count = IupGetInt(current_list, "COUNT");
|
||||||
|
if (count == 0)
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
|
||||||
|
// 弹出确认对话框
|
||||||
|
if (IupAlarm("确认清理", "此操作将移除当前列表中所有【无效路径】和【重复路径】。\n确定要继续吗?", "确定", "取消", NULL) != 1)
|
||||||
|
{
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从后往前遍历删除,避免索引错位
|
||||||
|
for (int i = count; i >= 1; i--)
|
||||||
|
{
|
||||||
|
char *item = IupGetAttributeId(current_list, "", i);
|
||||||
|
if (!item)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int should_remove = 0;
|
||||||
|
|
||||||
|
// 1. 检查有效性
|
||||||
|
if (!is_path_valid(item))
|
||||||
|
{
|
||||||
|
should_remove = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 2. 检查重复 (检查当前项之前是否出现过)
|
||||||
|
// 注意:这里需要再次遍历,性能稍低但最稳妥
|
||||||
|
for (int j = 1; j < i; j++)
|
||||||
|
{
|
||||||
|
char *prev_item = IupGetAttributeId(current_list, "", j);
|
||||||
|
if (prev_item && _stricmp(item, prev_item) == 0)
|
||||||
|
{
|
||||||
|
should_remove = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_remove)
|
||||||
|
{
|
||||||
|
IupSetAttributeId(current_list, "REMOVEITEM", i, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_single_list_style(current_list);
|
||||||
|
IupMessage("提示", "清理完成!");
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索回调
|
||||||
|
int txt_search_cb(Ihandle *self)
|
||||||
|
{
|
||||||
|
char *filter = IupGetAttribute(self, "VALUE");
|
||||||
|
if (!filter)
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
|
||||||
|
// 获取当前选中的 Tab 索引
|
||||||
|
int pos = IupGetInt(tabs_main, "VALUEPOS");
|
||||||
|
Ihandle *current_list = (pos == 0) ? list_sys : list_user;
|
||||||
|
StringList *raw_data = (pos == 0) ? &raw_sys_paths : &raw_user_paths;
|
||||||
|
|
||||||
|
// 清空列表
|
||||||
|
IupSetAttribute(current_list, "REMOVEITEM", "ALL");
|
||||||
|
|
||||||
|
// 重新填充
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < raw_data->count; i++)
|
||||||
|
{
|
||||||
|
// 如果 filter 为空,或包含 filter (不区分大小写)
|
||||||
|
if (strlen(filter) == 0 || stristr(raw_data->items[i], filter) != NULL)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
IupSetAttributeId(current_list, "", count, raw_data->items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IupSetInt(current_list, "COUNT", count);
|
||||||
|
refresh_single_list_style(current_list);
|
||||||
|
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽回调
|
||||||
|
int list_dropfiles_cb(Ihandle *self, const char *filename, int num, int x, int y)
|
||||||
|
{
|
||||||
|
// 获取当前列表和原始数据
|
||||||
|
// 注意:拖拽的目标列表可能是 list_sys 或 list_user,由 self 参数决定
|
||||||
|
// 但为了确保数据一致性,我们还是重新获取一下
|
||||||
|
Ihandle *current_list = self;
|
||||||
|
StringList *raw_data = NULL;
|
||||||
|
if (self == list_sys)
|
||||||
|
raw_data = &raw_sys_paths;
|
||||||
|
else if (self == list_user)
|
||||||
|
raw_data = &raw_user_paths;
|
||||||
|
else
|
||||||
|
return IUP_DEFAULT; // 异常情况
|
||||||
|
|
||||||
|
// 检查拖入的是否为目录
|
||||||
|
DWORD attr = GetFileAttributesA(filename);
|
||||||
|
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
// 如果正在搜索,先清空搜索框
|
||||||
|
IupSetAttribute(txt_search, "VALUE", "");
|
||||||
|
|
||||||
|
// 添加到列表末尾
|
||||||
|
int count = IupGetInt(current_list, "COUNT");
|
||||||
|
count++;
|
||||||
|
IupSetAttributeId(current_list, "", count, filename);
|
||||||
|
IupSetInt(current_list, "COUNT", count);
|
||||||
|
IupSetInt(current_list, "VALUE", count); // 选中新添加的项
|
||||||
|
|
||||||
|
// 同时添加到原始数据缓存,确保搜索时能搜到
|
||||||
|
if (raw_data)
|
||||||
|
{
|
||||||
|
add_string_list(raw_data, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_single_list_style(current_list);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果拖入的不是文件夹,可以在状态栏提示
|
||||||
|
IupSetAttribute(lbl_status, "TITLE", "提示: 只能拖拽文件夹添加到 PATH");
|
||||||
|
}
|
||||||
|
|
||||||
|
return IUP_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 键盘按键回调
|
||||||
|
int list_k_any_cb(Ihandle *self, int c)
|
||||||
|
{
|
||||||
|
// 处理 Delete 键
|
||||||
|
if (c == K_DEL)
|
||||||
|
{
|
||||||
|
btn_del_cb(NULL);
|
||||||
|
return IUP_IGNORE; // 阻止默认处理
|
||||||
|
}
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按钮回调:确定
|
// 按钮回调:确定
|
||||||
int btn_ok_cb(Ihandle *self)
|
int btn_ok_cb(Ihandle *self)
|
||||||
{
|
{
|
||||||
save_path();
|
save_all_paths();
|
||||||
return IUP_DEFAULT;
|
return IUP_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+64
-20
@@ -8,10 +8,32 @@
|
|||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "callbacks.h"
|
#include "callbacks.h"
|
||||||
|
|
||||||
|
// 全局变量定义
|
||||||
|
StringList raw_sys_paths = {0};
|
||||||
|
StringList raw_user_paths = {0};
|
||||||
|
|
||||||
// 全局控件定义
|
// 全局控件定义
|
||||||
Ihandle *dlg, *list_path, *lbl_status;
|
Ihandle *dlg, *tabs_main, *list_sys, *list_user, *lbl_status; // 主窗口、标签页、系统路径列表、用户路径列表、状态标签
|
||||||
Ihandle *btn_new, *btn_edit, *btn_browse, *btn_del, *btn_up, *btn_down;
|
Ihandle *btn_new, *btn_edit, *btn_browse, *btn_del, *btn_up, *btn_down; // 右侧按钮
|
||||||
Ihandle *btn_ok, *btn_cancel, *btn_help;
|
Ihandle *btn_ok, *btn_cancel, *btn_help; // 确认取消帮助按钮
|
||||||
|
Ihandle *btn_clean; // 一键清理按钮
|
||||||
|
Ihandle *txt_search; // 搜索框
|
||||||
|
|
||||||
|
// 辅助函数:创建列表控件
|
||||||
|
Ihandle *create_path_list()
|
||||||
|
{
|
||||||
|
Ihandle *list = IupFlatList();
|
||||||
|
IupSetAttribute(list, "EXPAND", "YES");
|
||||||
|
IupSetAttribute(list, "ITEMPADDING", "5x5");
|
||||||
|
IupSetAttribute(list, "BACKCOLOR", "255 255 255");
|
||||||
|
IupSetAttribute(list, "BORDER", "YES");
|
||||||
|
IupSetAttribute(list, "CANFOCUS", "YES");
|
||||||
|
IupSetAttribute(list, "HLINE", "NO");
|
||||||
|
IupSetCallback(list, "DBLCLICK_CB", (Icallback)list_dblclick_cb);
|
||||||
|
IupSetCallback(list, "DROPFILES_CB", (Icallback)list_dropfiles_cb);
|
||||||
|
IupSetCallback(list, "K_ANY", (Icallback)list_k_any_cb);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
// 主函数
|
// 主函数
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@@ -22,15 +44,24 @@ int main(int argc, char **argv)
|
|||||||
IupOpen(&argc, &argv);
|
IupOpen(&argc, &argv);
|
||||||
IupSetGlobal("UTF8MODE", "YES");
|
IupSetGlobal("UTF8MODE", "YES");
|
||||||
|
|
||||||
// 创建列表控件
|
// 创建两个列表控件
|
||||||
list_path = IupFlatList();
|
list_sys = create_path_list();
|
||||||
IupSetAttribute(list_path, "EXPAND", "YES");
|
list_user = create_path_list();
|
||||||
IupSetAttribute(list_path, "ITEMPADDING", "5x5");
|
|
||||||
IupSetAttribute(list_path, "BACKCOLOR", "255 255 255");
|
// 创建搜索框
|
||||||
IupSetAttribute(list_path, "BORDER", "YES");
|
txt_search = IupText(NULL);
|
||||||
IupSetAttribute(list_path, "CANFOCUS", "YES");
|
IupSetAttribute(txt_search, "EXPAND", "HORIZONTAL");
|
||||||
IupSetAttribute(list_path, "HLINE", "NO"); // 禁用横线,使用斑马纹
|
IupSetAttribute(txt_search, "CUEBANNER", "输入关键词搜索...");
|
||||||
// IupFlatList 不支持 VISIBLELINES,高度由 EXPAND 和布局决定
|
IupSetCallback(txt_search, "VALUECHANGED_CB", (Icallback)txt_search_cb);
|
||||||
|
|
||||||
|
// 创建 Tabs
|
||||||
|
tabs_main = IupTabs(
|
||||||
|
IupVbox(list_sys, NULL),
|
||||||
|
IupVbox(list_user, NULL),
|
||||||
|
NULL);
|
||||||
|
IupSetAttribute(tabs_main, "TABTITLE0", "系统变量 (System)");
|
||||||
|
IupSetAttribute(tabs_main, "TABTITLE1", "用户变量 (User)");
|
||||||
|
IupSetAttribute(tabs_main, "TABTYPE", "TOP");
|
||||||
|
|
||||||
// 创建右侧按钮
|
// 创建右侧按钮
|
||||||
btn_new = IupButton("新建(N)", NULL);
|
btn_new = IupButton("新建(N)", NULL);
|
||||||
@@ -39,6 +70,7 @@ int main(int argc, char **argv)
|
|||||||
btn_del = IupButton("删除(D)", NULL);
|
btn_del = IupButton("删除(D)", NULL);
|
||||||
btn_up = IupButton("上移(U)", NULL);
|
btn_up = IupButton("上移(U)", NULL);
|
||||||
btn_down = IupButton("下移(O)", NULL);
|
btn_down = IupButton("下移(O)", NULL);
|
||||||
|
btn_clean = IupButton("一键清理", NULL);
|
||||||
|
|
||||||
// 设置按钮回调
|
// 设置按钮回调
|
||||||
IupSetCallback(btn_new, "ACTION", (Icallback)btn_new_cb);
|
IupSetCallback(btn_new, "ACTION", (Icallback)btn_new_cb);
|
||||||
@@ -47,9 +79,7 @@ int main(int argc, char **argv)
|
|||||||
IupSetCallback(btn_del, "ACTION", (Icallback)btn_del_cb);
|
IupSetCallback(btn_del, "ACTION", (Icallback)btn_del_cb);
|
||||||
IupSetCallback(btn_up, "ACTION", (Icallback)btn_up_cb);
|
IupSetCallback(btn_up, "ACTION", (Icallback)btn_up_cb);
|
||||||
IupSetCallback(btn_down, "ACTION", (Icallback)btn_down_cb);
|
IupSetCallback(btn_down, "ACTION", (Icallback)btn_down_cb);
|
||||||
|
IupSetCallback(btn_clean, "ACTION", (Icallback)btn_clean_cb);
|
||||||
// 设置双击回调
|
|
||||||
IupSetCallback(list_path, "DBLCLICK_CB", (Icallback)list_dblclick_cb);
|
|
||||||
|
|
||||||
// 设置按钮大小 (宽度和高度都增加约1/4)
|
// 设置按钮大小 (宽度和高度都增加约1/4)
|
||||||
IupSetAttribute(btn_new, "RASTERSIZE", "100x32");
|
IupSetAttribute(btn_new, "RASTERSIZE", "100x32");
|
||||||
@@ -58,17 +88,20 @@ int main(int argc, char **argv)
|
|||||||
IupSetAttribute(btn_del, "RASTERSIZE", "100x32");
|
IupSetAttribute(btn_del, "RASTERSIZE", "100x32");
|
||||||
IupSetAttribute(btn_up, "RASTERSIZE", "100x32");
|
IupSetAttribute(btn_up, "RASTERSIZE", "100x32");
|
||||||
IupSetAttribute(btn_down, "RASTERSIZE", "100x32");
|
IupSetAttribute(btn_down, "RASTERSIZE", "100x32");
|
||||||
|
IupSetAttribute(btn_clean, "RASTERSIZE", "100x32");
|
||||||
|
|
||||||
Ihandle *vbox_btns = IupVbox(
|
Ihandle *vbox_btns = IupVbox(
|
||||||
btn_new, btn_edit, btn_browse, btn_del,
|
btn_new, btn_edit, btn_browse, btn_del,
|
||||||
IupFill(), // 间隔
|
IupFill(), // 间隔
|
||||||
|
btn_clean, // 放在上移下移之前,或者最下面,这里放在中间偏下
|
||||||
|
IupFill(),
|
||||||
btn_up, btn_down,
|
btn_up, btn_down,
|
||||||
NULL);
|
NULL);
|
||||||
IupSetAttribute(vbox_btns, "GAP", "5");
|
IupSetAttribute(vbox_btns, "GAP", "5");
|
||||||
IupSetAttribute(vbox_btns, "MARGIN", "0x0");
|
IupSetAttribute(vbox_btns, "MARGIN", "0x0");
|
||||||
|
|
||||||
// 上部布局:列表 + 按钮
|
// 上部布局:Tabs + 按钮
|
||||||
Ihandle *hbox_main = IupHbox(list_path, vbox_btns, NULL);
|
Ihandle *hbox_main = IupHbox(tabs_main, vbox_btns, NULL);
|
||||||
IupSetAttribute(hbox_main, "GAP", "10");
|
IupSetAttribute(hbox_main, "GAP", "10");
|
||||||
IupSetAttribute(hbox_main, "MARGIN", "10x10");
|
IupSetAttribute(hbox_main, "MARGIN", "10x10");
|
||||||
|
|
||||||
@@ -96,7 +129,8 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
// 总体布局
|
// 总体布局
|
||||||
Ihandle *vbox_all = IupVbox(
|
Ihandle *vbox_all = IupVbox(
|
||||||
IupLabel("系统变量 Path:"),
|
IupLabel("环境变量编辑器:"),
|
||||||
|
txt_search,
|
||||||
hbox_main,
|
hbox_main,
|
||||||
hbox_bottom,
|
hbox_bottom,
|
||||||
NULL);
|
NULL);
|
||||||
@@ -106,7 +140,7 @@ int main(int argc, char **argv)
|
|||||||
// 创建对话框
|
// 创建对话框
|
||||||
dlg = IupDialog(vbox_all);
|
dlg = IupDialog(vbox_all);
|
||||||
IupSetAttribute(dlg, "TITLE", "编辑环境变量 (IUP版)");
|
IupSetAttribute(dlg, "TITLE", "编辑环境变量 (IUP版)");
|
||||||
IupSetAttribute(dlg, "SIZE", "450x350");
|
IupSetAttribute(dlg, "SIZE", "500x400"); // 稍微调大一点
|
||||||
IupSetAttribute(dlg, "MINBOX", "NO");
|
IupSetAttribute(dlg, "MINBOX", "NO");
|
||||||
IupSetAttribute(dlg, "MAXBOX", "NO");
|
IupSetAttribute(dlg, "MAXBOX", "NO");
|
||||||
|
|
||||||
@@ -116,13 +150,23 @@ int main(int argc, char **argv)
|
|||||||
IupMessage("警告", "程序未以管理员身份运行,您只能查看,无法保存更改!");
|
IupMessage("警告", "程序未以管理员身份运行,您只能查看,无法保存更改!");
|
||||||
IupSetAttribute(dlg, "TITLE", "编辑环境变量 (只读模式)");
|
IupSetAttribute(dlg, "TITLE", "编辑环境变量 (只读模式)");
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 只读模式 (权限不足)");
|
IupSetAttribute(lbl_status, "TITLE", "状态: 只读模式 (权限不足)");
|
||||||
|
|
||||||
|
// 禁用修改类按钮
|
||||||
|
IupSetAttribute(btn_new, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_edit, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_browse, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_del, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_up, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_down, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_clean, "ACTIVE", "NO");
|
||||||
|
IupSetAttribute(btn_ok, "ACTIVE", "NO");
|
||||||
}
|
}
|
||||||
|
|
||||||
IupShowXY(dlg, IUP_CENTER, IUP_CENTER);
|
IupShowXY(dlg, IUP_CENTER, IUP_CENTER);
|
||||||
|
|
||||||
// IUP List APPEND 属性需要在控件 Map 之后才能生效
|
// IUP List APPEND 属性需要在控件 Map 之后才能生效
|
||||||
// IupShowXY 会触发 Map
|
// IupShowXY 会触发 Map
|
||||||
load_path();
|
load_all_paths();
|
||||||
|
|
||||||
IupMainLoop();
|
IupMainLoop();
|
||||||
IupClose();
|
IupClose();
|
||||||
|
|||||||
+78
-96
@@ -6,17 +6,23 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
// 从注册表加载PATH
|
// 内部辅助函数:加载单个列表
|
||||||
void load_path()
|
static void load_single_path(HKEY hKeyRoot, const wchar_t *regPath, Ihandle *list, StringList *cache)
|
||||||
{
|
{
|
||||||
|
// 清空旧缓存
|
||||||
|
clear_string_list(cache);
|
||||||
|
|
||||||
HKEY hKey;
|
HKEY hKey;
|
||||||
LONG res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_PATH, 0, KEY_READ, &hKey);
|
LONG res = RegOpenKeyExW(hKeyRoot, regPath, 0, KEY_READ, &hKey);
|
||||||
if (res != ERROR_SUCCESS)
|
if (res != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
// 只有 HKLM 失败才提示需要管理员,HKCU 失败可能是其他原因
|
||||||
|
if (hKeyRoot == HKEY_LOCAL_MACHINE)
|
||||||
{
|
{
|
||||||
char msg[512];
|
char msg[512];
|
||||||
snprintf(msg, sizeof(msg), "无法打开注册表键 (HKLM)。\n路径: %ls\n错误码: %ld\n\n请尝试右键点击程序 -> '以管理员身份运行'。", REG_PATH, res);
|
snprintf(msg, sizeof(msg), "无法打开注册表键 (HKLM)。\n路径: %ls\n错误码: %ld\n\n请尝试右键点击程序 -> '以管理员身份运行'。", regPath, res);
|
||||||
IupMessage("错误", msg);
|
IupMessage("错误", msg);
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 注册表读取失败");
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,172 +30,148 @@ void load_path()
|
|||||||
res = RegQueryValueExW(hKey, REG_VALUE, NULL, &type, NULL, &size);
|
res = RegQueryValueExW(hKey, REG_VALUE, NULL, &type, NULL, &size);
|
||||||
if (res == ERROR_SUCCESS)
|
if (res == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// 安全分配内存:size 是字节数,多分配 2 个字节给 null 终止符
|
|
||||||
wchar_t *buffer = (wchar_t *)malloc(size + 2);
|
wchar_t *buffer = (wchar_t *)malloc(size + 2);
|
||||||
if (!buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
IupMessage("错误", "内存分配失败!");
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化内存
|
|
||||||
memset(buffer, 0, size + 2);
|
memset(buffer, 0, size + 2);
|
||||||
|
|
||||||
if (RegQueryValueExW(hKey, REG_VALUE, NULL, &type, (LPBYTE)buffer, &size) == ERROR_SUCCESS)
|
if (RegQueryValueExW(hKey, REG_VALUE, NULL, &type, (LPBYTE)buffer, &size) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// 重新实现分割逻辑,避免 wcstok 的兼容性问题
|
|
||||||
wchar_t *current = buffer;
|
wchar_t *current = buffer;
|
||||||
wchar_t *next_semicolon = NULL;
|
wchar_t *next_semicolon = NULL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
// 清空列表
|
IupSetAttribute(list, "REMOVEITEM", "ALL");
|
||||||
IupSetAttribute(list_path, "REMOVEITEM", "ALL");
|
|
||||||
|
|
||||||
// 检查内容是否为空
|
|
||||||
if (wcslen(buffer) == 0)
|
|
||||||
{
|
|
||||||
IupMessage("提示", "读取到的 PATH 变量为空!");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*current)
|
while (*current)
|
||||||
{
|
{
|
||||||
// 查找下一个分号
|
|
||||||
next_semicolon = wcschr(current, L';');
|
next_semicolon = wcschr(current, L';');
|
||||||
if (next_semicolon)
|
if (next_semicolon)
|
||||||
{
|
*next_semicolon = L'\0';
|
||||||
*next_semicolon = L'\0'; // 临时截断
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳过空项
|
|
||||||
if (wcslen(current) > 0)
|
if (wcslen(current) > 0)
|
||||||
{
|
{
|
||||||
char *utf8_str = wide_to_utf8(current);
|
char *utf8_str = wide_to_utf8(current);
|
||||||
|
|
||||||
|
// 添加到列表
|
||||||
count++;
|
count++;
|
||||||
IupSetAttributeId(list_path, "", count, utf8_str);
|
IupSetAttributeId(list, "", count, utf8_str);
|
||||||
|
|
||||||
|
// 添加到缓存
|
||||||
|
add_string_list(cache, utf8_str);
|
||||||
|
|
||||||
free(utf8_str);
|
free(utf8_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_semicolon)
|
if (next_semicolon)
|
||||||
{
|
|
||||||
current = next_semicolon + 1;
|
current = next_semicolon + 1;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
IupSetInt(list_path, "COUNT", count); // 显式设置列表项数量
|
IupSetInt(list, "COUNT", count);
|
||||||
IupSetInt(list_path, "VALUE", 1); // 选中第一项
|
IupSetInt(list, "VALUE", 1);
|
||||||
|
|
||||||
// 刷新斑马纹样式
|
|
||||||
refresh_list_style();
|
|
||||||
|
|
||||||
char status_msg[100];
|
|
||||||
sprintf(status_msg, "状态: 已加载 %d 个条目", count);
|
|
||||||
IupSetAttribute(lbl_status, "TITLE", status_msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IupMessage("错误", "读取 PATH 值内容失败!");
|
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 读取值内容失败");
|
|
||||||
}
|
}
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
char msg[256];
|
|
||||||
sprintf(msg, "查询 PATH 值大小失败。错误码: %ld", res);
|
|
||||||
IupMessage("错误", msg);
|
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 查询值失败");
|
|
||||||
}
|
}
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存PATH到注册表
|
// 加载所有PATH
|
||||||
void save_path()
|
void load_all_paths()
|
||||||
{
|
{
|
||||||
if (!check_admin())
|
load_single_path(HKEY_LOCAL_MACHINE, REG_PATH_SYS, list_sys, &raw_sys_paths);
|
||||||
{
|
load_single_path(HKEY_CURRENT_USER, REG_PATH_USER, list_user, &raw_user_paths);
|
||||||
IupMessage("错误", "需要管理员权限才能保存更改!\n请重新以管理员身份运行程序。");
|
|
||||||
return;
|
refresh_list_style();
|
||||||
|
IupSetAttribute(lbl_status, "TITLE", "状态: 已加载系统和用户变量");
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = IupGetInt(list_path, "COUNT");
|
// 内部辅助函数:保存单个列表
|
||||||
if (count == 0)
|
static int save_single_path(HKEY hKeyRoot, const wchar_t *regPath, Ihandle *list)
|
||||||
{
|
{
|
||||||
// 警告:清空PATH是很危险的
|
int count = IupGetInt(list, "COUNT");
|
||||||
if (IupAlarm("警告", "PATH 为空!这可能导致系统命令无法使用。\n确定要保存吗?", "确定", "取消", NULL) != 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算所需缓冲区大小
|
// 计算大小
|
||||||
size_t total_len = 0;
|
size_t total_len = 0;
|
||||||
for (int i = 1; i <= count; i++)
|
for (int i = 1; i <= count; i++)
|
||||||
{
|
{
|
||||||
char *item = IupGetAttributeId(list_path, "", i);
|
char *item = IupGetAttributeId(list, "", i);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
wchar_t *witem = utf8_to_wide(item);
|
wchar_t *witem = utf8_to_wide(item);
|
||||||
total_len += wcslen(witem) + 1; // +1 for ';'
|
total_len += wcslen(witem) + 1;
|
||||||
free(witem);
|
free(witem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total_len += 1; // null terminator
|
total_len += 1;
|
||||||
|
|
||||||
wchar_t *buffer = (wchar_t *)malloc(total_len * sizeof(wchar_t));
|
wchar_t *buffer = (wchar_t *)malloc(total_len * sizeof(wchar_t));
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
{
|
return 0;
|
||||||
IupMessage("错误", "内存分配失败 (保存时)!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
buffer[0] = L'\0';
|
|
||||||
|
|
||||||
|
buffer[0] = L'\0';
|
||||||
for (int i = 1; i <= count; i++)
|
for (int i = 1; i <= count; i++)
|
||||||
{
|
{
|
||||||
char *item = IupGetAttributeId(list_path, "", i);
|
char *item = IupGetAttributeId(list, "", i);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
wchar_t *witem = utf8_to_wide(item);
|
wchar_t *witem = utf8_to_wide(item);
|
||||||
wcscat(buffer, witem);
|
wcscat(buffer, witem);
|
||||||
if (i < count)
|
if (i < count)
|
||||||
{
|
|
||||||
wcscat(buffer, L";");
|
wcscat(buffer, L";");
|
||||||
}
|
|
||||||
free(witem);
|
free(witem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入注册表
|
|
||||||
HKEY hKey;
|
HKEY hKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_PATH, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
|
int success = 0;
|
||||||
|
if (RegOpenKeyExW(hKeyRoot, regPath, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// 使用 REG_EXPAND_SZ 类型,因为 PATH 可能包含 %SystemRoot%
|
|
||||||
DWORD size = (wcslen(buffer) + 1) * sizeof(wchar_t);
|
DWORD size = (wcslen(buffer) + 1) * sizeof(wchar_t);
|
||||||
if (RegSetValueExW(hKey, REG_VALUE, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size) == ERROR_SUCCESS)
|
if (RegSetValueExW(hKey, REG_VALUE, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// 发送系统广播通知环境变量已更改
|
success = 1;
|
||||||
SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)L"Environment", SMTO_ABORTIFHUNG, 5000, NULL);
|
|
||||||
IupMessage("成功", "PATH 环境变量已更新!");
|
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 保存成功");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IupMessage("错误", "写入注册表失败!");
|
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 保存失败");
|
|
||||||
}
|
}
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
IupMessage("错误", "无法打开注册表进行写入。请检查权限!");
|
|
||||||
IupSetAttribute(lbl_status, "TITLE", "状态: 打开注册表失败");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存所有PATH
|
||||||
|
void save_all_paths()
|
||||||
|
{
|
||||||
|
if (!check_admin())
|
||||||
|
{
|
||||||
|
IupMessage("错误", "需要管理员权限才能保存更改!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备份
|
||||||
|
backup_registry();
|
||||||
|
|
||||||
|
int sys_ok = save_single_path(HKEY_LOCAL_MACHINE, REG_PATH_SYS, list_sys);
|
||||||
|
int user_ok = save_single_path(HKEY_CURRENT_USER, REG_PATH_USER, list_user);
|
||||||
|
|
||||||
|
if (sys_ok && user_ok)
|
||||||
|
{
|
||||||
|
SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)L"Environment", SMTO_ABORTIFHUNG, 5000, NULL);
|
||||||
|
IupMessage("成功", "系统和用户 PATH 环境变量均已更新!");
|
||||||
|
IupSetAttribute(lbl_status, "TITLE", "状态: 全部保存成功");
|
||||||
|
}
|
||||||
|
else if (sys_ok)
|
||||||
|
{
|
||||||
|
IupMessage("提示", "系统变量保存成功,但用户变量保存失败。");
|
||||||
|
}
|
||||||
|
else if (user_ok)
|
||||||
|
{
|
||||||
|
IupMessage("提示", "用户变量保存成功,但系统变量保存失败。");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IupMessage("错误", "保存失败!");
|
||||||
|
IupSetAttribute(lbl_status, "TITLE", "状态: 保存失败");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+180
-8
@@ -3,6 +3,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <iup.h>
|
#include <iup.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <direct.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
// 宽字符转UTF-8 (用于IUP显示)
|
// 宽字符转UTF-8 (用于IUP显示)
|
||||||
char *wide_to_utf8(const wchar_t *wstr)
|
char *wide_to_utf8(const wchar_t *wstr)
|
||||||
@@ -39,23 +42,192 @@ int check_admin()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新列表样式(斑马纹)
|
// 检查路径是否存在
|
||||||
void refresh_list_style()
|
static int path_exists(const char *path)
|
||||||
{
|
{
|
||||||
if (!list_path)
|
// 如果包含 %,说明是变量,无法直接检查存在性,默认视为有效
|
||||||
|
if (strchr(path, '%'))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
wchar_t *wpath = utf8_to_wide(path);
|
||||||
|
if (!wpath)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DWORD attr = GetFileAttributesW(wpath);
|
||||||
|
free(wpath);
|
||||||
|
|
||||||
|
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return 0;
|
||||||
|
return (attr & FILE_ATTRIBUTE_DIRECTORY); // 必须是目录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查路径是否存在(公开给外部使用)
|
||||||
|
int is_path_valid(const char *path)
|
||||||
|
{
|
||||||
|
return path_exists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新列表样式(斑马纹 + 有效性检查)
|
||||||
|
void refresh_single_list_style(Ihandle *list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
return;
|
return;
|
||||||
int count = IupGetInt(list_path, "COUNT");
|
int count = IupGetInt(list, "COUNT");
|
||||||
|
|
||||||
|
// 用于查重的简单数组(实际项目可以用哈希表)
|
||||||
|
// 为了简单,我们只用双重循环检查重复,性能在几百个条目下没问题
|
||||||
|
|
||||||
for (int i = 1; i <= count; i++)
|
for (int i = 1; i <= count; i++)
|
||||||
{
|
{
|
||||||
// 奇数行:白色
|
char *item = IupGetAttributeId(list, "", i);
|
||||||
// 偶数行:极浅灰色 (245 245 245)
|
if (!item)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 默认颜色:黑字
|
||||||
|
char fg_color[32] = "0 0 0";
|
||||||
|
|
||||||
|
// 1. 检查有效性
|
||||||
|
if (!path_exists(item))
|
||||||
|
{
|
||||||
|
// 无效路径:红色
|
||||||
|
sprintf(fg_color, "255 0 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查重复 (只检查当前项之前的项,如果之前出现过,当前项标橙)
|
||||||
|
for (int j = 1; j < i; j++)
|
||||||
|
{
|
||||||
|
char *prev_item = IupGetAttributeId(list, "", j);
|
||||||
|
if (prev_item && _stricmp(item, prev_item) == 0) // Windows 路径不区分大小写
|
||||||
|
{
|
||||||
|
// 重复路径:橙色
|
||||||
|
sprintf(fg_color, "255 128 0");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IupSetAttributeId(list, "ITEMFGCOLOR", i, fg_color);
|
||||||
|
|
||||||
|
// 斑马纹背景
|
||||||
if (i % 2 == 0)
|
if (i % 2 == 0)
|
||||||
{
|
{
|
||||||
IupSetAttributeId(list_path, "ITEMBGCOLOR", i, "245 245 245");
|
IupSetAttributeId(list, "ITEMBGCOLOR", i, "245 245 245");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IupSetAttributeId(list_path, "ITEMBGCOLOR", i, "255 255 255");
|
IupSetAttributeId(list, "ITEMBGCOLOR", i, "255 255 255");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新所有列表样式
|
||||||
|
void refresh_list_style()
|
||||||
|
{
|
||||||
|
refresh_single_list_style(list_sys);
|
||||||
|
refresh_single_list_style(list_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备份注册表
|
||||||
|
void backup_registry()
|
||||||
|
{
|
||||||
|
// 创建 records 目录
|
||||||
|
if (_mkdir("records") == -1)
|
||||||
|
{
|
||||||
|
// 目录可能已存在,忽略错误
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前时间
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm *tm_info = localtime(&t);
|
||||||
|
char time_str[64];
|
||||||
|
strftime(time_str, sizeof(time_str), "%Y%m%d_%H%M%S", tm_info);
|
||||||
|
|
||||||
|
// 构造备份文件名
|
||||||
|
char filename[256];
|
||||||
|
snprintf(filename, sizeof(filename), "records\\backup_%s.reg", time_str);
|
||||||
|
|
||||||
|
// 构造 reg export 命令
|
||||||
|
char full_cmd[1024];
|
||||||
|
snprintf(full_cmd, sizeof(full_cmd), "reg.exe export \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\" \"%s\" /y", filename);
|
||||||
|
|
||||||
|
// 使用 CreateProcess 隐藏窗口执行
|
||||||
|
STARTUPINFOA si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
memset(&si, 0, sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||||
|
si.wShowWindow = SW_HIDE; // 隐藏窗口
|
||||||
|
memset(&pi, 0, sizeof(pi));
|
||||||
|
|
||||||
|
if (CreateProcessA(NULL, full_cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
|
||||||
|
{
|
||||||
|
// 等待进程结束
|
||||||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
|
||||||
|
DWORD exit_code = 0;
|
||||||
|
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||||
|
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化字符串列表
|
||||||
|
void init_string_list(StringList *list)
|
||||||
|
{
|
||||||
|
list->items = NULL;
|
||||||
|
list->count = 0;
|
||||||
|
list->capacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不区分大小写的字符串查找 (简单实现)
|
||||||
|
char *stristr(const char *haystack, const char *needle)
|
||||||
|
{
|
||||||
|
if (!haystack || !needle)
|
||||||
|
return NULL;
|
||||||
|
if (*needle == '\0')
|
||||||
|
return (char *)haystack;
|
||||||
|
|
||||||
|
const char *h = haystack;
|
||||||
|
const char *n = needle;
|
||||||
|
const char *h_start = haystack;
|
||||||
|
|
||||||
|
while (*h)
|
||||||
|
{
|
||||||
|
h_start = h;
|
||||||
|
n = needle;
|
||||||
|
while (*h && *n && (tolower((unsigned char)*h) == tolower((unsigned char)*n)))
|
||||||
|
{
|
||||||
|
h++;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (*n == '\0')
|
||||||
|
return (char *)h_start;
|
||||||
|
h = h_start + 1;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加字符串到列表
|
||||||
|
void add_string_list(StringList *list, const char *str)
|
||||||
|
{
|
||||||
|
if (list->count >= list->capacity)
|
||||||
|
{
|
||||||
|
list->capacity = (list->capacity == 0) ? 16 : list->capacity * 2;
|
||||||
|
list->items = (char **)realloc(list->items, list->capacity * sizeof(char *));
|
||||||
|
}
|
||||||
|
list->items[list->count] = _strdup(str); // 复制字符串
|
||||||
|
list->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空字符串列表
|
||||||
|
void clear_string_list(StringList *list)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < list->count; i++)
|
||||||
|
{
|
||||||
|
free(list->items[i]);
|
||||||
|
}
|
||||||
|
free(list->items);
|
||||||
|
list->items = NULL;
|
||||||
|
list->count = 0;
|
||||||
|
list->capacity = 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user