不得不提的,是win32程序已经走在淘汰的边缘了,但今天还是想说说它。若把计算机系统比作一座不断翻新的城市,Win32 就像那些承载着城市记忆的老街区。64 位系统的普及确实像拓宽了主干道,Win64 作为新拓宽的车道,能跑更大更重的 "卡车"(处理更大内存、更复杂运算),但老街区的石板路(Win32)依然有它的用处 ------ 那些只需要自行车就能到达的目的地(轻量工具、嵌入式设备),没必要非得开卡车。

目前国产化已经盛行,win32程序如果想在麒麟系统里运行,就得是64位的windows程序。因为麒麟系统用模拟器支持 64 位,更像是城市管理者在老街区旁修了座现代化换乘站。国产化系统需要兼容大量历史软件,就像新城区得对接老城区的供水系统,模拟器不是 "淘汰" 的信号,反而是技术传承的桥梁。当年从 16 位到 32 位过渡时,Windows 也曾保留 DOS 虚拟机,这种兼容背后想必是对用户习惯和历史资产的尊重。
已经过了20多年了,如今再看 Win32 程序的构成要素,它们如精密钟表齿轮,各居其位,驱动着 Windows 世界运转。把 Win32 程序比作一栋房子,开发流程就是从打地基到封顶的过程。就像盖房先规划,写程序也得按步骤来,看这段代码。
cpp
#include <windows.h>
// 窗口过程(处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
// 主函数(程序入口)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hWnd;
MSG Msg;
// 初始化窗口类(相当于设计房子图纸)
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = "MyClass";
// 注册窗口类(给房子登记身份)
RegisterClassEx(&wc);
// 创建窗口(搭建房子框架)
hWnd = CreateWindowEx(0, "MyClass", "Win32程序", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 300, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 消息循环(处理各种请求)
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
所需函数库与头文件就像工匠的工具箱和说明书。#include <windows.h> 如同万能工具箱,里面装着盖房子要用的各种工具(函数)和零件(数据结构)。就像做饭不能没有锅碗瓢盆,写 Win32 程序也离不开这些基础库,它们是和 Windows 系统沟通的桥梁。
消息机制像老办公室的传呼系统。鼠标点击是一张纸条,窗口移动是一封电报,消息循环就是收发员。当你点击按钮,就像寄了封信,WM_COMMAND 消息就是信封上的地址,确保送到正确的地方。
cpp
// 消息处理示例,如同前台接待不同客人
case WM_LBUTTONDOWN:
// 处理鼠标左键点击,像接待一位要咨询的客人
MessageBox(hWnd, "鼠标左键被点击了", "提示", MB_OK);
break;
case WM_KEYDOWN:
// 处理键盘按键,如同接到一个电话
if(wParam == VK_ESCAPE) {
DestroyWindow(hWnd);
}
break;
程序结构是房子的骨架。WinMain 是总工程师,窗口类注册是给房子登记身份,消息循环是不停处理各种事务,窗口函数则是具体应对不同情况的前台经理。它们分工协作,让程序有条不紊地运行。
对话框像临时咨询台。模态对话框是 "请稍等" 的牌子,非模态是开放式柜台。创建对话框就像搭个临时摊位,方便和用户互动。
cpp
// 创建模态对话框,如同设置一个必须先处理完的咨询点
DialogBox(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), hWnd, DlgProc);
模块定义文件与资源文件是装修手册。.def 文件规定哪些房间可外人进入,.rc 文件记录窗帘花色、壁画位置等。我曾为调整按钮图标在.rc 里改了一下午,那像素级的较真,是程序员的浪漫。
Windows 程序的生与死像一场宴席。WinMain 启动是宾客入座,WM_CREATE 是摆餐具,消息循环是热闹的聚餐,WM_DESTROY 是道别,PostQuitMessage 是关灯锁门。有次调试时,程序退出了还有线程发消息,就像散席后仍在自饮的醉汉。
空闲时间处理是程序的 "摸鱼时刻"。消息循环没事做时,就像值班人员整理文件,悄悄处理后台任务。
cpp
// 空闲时间处理,如同值班人员利用空闲整理资料
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
// 检查是否有空闲时间
while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) == 0) {
// 处理空闲任务,像趁机整理文件
DoIdleTasks();
if(需要退出空闲处理) break;
}
}
Console 程序和 DOS 程序,如同传呼机与智能手机。DOS 程序是单车道自行车,Win32 控制台程序是带导航的汽车,能在自己车道行驶,还能听广播(系统消息)。
进程与线程是公司和员工。进程是独立公司,有自己的地址和执照;线程是员工,有的接待客户(UI 线程),有的埋头算账(后台线程)。优先级像任务紧急程度,给实时数据采集线程高优先级,如同给急诊医生开绿灯。
cpp
// 创建线程,如同招聘一名员工去完成特定工作
HANDLE hThread = CreateThread(
NULL, // 默认安全属性
0, // 默认栈大小
MyThreadFunc, // 线程要执行的函数(员工的工作内容)
NULL, // 传递给线程的参数
0, // 立即执行
&dwThreadId); // 线程ID
这些代码和概念,是我们与机器对话的语法,是用逻辑编织的咒语。当 Windows 系统念起这些咒语,冰冷的硅晶片有了温度,像素开始跳舞,这就是 Win32 开发的动人之处。
现在回头看,Win32 更像是位退居二线的老师傅。它不再冲锋在前,但年轻时攒下的 "手艺"(消息机制、窗口管理思想)早已融入现代编程的基因里。就像活字印刷术虽被数字印刷取代,但其 "模块化" 理念却启发了计算机编程。或许某天 Win32 会彻底淡出视野,但那些在调试窗口函数时悟到的逻辑思维,永远不会过时。这也是我想在这里梳理之前经历技术的意义,或许年轻的程序员根本就没层了解过,但想说的如今很多的技术要点,其实源于早期win32开发的一些脉络,从诞生到运行再到结束,每个环节都有其意义。未完待续.......