其实如果是我,我会使用 msys2 来编译我的 Win32 工程,并使用“弱符号”的方式来实现各种控件的“仿 VB6 事件函数”的自动调用,效果就是:我如果写了事件函数的实现,那么它会被自动调用;如果我没写,也不妨碍它正常编译。
msys2 包含 Windows 上可用的 GCC 编译工具链,可以使用 Windows 的头文件和库(比如 Windows.h )并且生成 exe、dll。
类似于原版 VB6 的一个特点:我如果写了事件处理过程(比如 Private Sub Form_Click() 也就是窗体的单击事件)那么这个 Sub 会在你单击窗体的时候自动被调用,但如果你不写这个过程,那也不妨碍你程序可以编译(也就是你不需要把所有控件的所有事件的过程都写出来)。
假设我有个 Button 控件名为 Button1 在我的主窗体上,那么这个控件的单击事件的响应函数是这样写的:[C] 纯文本查看 复制代码 void OnClick(HWND Button, size_t Button_ID)
{
// 此处定义按钮行为
MessageBeep(MB_OK); // 发出“咚”的一声
} 因为我写了这个函数,所以我的按钮被按下的时候,这个函数会被调用。但是我如果完全删除了这个函数呢?那依然可以正常编译。
原理是:在 GCC 可以使用 __attribute__((weak)) 来修饰一个变量、函数,使其成为“弱符号”。然后这个“弱符号”对应的函数、变量等,就会变为一个“备用”的函数或者变量。如果出现了同名的非弱符号,则链接器会链接到这个非弱符号上。比如:[C] 纯文本查看 复制代码 __attribute__((weak)) void foo()
{
printf("A");
}
void foo()
{
printf("B");
}
int main()
{
foo(); // 会输出 B
return 0;
} 对比另一份代码(没写 void foo())则是这样的:[C] 纯文本查看 复制代码 __attribute__((weak)) void foo()
{
printf("A");
}
int main()
{
foo(); // 会输出 A
return 0;
} 我在我的“通用消息处理函数”里面对几种我设定的常用的控件的事件函数进行调用,并且我把这些事件函数都以弱符号的形式定义好。那么我的界面库在被使用的时候,使用者就可以通过自己写同名、同返回值、同参数列表的事件函数来处理事件了。
可以通过参阅 STM32 的 HAL 库,你可以看到它对 STM32 的各种 CPU 中断函数进行了封装,每一种中断都有它的默认行为,而只要你编写了同名的中断处理函数,则最终生成的指令里会选用你的中断处理函数对 CPU 的中断进行处理。
|