#include "slide_combine_c.h" // 全局状态 AppState g_app_state = {0}; // 初始化通用控件 void init_common_controls() { INITCOMMONCONTROLSEX icc; icc.dwSize = sizeof(icc); icc.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&icc); } // 居中窗口 void center_window(HWND hwnd) { RECT rect; GetWindowRect(hwnd, &rect); int width = rect.right - rect.left; int height = rect.bottom - rect.top; int screen_width = GetSystemMetrics(SM_CXSCREEN); int screen_height = GetSystemMetrics(SM_CYSCREEN); int x = (screen_width - width) / 2; int y = (screen_height - height) / 2; SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } // 浏览文件夹 void browse_folder(HWND hwnd, char* path, const char* title) { BROWSEINFOA bi = {0}; bi.hwndOwner = hwnd; bi.lpszTitle = title; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; LPITEMIDLIST pidl = SHBrowseForFolderA(&bi); if (pidl) { if (SHGetPathFromIDListA(pidl, path)) { SetWindowTextA(GetDlgItem(hwnd, ID_EDIT_PDF_PATH + (&path - g_app_state.pdf_path) / MAX_PATH_LENGTH), path); } CoTaskMemFree(pidl); } } // 记录日志消息 void log_message(HWND hwnd, const char* message, BOOL is_error) { HWND hLog = GetDlgItem(hwnd, ID_LOG_TEXT); if (!hLog) return; // 获取当前时间 SYSTEMTIME st; GetLocalTime(&st); char timestamp[32]; sprintf_s(timestamp, sizeof(timestamp), "[%02d:%02d:%02d] ", st.wHour, st.wMinute, st.wSecond); // 构建完整消息 char full_message[MAX_BUFFER_SIZE]; if (is_error) { sprintf_s(full_message, sizeof(full_message), "%s❌ %s\r\n", timestamp, message); } else { sprintf_s(full_message, sizeof(full_message), "%s✅ %s\r\n", timestamp, message); } // 获取当前文本长度 int text_length = GetWindowTextLengthA(hLog); SendMessageA(hLog, EM_SETSEL, text_length, text_length); SendMessageA(hLog, EM_REPLACESEL, FALSE, (LPARAM)full_message); // 滚动到底部 SendMessageA(hLog, EM_SCROLLCARET, 0, 0); UpdateWindow(hwnd); } // 清空路径 void clear_paths(HWND hwnd) { SetWindowTextA(GetDlgItem(hwnd, ID_EDIT_PDF_PATH), ""); SetWindowTextA(GetDlgItem(hwnd, ID_EDIT_TXT_PATH), ""); SetWindowTextA(GetDlgItem(hwnd, ID_EDIT_OUTPUT_PATH), ""); g_app_state.pdf_path[0] = '\0'; g_app_state.txt_path[0] = '\0'; g_app_state.output_path[0] = '\0'; HWND hLog = GetDlgItem(hwnd, ID_LOG_TEXT); SetWindowTextA(hLog, ""); log_message(hwnd, "界面已清空", FALSE); } // 验证路径 BOOL is_valid_path(const char* path) { return path && strlen(path) > 0 && PathFileExistsA(path); } // 处理过程 DWORD WINAPI processing_thread(LPVOID param) { HWND hwnd = (HWND)param; g_app_state.processing = TRUE; log_message(hwnd, "开始处理PDF书签文件...", FALSE); // 获取路径 GetWindowTextA(GetDlgItem(hwnd, ID_EDIT_PDF_PATH), g_app_state.pdf_path, MAX_PATH_LENGTH); GetWindowTextA(GetDlgItem(hwnd, ID_EDIT_TXT_PATH), g_app_state.txt_path, MAX_PATH_LENGTH); GetWindowTextA(GetDlgItem(hwnd, ID_EDIT_OUTPUT_PATH), g_app_state.output_path, MAX_PATH_LENGTH); // 验证路径 if (!is_valid_path(g_app_state.pdf_path)) { log_message(hwnd, "错误:PDF文件夹路径无效或不存在", TRUE); g_app_state.processing = FALSE; return 1; } if (!is_valid_path(g_app_state.txt_path)) { log_message(hwnd, "错误:TXT源文件路径无效或不存在", TRUE); g_app_state.processing = FALSE; return 1; } // 确保输出目录存在 if (!is_valid_path(g_app_state.output_path)) { if (!CreateDirectoryA(g_app_state.output_path, NULL)) { log_message(hwnd, "错误:无法创建输出目录", TRUE); g_app_state.processing = FALSE; return 1; } log_message(hwnd, "已创建输出目录", FALSE); } // 处理文件 FileGroup* groups = NULL; int group_count = 0; ErrorCode result = process_all_files(g_app_state.pdf_path, g_app_state.txt_path, &groups, &group_count); if (result != ERROR_NONE) { char error_msg[MAX_BUFFER_SIZE]; sprintf_s(error_msg, sizeof(error_msg), "处理失败:%d", result); log_message(hwnd, error_msg, TRUE); g_app_state.processing = FALSE; return 1; } log_message(hwnd, "成功读取文件,开始保存合并结果", FALSE); // 保存结果 result = save_all_results(groups, group_count, g_app_state.output_path); if (result == ERROR_NONE) { char success_msg[MAX_BUFFER_SIZE]; sprintf_s(success_msg, sizeof(success_msg), "处理完成!成功合并 %d 个文件组", group_count); log_message(hwnd, success_msg, FALSE); for (int i = 0; i < group_count; i++) { char file_msg[MAX_BUFFER_SIZE]; sprintf_s(file_msg, sizeof(file_msg), "✓ 已生成:%s.txt", groups[i].base_name); log_message(hwnd, file_msg, FALSE); } MessageBoxA(hwnd, "PDF书签合并完成!", "成功", MB_OK | MB_ICONINFORMATION); } else { log_message(hwnd, "保存结果时发生错误", TRUE); MessageBoxA(hwnd, "保存结果时发生错误", "错误", MB_OK | MB_ICONERROR); } // 释放内存 free_memory(groups, group_count); g_app_state.processing = FALSE; return 0; } // 开始处理 void start_processing(HWND hwnd) { if (g_app_state.processing) { MessageBoxA(hwnd, "正在处理中,请等待", "提示", MB_OK | MB_ICONINFORMATION); return; } // 创建处理线程 HANDLE hThread = CreateThread(NULL, 0, processing_thread, hwnd, 0, NULL); if (hThread) { CloseHandle(hThread); } else { MessageBoxA(hwnd, "无法创建处理线程", "错误", MB_OK | MB_ICONERROR); } } // 显示错误消息 void show_error(HWND hwnd, const char* message) { MessageBoxA(hwnd, message, "错误", MB_OK | MB_ICONERROR); } // 显示信息消息 void show_info(HWND hwnd, const char* message) { MessageBoxA(hwnd, message, "信息", MB_OK | MB_ICONINFORMATION); } // 窗口过程 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { // 创建字体 g_app_state.hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Microsoft YaHei"); // 创建背景画刷 g_app_state.hBgBrush = CreateSolidBrush(RGB(240, 240, 240)); return 0; } case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_BUTTON_BROWSE_PDF: browse_folder(hwnd, g_app_state.pdf_path, "选择包含PDF文件夹的路径"); break; case ID_BUTTON_BROWSE_TXT: browse_folder(hwnd, g_app_state.txt_path, "选择包含TXT源文件的路径"); break; case ID_BUTTON_BROWSE_OUTPUT: browse_folder(hwnd, g_app_state.output_path, "选择输出路径"); break; case ID_BUTTON_PROCESS: start_processing(hwnd); break; case ID_BUTTON_CLEAR: clear_paths(hwnd); break; case ID_BUTTON_EXIT: DestroyWindow(hwnd); break; } return 0; } case WM_CTLCOLORSTATIC: case WM_CTLCOLOREDIT: { HDC hdc = (HDC)wParam; SetTextColor(hdc, RGB(0, 0, 0)); SetBkMode(hdc, TRANSPARENT); return (LRESULT)g_app_state.hBgBrush; } case WM_DESTROY: { if (g_app_state.hFont) DeleteObject(g_app_state.hFont); if (g_app_state.hBgBrush) DeleteObject(g_app_state.hBgBrush); PostQuitMessage(0); return 0; } default: return DefWindowProc(hwnd, msg, wParam, lParam); } } // 创建主窗口 BOOL create_main_window(HINSTANCE hInstance, int nCmdShow) { // 注册窗口类 WNDCLASSA wc = {0}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = "SlideCombineWindow"; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); if (!RegisterClassA(&wc)) { return FALSE; } // 创建窗口 HWND hwnd = CreateWindowExA( 0, "SlideCombineWindow", "PDF书签合并工具 v2.0 - C语言版", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL ); if (!hwnd) { return FALSE; } // 创建控件 int y = CONTROL_MARGIN; // PDF路径 CreateWindowA("STATIC", "PDF文件夹路径(含FreePic2Pdf_bkmk.txt文件):", WS_VISIBLE | WS_CHILD, CONTROL_MARGIN, y, WINDOW_WIDTH - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, NULL, hInstance, NULL); y += CONTROL_HEIGHT + 5; CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, CONTROL_MARGIN, y, WINDOW_WIDTH - 100 - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, (HMENU)ID_EDIT_PDF_PATH, hInstance, NULL); CreateWindowA("BUTTON", "浏览", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, WINDOW_WIDTH - 90 - CONTROL_MARGIN, y, 80, CONTROL_HEIGHT, hwnd, (HMENU)ID_BUTTON_BROWSE_PDF, hInstance, NULL); y += CONTROL_HEIGHT + CONTROL_MARGIN; // TXT路径 CreateWindowA("STATIC", "TXT源文件路径:", WS_VISIBLE | WS_CHILD, CONTROL_MARGIN, y, WINDOW_WIDTH - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, NULL, hInstance, NULL); y += CONTROL_HEIGHT + 5; CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, CONTROL_MARGIN, y, WINDOW_WIDTH - 100 - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, (HMENU)ID_EDIT_TXT_PATH, hInstance, NULL); CreateWindowA("BUTTON", "浏览", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, WINDOW_WIDTH - 90 - CONTROL_MARGIN, y, 80, CONTROL_HEIGHT, hwnd, (HMENU)ID_BUTTON_BROWSE_TXT, hInstance, NULL); y += CONTROL_HEIGHT + CONTROL_MARGIN; // 输出路径 CreateWindowA("STATIC", "输出路径:", WS_VISIBLE | WS_CHILD, CONTROL_MARGIN, y, WINDOW_WIDTH - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, NULL, hInstance, NULL); y += CONTROL_HEIGHT + 5; CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, CONTROL_MARGIN, y, WINDOW_WIDTH - 100 - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, (HMENU)ID_EDIT_OUTPUT_PATH, hInstance, NULL); CreateWindowA("BUTTON", "浏览", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, WINDOW_WIDTH - 90 - CONTROL_MARGIN, y, 80, CONTROL_HEIGHT, hwnd, (HMENU)ID_BUTTON_BROWSE_OUTPUT, hInstance, NULL); y += CONTROL_HEIGHT + CONTROL_MARGIN; // 操作按钮 CreateWindowA("BUTTON", "🚀 开始合并", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, CONTROL_MARGIN, y, 100, CONTROL_HEIGHT, hwnd, (HMENU)ID_BUTTON_PROCESS, hInstance, NULL); CreateWindowA("BUTTON", "🔄 清空", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, CONTROL_MARGIN + 110, y, 80, CONTROL_HEIGHT, hwnd, (HMENU)ID_BUTTON_CLEAR, hInstance, NULL); CreateWindowA("BUTTON", "❌ 退出", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, CONTROL_MARGIN + 200, y, 80, CONTROL_HEIGHT, hwnd, (HMENU)ID_BUTTON_EXIT, hInstance, NULL); y += CONTROL_HEIGHT + CONTROL_MARGIN; // 日志区域 CreateWindowA("STATIC", "📊 处理日志:", WS_VISIBLE | WS_CHILD, CONTROL_MARGIN, y, WINDOW_WIDTH - 2 * CONTROL_MARGIN, CONTROL_HEIGHT, hwnd, NULL, hInstance, NULL); y += CONTROL_HEIGHT + 5; CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, CONTROL_MARGIN, y, WINDOW_WIDTH - 2 * CONTROL_MARGIN, WINDOW_HEIGHT - y - CONTROL_MARGIN - 20, hwnd, (HMENU)ID_LOG_TEXT, hInstance, NULL); // 设置字体 SendMessageA(hwnd, WM_SETFONT, (WPARAM)g_app_state.hFont, TRUE); // 居中并显示窗口 center_window(hwnd); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); g_app_state.hwnd = hwnd; return TRUE; } // 主函数 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { init_common_controls(); if (!create_main_window(hInstance, nCmdShow)) { MessageBoxA(NULL, "无法创建主窗口", "错误", MB_OK | MB_ICONERROR); return 1; } // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }