mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-05-09 18:02:52 +08:00
refactor: 提取UI组件到独立模块并改进拖拽支持
- 将列表、按钮等UI创建代码从main.c移至ui.c/ui.h - 添加Windows UIPI消息过滤以支持管理员模式下的文件拖拽 - 更新Makefile和构建脚本以包含新的UI模块 - 清理旧的备份注册表文件并更新README文档
This commit is contained in:
@@ -18,9 +18,9 @@ CFLAGS = -Wall -O2 -I$(INCLUDE_DIR) -I$(LOCAL_INCLUDE_DIR) -D_WIN32 -DUNICODE -D
|
||||
LDFLAGS = -L$(LIB_DIR) -liup -liupcd -lgdi32 -lcomdlg32 -lcomctl32 -luuid -lole32 -ladvapi32 -mwindows
|
||||
|
||||
# Source
|
||||
SRC = src/main.c src/utils.c src/registry.c src/callbacks.c
|
||||
SRC = src/main.c src/utils.c src/registry.c src/callbacks.c src/ui.c
|
||||
RES = ico/resources.rc
|
||||
OBJ = $(OBJ_DIR)/main.o $(OBJ_DIR)/utils.o $(OBJ_DIR)/registry.o $(OBJ_DIR)/callbacks.o $(OBJ_DIR)/resources.o
|
||||
OBJ = $(OBJ_DIR)/main.o $(OBJ_DIR)/utils.o $(OBJ_DIR)/registry.o $(OBJ_DIR)/callbacks.o $(OBJ_DIR)/ui.o $(OBJ_DIR)/resources.o
|
||||
EXE = $(BIN_DIR)/PathEditor.exe
|
||||
|
||||
all: $(BIN_DIR) $(OBJ_DIR) $(EXE)
|
||||
@@ -46,6 +46,9 @@ $(OBJ_DIR)/registry.o: src/registry.c
|
||||
$(OBJ_DIR)/callbacks.o: src/callbacks.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR)/ui.o: src/ui.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR)/resources.o: ico/resources.rc
|
||||
$(WINDRES) -i $< -o $@
|
||||
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
# Path Editor (系统环境变量编辑器)
|
||||
|
||||
一个简单、轻量级的 Windows 系统环境变量(PATH)编辑器,基于 C 语言和 IUP 图形库开发。
|
||||
一个简单、轻量级但功能强大的 Windows 系统环境变量(PATH)编辑器,基于 C 语言和 IUP 图形库开发。
|
||||
|
||||
## ✨ 功能特点
|
||||
|
||||
* **可视化编辑**:直观地查看和管理系统 PATH 环境变量。
|
||||
* **安全操作**:必须以管理员身份运行才能保存更改,防止误操作。
|
||||
* **🛡️ 安全第一**:
|
||||
* **自动备份**:每次保存前自动备份注册表,防止意外。
|
||||
* **只读模式**:非管理员运行时自动切换到只读模式,防止误操作。
|
||||
* **权限检测**:智能检测当前运行权限。
|
||||
|
||||
* **📑 双视图管理**:
|
||||
* 完美支持 **System (系统变量)** 和 **User (用户变量)** 的分离查看与编辑。
|
||||
* 清晰的 Tab 标签页切换。
|
||||
|
||||
* **🔴 智能诊断与维护**:
|
||||
* **无效路径高亮**:自动检测路径是否存在,不存在的显示为红色。
|
||||
* **重复路径高亮**:自动检测重复项,重复的显示为橙色。
|
||||
* **一键清理**:智能移除所有无效和重复的路径,保持环境整洁。
|
||||
|
||||
* **📂 高效交互**:
|
||||
* **拖拽支持**:直接将文件夹拖入窗口即可添加(支持管理员模式下的 UIPI 穿透)。
|
||||
* **实时搜索**:顶部搜索框支持不区分大小写的实时过滤查找。
|
||||
* **快捷键**:支持 Delete 键快速删除选中项。
|
||||
|
||||
* **便捷管理**:
|
||||
* ➕ **新建**:添加新路径到列表。
|
||||
* 📂 **浏览**:直接从文件资源管理器选择目录添加。
|
||||
* ✏️ **编辑**:修改现有路径。
|
||||
* ✏️ **编辑**:双击或点击按钮修改现有路径。
|
||||
* 🗑️ **删除**:移除不需要的路径。
|
||||
* ⬆️⬇️ **排序**:上移/下移调整路径优先级。
|
||||
* **轻量级**:原生 C 语言编写,运行速度快,占用资源少。
|
||||
|
||||
* **轻量级**:原生 C 语言编写,无臃肿依赖,运行速度极快。
|
||||
|
||||
## 📦 下载与安装
|
||||
|
||||
@@ -30,6 +48,7 @@
|
||||
* GCC 编译器 (推荐 MinGW-w64)
|
||||
* Make 工具
|
||||
* IUP 库 (已包含在 `libs` 目录下)
|
||||
* Inno Setup 6 (仅打包需要)
|
||||
|
||||
### 编译步骤
|
||||
|
||||
@@ -54,16 +73,22 @@
|
||||
本项目使用 Inno Setup 生成安装包。
|
||||
|
||||
1. 确保已安装 [Inno Setup 6](https://jrsoftware.org/isdl.php)。
|
||||
2. 编译项目生成 exe 文件。
|
||||
3. 使用 Inno Setup 编译 `dist/installer.iss` 脚本。
|
||||
2. 运行根目录下的 `build_installer.bat` 脚本。
|
||||
3. 生成的安装包将位于 `dist/dist/PathEditorSetup.exe`。
|
||||
|
||||
## 📝 使用说明
|
||||
|
||||
1. **启动**:右键点击程序图标,选择“以管理员身份运行”。
|
||||
2. **查看**:程序启动后会自动加载当前的系统 PATH 变量。
|
||||
3. **修改**:使用右侧按钮栏进行添加、删除、移动等操作。
|
||||
4. **保存**:操作完成后,务必点击底部的【确定】按钮保存更改。
|
||||
5. **生效**:保存后,某些正在运行的程序可能需要重启才能识别新的环境变量。CMD 或 PowerShell 窗口需要重新打开。
|
||||
* **红色**条目表示路径不存在。
|
||||
* **橙色**条目表示路径重复。
|
||||
3. **搜索**:在顶部输入关键词可快速筛选。
|
||||
4. **修改**:
|
||||
* 拖拽文件夹到列表可直接添加。
|
||||
* 使用右侧按钮栏进行常规操作。
|
||||
* 点击“一键清理”可自动删除无效和重复项。
|
||||
5. **保存**:操作完成后,务必点击底部的【确定】按钮保存更改。
|
||||
6. **生效**:保存后,某些正在运行的程序可能需要重启才能识别新的环境变量。CMD 或 PowerShell 窗口需要重新打开。
|
||||
|
||||
## 👤 作者信息
|
||||
|
||||
|
||||
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.
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
echo Copying DLLs...
|
||||
if not exist bin mkdir bin
|
||||
copy /Y "libs\iup-3.31_Win64_dllw6_lib\*.dll" bin\
|
||||
|
||||
echo Building Installer...
|
||||
"D:\Program Files (x86)\Inno Setup 6\ISCC.exe" "dist\installer.iss"
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Installer build failed!
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
echo Done! Installer is in dist\dist\
|
||||
pause
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef UI_H
|
||||
#define UI_H
|
||||
|
||||
#include <iup.h>
|
||||
|
||||
// 创建列表控件
|
||||
Ihandle *create_path_list();
|
||||
|
||||
// 创建右侧功能按钮区域
|
||||
Ihandle *create_main_buttons();
|
||||
|
||||
// 创建底部按钮区域
|
||||
Ihandle *create_bottom_buttons();
|
||||
|
||||
#endif // UI_H
|
||||
+36
-73
@@ -7,33 +7,27 @@
|
||||
#include "utils.h"
|
||||
#include "registry.h"
|
||||
#include "callbacks.h"
|
||||
#include "ui.h"
|
||||
|
||||
// 定义 Windows 消息常量
|
||||
#ifndef WM_COPYGLOBALDATA
|
||||
#define WM_COPYGLOBALDATA 0x0049
|
||||
#endif
|
||||
|
||||
#ifndef MSGFLT_ADD
|
||||
#define MSGFLT_ADD 1
|
||||
#endif
|
||||
|
||||
// 全局变量定义
|
||||
StringList raw_sys_paths = {0};
|
||||
StringList raw_user_paths = {0};
|
||||
|
||||
// 全局控件定义
|
||||
Ihandle *dlg, *tabs_main, *list_sys, *list_user, *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_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;
|
||||
}
|
||||
Ihandle *btn_ok, *btn_cancel, *btn_help; // 确认取消帮助按钮
|
||||
Ihandle *btn_clean; // 一键清理按钮
|
||||
Ihandle *txt_search; // 搜索框
|
||||
|
||||
// 主函数
|
||||
int main(int argc, char **argv)
|
||||
@@ -44,6 +38,24 @@ int main(int argc, char **argv)
|
||||
IupOpen(&argc, &argv);
|
||||
IupSetGlobal("UTF8MODE", "YES");
|
||||
|
||||
// 在管理员模式下,解决无法拖拽文件到列表框的问题 (UIPI)
|
||||
// 需要加载 User32.dll 获取 ChangeWindowMessageFilter 函数
|
||||
HMODULE hUser32 = LoadLibraryW(L"user32.dll");
|
||||
if (hUser32)
|
||||
{
|
||||
typedef BOOL(WINAPI * ChangeWindowMessageFilterProc)(UINT, DWORD);
|
||||
ChangeWindowMessageFilterProc pChangeWindowMessageFilter =
|
||||
(ChangeWindowMessageFilterProc)GetProcAddress(hUser32, "ChangeWindowMessageFilter");
|
||||
|
||||
if (pChangeWindowMessageFilter)
|
||||
{
|
||||
pChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
|
||||
pChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
|
||||
pChangeWindowMessageFilter(WM_COPYGLOBALDATA, MSGFLT_ADD);
|
||||
}
|
||||
FreeLibrary(hUser32);
|
||||
}
|
||||
|
||||
// 创建两个列表控件
|
||||
list_sys = create_path_list();
|
||||
list_user = create_path_list();
|
||||
@@ -63,42 +75,8 @@ int main(int argc, char **argv)
|
||||
IupSetAttribute(tabs_main, "TABTITLE1", "用户变量 (User)");
|
||||
IupSetAttribute(tabs_main, "TABTYPE", "TOP");
|
||||
|
||||
// 创建右侧按钮
|
||||
btn_new = IupButton("新建(N)", NULL);
|
||||
btn_edit = IupButton("编辑(E)", NULL);
|
||||
btn_browse = IupButton("浏览(B)...", NULL);
|
||||
btn_del = IupButton("删除(D)", NULL);
|
||||
btn_up = IupButton("上移(U)", NULL);
|
||||
btn_down = IupButton("下移(O)", NULL);
|
||||
btn_clean = IupButton("一键清理", NULL);
|
||||
|
||||
// 设置按钮回调
|
||||
IupSetCallback(btn_new, "ACTION", (Icallback)btn_new_cb);
|
||||
IupSetCallback(btn_edit, "ACTION", (Icallback)btn_edit_cb);
|
||||
IupSetCallback(btn_browse, "ACTION", (Icallback)btn_browse_cb);
|
||||
IupSetCallback(btn_del, "ACTION", (Icallback)btn_del_cb);
|
||||
IupSetCallback(btn_up, "ACTION", (Icallback)btn_up_cb);
|
||||
IupSetCallback(btn_down, "ACTION", (Icallback)btn_down_cb);
|
||||
IupSetCallback(btn_clean, "ACTION", (Icallback)btn_clean_cb);
|
||||
|
||||
// 设置按钮大小 (宽度和高度都增加约1/4)
|
||||
IupSetAttribute(btn_new, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_edit, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_browse, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_del, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_up, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_down, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_clean, "RASTERSIZE", "100x32");
|
||||
|
||||
Ihandle *vbox_btns = IupVbox(
|
||||
btn_new, btn_edit, btn_browse, btn_del,
|
||||
IupFill(), // 间隔
|
||||
btn_clean, // 放在上移下移之前,或者最下面,这里放在中间偏下
|
||||
IupFill(),
|
||||
btn_up, btn_down,
|
||||
NULL);
|
||||
IupSetAttribute(vbox_btns, "GAP", "5");
|
||||
IupSetAttribute(vbox_btns, "MARGIN", "0x0");
|
||||
// 创建右侧按钮区域
|
||||
Ihandle *vbox_btns = create_main_buttons();
|
||||
|
||||
// 上部布局:Tabs + 按钮
|
||||
Ihandle *hbox_main = IupHbox(tabs_main, vbox_btns, NULL);
|
||||
@@ -109,23 +87,8 @@ int main(int argc, char **argv)
|
||||
lbl_status = IupLabel("状态: 就绪");
|
||||
IupSetAttribute(lbl_status, "EXPAND", "HORIZONTAL");
|
||||
|
||||
// 底部按钮
|
||||
btn_ok = IupButton("确定", NULL);
|
||||
btn_cancel = IupButton("取消", NULL);
|
||||
btn_help = IupButton("帮助(?)", NULL);
|
||||
|
||||
IupSetCallback(btn_ok, "ACTION", (Icallback)btn_ok_cb);
|
||||
IupSetCallback(btn_cancel, "ACTION", (Icallback)btn_cancel_cb);
|
||||
IupSetCallback(btn_help, "ACTION", (Icallback)btn_help_cb);
|
||||
|
||||
IupSetAttribute(btn_ok, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_cancel, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_help, "RASTERSIZE", "100x32");
|
||||
|
||||
Ihandle *hbox_bottom = IupHbox(lbl_status, IupFill(), btn_help, btn_ok, btn_cancel, NULL);
|
||||
IupSetAttribute(hbox_bottom, "GAP", "10");
|
||||
IupSetAttribute(hbox_bottom, "MARGIN", "10x10");
|
||||
IupSetAttribute(hbox_bottom, "ALIGNMENT", "ACENTER");
|
||||
// 创建底部按钮区域
|
||||
Ihandle *hbox_bottom = create_bottom_buttons();
|
||||
|
||||
// 总体布局
|
||||
Ihandle *vbox_all = IupVbox(
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "ui.h"
|
||||
#include "globals.h"
|
||||
#include "callbacks.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// 创建列表控件
|
||||
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;
|
||||
}
|
||||
|
||||
// 创建右侧功能按钮区域
|
||||
Ihandle *create_main_buttons()
|
||||
{
|
||||
// 创建右侧按钮
|
||||
btn_new = IupButton("新建(N)", NULL);
|
||||
btn_edit = IupButton("编辑(E)", NULL);
|
||||
btn_browse = IupButton("浏览(B)...", NULL);
|
||||
btn_del = IupButton("删除(D)", NULL);
|
||||
btn_up = IupButton("上移(U)", NULL);
|
||||
btn_down = IupButton("下移(O)", NULL);
|
||||
btn_clean = IupButton("一键清理", NULL);
|
||||
|
||||
// 设置按钮回调
|
||||
IupSetCallback(btn_new, "ACTION", (Icallback)btn_new_cb);
|
||||
IupSetCallback(btn_edit, "ACTION", (Icallback)btn_edit_cb);
|
||||
IupSetCallback(btn_browse, "ACTION", (Icallback)btn_browse_cb);
|
||||
IupSetCallback(btn_del, "ACTION", (Icallback)btn_del_cb);
|
||||
IupSetCallback(btn_up, "ACTION", (Icallback)btn_up_cb);
|
||||
IupSetCallback(btn_down, "ACTION", (Icallback)btn_down_cb);
|
||||
IupSetCallback(btn_clean, "ACTION", (Icallback)btn_clean_cb);
|
||||
|
||||
// 设置按钮大小 (宽度和高度都增加约1/4)
|
||||
IupSetAttribute(btn_new, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_edit, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_browse, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_del, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_up, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_down, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_clean, "RASTERSIZE", "100x32");
|
||||
|
||||
Ihandle *vbox_btns = IupVbox(
|
||||
btn_new, btn_edit, btn_browse, btn_del,
|
||||
IupFill(), // 间隔
|
||||
btn_clean, // 放在上移下移之前,或者最下面,这里放在中间偏下
|
||||
IupFill(),
|
||||
btn_up, btn_down,
|
||||
NULL);
|
||||
IupSetAttribute(vbox_btns, "GAP", "5");
|
||||
IupSetAttribute(vbox_btns, "MARGIN", "0x0");
|
||||
|
||||
return vbox_btns;
|
||||
}
|
||||
|
||||
// 创建底部按钮区域
|
||||
Ihandle *create_bottom_buttons()
|
||||
{
|
||||
// 底部按钮
|
||||
btn_ok = IupButton("确定", NULL);
|
||||
btn_cancel = IupButton("取消", NULL);
|
||||
btn_help = IupButton("帮助(?)", NULL);
|
||||
|
||||
IupSetCallback(btn_ok, "ACTION", (Icallback)btn_ok_cb);
|
||||
IupSetCallback(btn_cancel, "ACTION", (Icallback)btn_cancel_cb);
|
||||
IupSetCallback(btn_help, "ACTION", (Icallback)btn_help_cb);
|
||||
|
||||
IupSetAttribute(btn_ok, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_cancel, "RASTERSIZE", "100x32");
|
||||
IupSetAttribute(btn_help, "RASTERSIZE", "100x32");
|
||||
|
||||
Ihandle *hbox_bottom = IupHbox(lbl_status, IupFill(), btn_help, btn_ok, btn_cancel, NULL);
|
||||
IupSetAttribute(hbox_bottom, "GAP", "10");
|
||||
IupSetAttribute(hbox_bottom, "MARGIN", "10x10");
|
||||
IupSetAttribute(hbox_bottom, "ALIGNMENT", "ACENTER");
|
||||
|
||||
return hbox_bottom;
|
||||
}
|
||||
Reference in New Issue
Block a user