diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c06d6e1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 4.0) +project(cyzg C) + +set(CMAKE_C_STANDARD 11) + +add_executable(cyzg main.c) + +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os -DNDEBUG") + + diff --git a/backend.py b/backend.py index 6c563de..a99cb46 100644 --- a/backend.py +++ b/backend.py @@ -202,6 +202,3 @@ class Backend: elif item == "错过的题": self.global_filter +=" OR q.count > 3 " self.global_filter += ")" - - - diff --git a/data.db.zip b/data.db.zip index d31e396..31fe72d 100644 Binary files a/data.db.zip and b/data.db.zip differ diff --git a/embed.py b/embed.py new file mode 100644 index 0000000..f7c58d3 --- /dev/null +++ b/embed.py @@ -0,0 +1,17 @@ +# embed.py +def file_to_c_array(filename, var_name): + try: + with open(filename, 'rb') as f: + data = f.read() + hex_str = ', '.join(f'0x{b:02x}' for b in data) + return f'// Resource: {filename}\nconst unsigned char {var_name}[] = {{ {hex_str} }};\nconst int {var_name}_len = {len(data)};\n\n' + except FileNotFoundError: + print(f"ERROR: File not found: {filename}") + exit(1) + +with open('embedded.h', 'w', encoding='utf-8') as f: + f.write(file_to_c_array('init.py', 'script_main')) + f.write(file_to_c_array('data.db.zip', 'data_zip')) + f.write(file_to_c_array('cyzg.zip', 'cyzg_zip')) + +print("done") \ No newline at end of file diff --git a/init.py b/init.py new file mode 100644 index 0000000..6acad01 --- /dev/null +++ b/init.py @@ -0,0 +1,10 @@ +import os +import zipfile + +code_zip = "cyzg.zip" +if os.path.exists(code_zip): + with zipfile.ZipFile(code_zip, 'r') as zip_ref: + zip_ref.extractall(".") + +if os.path.exists("main.py"): + os.system("python main.py") \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..ed3cf91 --- /dev/null +++ b/main.c @@ -0,0 +1,124 @@ +#include +#include + +#include "embedded.h" + +// 简化路径拼接宏 +#define APPEND_PATH(base, file) (lstrcpyA(lstrcatA(lstrcpyA((base), (base)), "\\"), (file))) + +// 检查文件是否存在 +static BOOL file_exists(const char* filename) { + DWORD attrs = GetFileAttributesA(filename); + return (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY)); +} + +// 仅当文件不存在时保存资源 +static BOOL save_resource_if_missing(const unsigned char* data, int len, const char* filepath) { + if (file_exists(filepath)) return TRUE; + + HANDLE hFile = CreateFileA(filepath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return FALSE; + + DWORD written; + BOOL result = WriteFile(hFile, data, len, &written, NULL); + CloseHandle(hFile); + + return result && (written == len); +} + +// 检测 Python 是否可用 +static BOOL CheckPythonAvailable() { + char python_path[MAX_PATH]; + if (SearchPathA(NULL, "python.exe", NULL, MAX_PATH, python_path, NULL) == 0) { + return FALSE; + } + + CHAR cmd[MAX_PATH + 32]; + sprintf_s(cmd, sizeof(cmd), "\"%s\" --version", python_path); + + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION pi = { 0 }; + + if (!CreateProcessA(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { + return FALSE; + } + + WaitForSingleObject(pi.hProcess, 5000); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return TRUE; +} + +// 安全地从完整路径中提取目录部分(不包含最后的反斜杠) +void GetDirectoryFromPath(char* path) { + char* last_slash = strrchr(path, '\\'); + if (last_slash != NULL) { + *last_slash = '\0'; // 截断文件名 + } else { + // 如果没有反斜杠,说明只有文件名,保留原路径或设为 "." + lstrcpyA(path, "."); + } +} + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE h0, LPSTR cmd, int nShow) { + // 检查 Python + if (!CheckPythonAvailable()) { + MessageBoxA(NULL, "Python is not available. Please install Python first.", "Error", MB_OK | MB_ICONERROR); + return 1; + } + + CHAR exe_dir[MAX_PATH] = { 0 }; + CHAR cash_dir[MAX_PATH] = { 0 }; + CHAR command[MAX_PATH * 2] = { 0 }; + + // 获取当前目录 + GetModuleFileNameA(NULL, exe_dir, MAX_PATH); + GetDirectoryFromPath(exe_dir); + + lstrcpyA(cash_dir, exe_dir); + lstrcatA(cash_dir, "\\cash"); + + // 创建 cash 目录 + if (!CreateDirectoryA(cash_dir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { + MessageBoxA(NULL, "Failed to create 'cash' directory.", "Error", MB_OK | MB_ICONERROR); + return 1; + } + + // 定义资源项结构 + struct { + const unsigned char* data; + int len; + const char* filename; + } resources[] = { + { script_main, script_main_len, "\\init.py" }, + { data_zip, data_zip_len, "\\data.db.zip" }, + { cyzg_zip, cyzg_zip_len, "\\cyzg.zip" } + }; + + // 提取所有嵌入资源(如果不存在) + for (int i = 0; i < _countof(resources); ++i) { + CHAR filepath[MAX_PATH]; + lstrcpyA(filepath, cash_dir); + lstrcatA(filepath, resources[i].filename); + + if (!save_resource_if_missing(resources[i].data, resources[i].len, filepath)) { + MessageBoxA(NULL, "Failed to extract embedded resource.", "Error", MB_OK | MB_ICONERROR); + return 1; + } + } + + // 判断是否已完成初始化 + CHAR main_py[MAX_PATH], data_db[MAX_PATH]; + lstrcpyA(main_py, cash_dir); lstrcatA(main_py, "\\main.py"); + lstrcpyA(data_db, cash_dir); lstrcatA(data_db, "\\data.db"); + + const char* script_to_run = file_exists(main_py) && file_exists(data_db) ? "main.py" : "init.py"; + + // 构造并执行命令 + snprintf(command, sizeof(command), + "cmd /c \"cd /d \"%s\" && python \"%s\"", cash_dir, script_to_run); + + WinExec(command, nShow); + + return 0; +} \ No newline at end of file