eduwin 工具 API
数字与字符串工具
int rand_int(int min, int max);
返回 [min, max] 闭区间的随机整数。
const WCHAR *itow(int value);
整数 → 宽字符串。如 itow(42) 返回 L"42"。
const WCHAR *ftow(double value);
小数 → 宽字符串。如 ftow(3.14) 返回 L"3.14"。
void str_concat(WCHAR *dest, int size, ...);
拼接多个宽字符串,最后一个参数必须是 NULL 表示结束。
WCHAR buf[64];
str_concat(buf, 64, L"你点击了 ", itow(count), L" 次", NULL);
set_text(label, buf);
void str_format(WCHAR *buf, int size, const WCHAR *fmt, ...);
void str_format_a(char *buf, int size, const char *fmt, ...);
格式化字符串到 buf,用法类似 printf,自动截断不会溢出。str_format 输出到宽字符串(WCHAR),str_format_a 输出到 UTF-8 字符串(char)。
WCHAR buf[64];
str_format(buf, 64, L"Client: %d x %d", w, h); /* buf = L"Client: 682 x 453" */
str_format(buf, 64, L"%.1f%%", 95.7f); /* buf = L"95.7%" */
char buf_a[64];
str_format_a(buf_a, 64, "{\"result\":%d}", 42); /* buf_a = {"result":42} */
剪贴板
void clipboard_copy(const WCHAR *text);
将文本复制到系统剪贴板。
Base64 解码
int base64_decode(const char *in, int in_len, unsigned char *out);
解码 Base64 字符串为原始字节。in_len 传入输入字符串长度(用 strlen),返回值是输出的字节数。out 缓冲区需足够大(最大约为 in_len * 3 / 4)。
unsigned char data[1024];
int len = base64_decode("SGVsbG8=", 8, data); // len=5, data="Hello"
内部在 eduwin_d3d 的 glTF 加载器中使用,解码 data URI 中的 base64 数据。
文件读写
文本文件读写
int read_text_file(const WCHAR *filepath, WCHAR *buf, int size);
int write_text_file(const WCHAR *filepath, const WCHAR *text);
read_text_file 读取文本文件内容到宽字符串缓冲区。自动以 UTF-8 编码读取(兼容含 BOM 的文件)。成功返回读取的字符数(不含末尾 \0),失败返回 -1。
write_text_file 将宽字符串写入文本文件,编码为 UTF-8(含 BOM)。成功返回 1,失败返回 0。
WCHAR buf[1024];
int n = read_text_file(L"data.txt", buf, 1024);
二进制文件读写
int read_bin_file(const WCHAR *filepath, void *buf, int elem_size, int max_count);
int write_bin_file(const WCHAR *filepath, void *buf, int elem_size, int count);
read_bin_file 从二进制文件中读取数据到缓冲区。elem_size 为每个元素的字节数,max_count 为最多读取多少个元素。成功返回实际读取的元素数,失败返回 -1。
write_bin_file 将缓冲区数据写入二进制文件。count 为要写入的元素个数。成功返回 1,失败返回 0。
常用于读写结构体或结构体数组:
typedef struct {
int id;
WCHAR name[32];
int score;
} Student;
Student students[3] = {
{1001, L"张三", 85},
{1002, L"李四", 92},
{1003, L"王五", 78}
};
write_bin_file(L"students.bin", students, sizeof(Student), 3);
Student buf[3];
int n = read_bin_file(L"students.bin", buf, sizeof(Student), 3);
注意事项:
- 不可跨平台——结构体内存布局(对齐、填充字节)在不同编译器下可能不同。在 eduwin(MSVC x64)环境下读写无问题。
- 不能包含指针——结构体里有
char *或WCHAR *指针时,只会写入指针地址值而不是指向的字符串内容。应改用固定大小的字符数组(如WCHAR name[32])。- 路径用宽字符串——与 eduwin 其他文件 API 一致。
- 防止缓冲区溢出——
buf必须足够大以容纳elem_size * max_count字节。
二进制文件读取(动态分配)
unsigned char* read_bin_file_alloc(const char *path, int *out_len);
将整个文件一次性读入堆内存,自动以 malloc 分配缓冲区。out_len 返回文件字节数。调用方需用 free() 释放返回的缓冲区。失败返回 NULL。
常用于需要将整个文件加载到内存的场景,如图片文件加载、glTF 二进制数据处理等。
int len;
unsigned char *data = read_bin_file_alloc("image.bmp", &len);
if (data) {
// 使用 data...
free(data);
}
数据库
eduwin 已内置 SQLite 嵌入式数据库引擎,无需任何额外配置:
#include "eduwin.h"
#include "sqlite3.h"
sqlite3 *db;
sqlite3_open("test.db", &db);
sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS ...", NULL, NULL, NULL);
sqlite3_close(db);
详见 eduwin-sqlite.md。samples\sqlite_demo\sqlite_demo.c 是一个完整的用户信息增删改查演示。
进程管理
HANDLE run_process(const WCHAR *exe_path, const WCHAR *cmdline, int show);
int kill_process(HANDLE proc);
int kill_process_pid(DWORD pid);
int wait_process(HANDLE proc);
run_process 创建新进程。exe_path 为可执行文件路径,cmdline 为命令行参数(可为 NULL),show=1 显示窗口,show=0 隐藏窗口。成功返回进程句柄,失败返回 NULL。
kill_process 强制终止进程并关闭句柄,成功返回 0。
kill_process_pid 按进程 PID 终止进程(内部调用 OpenProcess + kill_process),成功返回 0。
wait_process 等待进程结束,返回进程退出码(内部会自动关闭句柄)。
// 启动记事本,等待退出
HANDLE h = run_process(L"C:\\Windows\\System32\\notepad.exe", NULL, 1);
if (h) {
int code = wait_process(h);
log_info(L"记事本已退出");
}
// 后台启动 cmd
HANDLE h2 = run_process(L"C:\\Windows\\System32\\cmd.exe", NULL, 1);
// 稍后终止
kill_process(h2);
// 按 PID 终止进程
kill_process_pid(1234);
进程枚举
typedef struct {
DWORD pid;
WCHAR name[260];
} process_entry_t;
int enum_processes(process_entry_t **out, int *count);
enum_processes 枚举所有系统进程,动态分配数组并通过 out 返回。count 返回进程数量。成功返回 0。调用方需 free() 释放返回的数组。
process_entry_t *procs = NULL;
int count = 0;
if (enum_processes(&procs, &count) == 0) {
for (int i = 0; i < count; i++)
wprintf(L"%u %s\n", procs[i].pid, procs[i].name);
free(procs);
}
系统信息
typedef struct {
WCHAR computer_name[64];
WCHAR user_name[64];
WCHAR os_version[64];
int cpu_cores;
WCHAR cpu_name[128];
unsigned long long mem_total_mb;
unsigned long long mem_avail_mb;
WCHAR windows_dir[MAX_PATH];
} sys_info_t;
int get_sys_info(sys_info_t *info);
get_sys_info 填充系统信息到 sys_info_t 结构体。成功返回 0。
sys_info_t info;
get_sys_info(&info);
// info.computer_name → 计算机名
// info.os_version → "Windows 10 Pro (Build 19045, 22H2)"
// info.cpu_cores → 8
// info.cpu_name → "Intel(R) Core(TM) i7-10700"
// info.mem_total_mb → 16384
注册表读写
int reg_read_str(HKEY root, const WCHAR *key, const WCHAR *value, WCHAR *buf, int size);
int reg_read_dword(HKEY root, const WCHAR *key, const WCHAR *value, DWORD *out);
int reg_write_str(HKEY root, const WCHAR *key, const WCHAR *value, const WCHAR *data);
int reg_write_dword(HKEY root, const WCHAR *key, const WCHAR *value, DWORD data);
int reg_delete_value(HKEY root, const WCHAR *key, const WCHAR *value);
注册表读写操作。root 为根键(如 HKEY_LOCAL_MACHINE)。key 为键路径。成功返回 0。写操作会自动创建不存在的键。
WCHAR cpu_name[128];
reg_read_str(HKEY_LOCAL_MACHINE,
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
L"ProcessorNameString", cpu_name, 128);
DWORD value = 1;
reg_write_dword(HKEY_CURRENT_USER,
L"Software\\MyApp", L"Setting", value);
环境变量
int get_env(const WCHAR *name, WCHAR *buf, int size);
int set_env(const WCHAR *name, const WCHAR *value);
get_env 读取环境变量,成功返回 0。set_env 设置环境变量(仅影响当前进程),成功返回 0。
WCHAR path_val[4096];
get_env(L"PATH", path_val, 4096);
set_env(L"MY_VAR", L"hello");
特殊文件夹
#define FOLDER_DESKTOP 0
#define FOLDER_DOCUMENTS 1
#define FOLDER_DOWNLOADS 2
#define FOLDER_PICTURES 3
#define FOLDER_MUSIC 4
#define FOLDER_VIDEOS 5
#define FOLDER_APPDATA 6
#define FOLDER_LOCALAPPDATA 7
#define FOLDER_PROGRAMFILES 8
#define FOLDER_STARTUP 9
int get_special_folder(int folder_id, WCHAR *buf, int size);
get_special_folder 获取系统特殊文件夹路径。成功返回 0。
WCHAR path[MAX_PATH];
get_special_folder(FOLDER_DOWNLOADS, path, MAX_PATH);
// path → "C:\Users\xxx\Downloads"
日志
void log_info(const WCHAR *text);
void log_warning(const WCHAR *text);
void log_error(const WCHAR *title);
void log_clear(void);
将文本写入 exe 所在目录下的 log.txt 文件,自动在行首添加日期时间戳(精确到毫秒)和标签([INFO] / [WARN] / [ERROR])。日志以追加方式写入。
log_error 除了写入时间戳和 [ERROR] 标签外,还会自动追加 GetLastError() 的错误码和对应的系统错误描述。
log_clear 清空日志文件。
log_info(L"程序启动完成");
log_warning(L"纹理加载失败,使用默认纹理");
log_error(L"CreateDevice"); // 自动追加 err=87 - 参数错误
log_clear();
输出示例:
2026-06-23 14:30:01.123 [INFO] 程序启动完成
2026-06-23 14:30:02.456 [WARN] 纹理加载失败,使用默认纹理
2026-06-23 14:30:03.789 [ERROR] CreateDevice (err=87 - 参数错误)