Files
WinGUI/GUITest/WMExtractor.t.c
T
2026-07-28 14:17:49 +08:00

255 lines
8.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE_LEN 2048
#define MAX_PARAMS 16
#define MAX_NAME_LEN 64
typedef struct {
char type[MAX_NAME_LEN];
char name[MAX_NAME_LEN];
} ParamInfo;
// 辅助函数:去除两端空格
void trim(char *str) {
char *end;
while (isspace((unsigned char)*str)) str++;
if (*str == 0) return;
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) end--;
*(end + 1) = '\0';
memmove(str - (str - (str + (isspace((unsigned char)*str) ? 1 : 0))), str, strlen(str) + 1);
}
// 辅助函数:精准提取类型强转
// 例如:"(int)(short)LOWORD(lParam)" -> 提取出 "int"
// 如果只是 "(hwnd)",由于 hwnd 是变量名而非合法类型,会通过 default_name 转换成 "HWND"
void extract_first_type(const char *src, char *dest, const char *default_name) {
dest[0] = '\0';
const char *p = src;
// 跳过前面的空格
while (*p && isspace((unsigned char)*p)) p++;
if (*p == '(') {
p++; // 进入第一个左括号
int i = 0;
while (*p && *p != ')') {
dest[i++] = *p++;
}
dest[i] = '\0';
trim(dest);
}
// 关键修正:如果提取出来的“类型”和变量名一样(例如把 (hwnd) 误判为类型为 hwnd),或者为空
// 则通过名字来给它赋予 Windows 标准类型
if (strlen(dest) == 0 || strcmp(dest, default_name) == 0 || strcmp(dest, "fn") == 0) {
if (strstr(default_name, "hwnd")) strcpy(dest, "HWND");
else if (strstr(default_name, "lParam")) strcpy(dest, "LPARAM");
else if (strstr(default_name, "wParam")) strcpy(dest, "WPARAM");
else if (strstr(default_name, "vk")) strcpy(dest, "UINT");
else strcpy(dest, "int"); // 默认兜底
}
}
// 核心解析函数
void process_macros(const char *handle_line, const char *forward_line) {
char msg_name[MAX_NAME_LEN] = {0};
char return_type[MAX_NAME_LEN] = {0};
// 1. 提取 MsgName
char *msg_pos = strstr(handle_line, "HANDLE_WM_");
if (!msg_pos) return;
msg_pos += 10;
int len = 0;
while (isalnum((unsigned char)msg_pos[len]) || msg_pos[len] == '_') {
msg_name[len] = msg_pos[len];
len++;
}
msg_name[len] = '\0';
// 2. 提取 FORWARD_WM_xxx 宏括号定义中的所有参数名
char forward_search[MAX_NAME_LEN + 20];
sprintf(forward_search, "FORWARD_WM_%s(", msg_name);
char *f_param_start = strstr(forward_line, forward_search);
if (!f_param_start) return;
f_param_start += strlen(forward_search);
char f_params_buf[MAX_LINE_LEN] = {0};
int f_len = 0;
int f_depth = 1;
// 严格按括号匹配提取参数声明区间,避免被后续宏体干扰
while (f_param_start[f_len] && f_depth > 0) {
if (f_param_start[f_len] == '(') f_depth++;
if (f_param_start[f_len] == ')') f_depth--;
if (f_depth > 0) {
f_params_buf[f_len] = f_param_start[f_len];
f_len++;
}
}
f_params_buf[f_len] = '\0';
// 切分 FORWARD 宏头部的参数名
char f_param_names[MAX_PARAMS][MAX_NAME_LEN];
int f_param_count = 0;
// 修正点:手动切分逗号,不使用会破坏内部状态的 strtok
char *f_ptr = f_params_buf;
char *f_comma;
while ((f_comma = strchr(f_ptr, ',')) != NULL && f_param_count < MAX_PARAMS) {
*f_comma = '\0';
trim(f_ptr);
if (strcmp(f_ptr, "fn") != 0 && strlen(f_ptr) > 0) {
strcpy(f_param_names[f_param_count++], f_ptr);
}
f_ptr = f_comma + 1;
}
trim(f_ptr);
if (strcmp(f_ptr, "fn") != 0 && strlen(f_ptr) > 0) {
strcpy(f_param_names[f_param_count++], f_ptr);
}
// 3. 解析 return_type
char *fn_pos = strstr(forward_line, "(fn)");
if (fn_pos) {
char *search_start = strstr(forward_line, forward_search);
if (search_start) {
char *body_start = strchr(search_start, ')');
if (body_start && body_start < fn_pos) {
char return_buf[MAX_LINE_LEN] = {0};
strncpy(return_buf, body_start + 1, fn_pos - (body_start + 1));
return_buf[fn_pos - (body_start + 1)] = '\0';
extract_first_type(return_buf, return_type, "");
}
}
}
if (strlen(return_type) == 0 || strcmp(return_type, "void") == 0) {
strcpy(return_type, "void");
}
// 4 & 5 & 6. 解析 HANDLE_WM_xxx 中 fn(...) 内部调用
char *fn_call = strstr(handle_line, "(fn)(");
if (!fn_call) fn_call = strstr(handle_line, "fn(");
ParamInfo final_params[MAX_PARAMS];
int final_param_count = 0;
if (fn_call) {
if (strncmp(fn_call, "(fn)(", 5) == 0) {
fn_call += 5; // 移动到 (fn)( 之后的具体参数部分
} else {
fn_call += 3; // 移动到 fn( 之后的具体参数部分
}
// 匹配提取出整个括号内的参数段表达式
char h_body_buf[MAX_LINE_LEN] = {0};
int h_depth = 1;
int h_idx = 0;
while (fn_call[h_idx] && h_depth > 0) {
if (fn_call[h_idx] == '(') h_depth++;
if (fn_call[h_idx] == ')') h_depth--;
if (h_depth > 0) {
h_body_buf[h_idx] = fn_call[h_idx];
h_idx++;
}
}
h_body_buf[h_idx] = '\0';
// 核心修正:按照外层零嵌套深度的逗号切分出各个独立的传参表达式
char *expressions[MAX_PARAMS];
int exp_count = 0;
char *start = h_body_buf;
int depth_count = 0;
for (int i = 0; h_body_buf[i] != '\0'; i++) {
if (h_body_buf[i] == '(') depth_count++;
else if (h_body_buf[i] == ')') depth_count--;
else if (h_body_buf[i] == ',' && depth_count == 0) {
h_body_buf[i] = '\0';
expressions[exp_count++] = start;
start = &h_body_buf[i + 1];
}
}
expressions[exp_count++] = start;
// 根据表达式与 FORWARD 的名字进行最终映射与插入
int f_idx = 0;
for (int i = 0; i < exp_count; i++) {
trim(expressions[i]);
if (strlen(expressions[i]) == 0) continue;
// 4. 对 HANDLE_WM_xxx 中 TRUE 所在位置,直接生成 fBool 参数名插入
if (strcmp(expressions[i], "TRUE") == 0 || strcmp(expressions[i], "FALSE") == 0) {
strcpy(final_params[final_param_count].name, "fBool");
strcpy(final_params[final_param_count].type, "WINBOOL");
final_param_count++;
} else {
if (f_idx < f_param_count) {
strcpy(final_params[final_param_count].name, f_param_names[f_idx]);
// 5 & 6. 提取每个参数对应的真实强转类型
char parsed_type[MAX_NAME_LEN] = {0};
extract_first_type(expressions[i], parsed_type, f_param_names[f_idx]);
strcpy(final_params[final_param_count].type, parsed_type);
final_param_count++;
f_idx++;
}
}
}
}
// 7. 生成格式化内容输出
printf("#define c_WinGUI_EventFn_WM_%s(fn) \\\n %s fn(", msg_name, return_type);
for (int i = 0; i < final_param_count; i++) {
printf("%s %s", final_params[i].type, final_params[i].name);
if (i < final_param_count - 1) {
printf(", ");
}
}
printf(")\n\n");
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "使用方法: %s <windowsx.h 路径>\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (!fp) {
perror("打不开文件");
return 1;
}
char line[MAX_LINE_LEN];
char cached_handle[MAX_LINE_LEN] = {0};
char current_msg[MAX_NAME_LEN] = {0};
while (fgets(line, sizeof(line), fp)) {
line[strcspn(line, "\r\n")] = 0;
if (strstr(line, "#define HANDLE_WM_")) {
strcpy(cached_handle, line);
char *p = strstr(line, "HANDLE_WM_") + 10;
int idx = 0;
while (isalnum((unsigned char)p[idx]) || p[idx] == '_') {
current_msg[idx] = p[idx];
idx++;
}
current_msg[idx] = '\0';
}
else if (strstr(line, "#define FORWARD_WM_")) {
if (strlen(current_msg) > 0 && strstr(line, current_msg)) {
process_macros(cached_handle, line);
cached_handle[0] = '\0';
current_msg[0] = '\0';
}
}
}
fclose(fp);
return 0;
}