晚上十一点半。IDE 里那堆红字总算闭嘴了。我往后一瘫,椅子嘎吱响,盯着屏幕正中央那几行 Declare 发呆。写 VB 调 Win32 API 的,谁没被这玩意儿折磨过?第一步,老老实实抄声明。函数名、DLL 路径、传值还是传引用、返回值是 Long 还是 Boolean。错一个字母,或者手贱把 ByVal 敲成 ByRef,跑起来直接甩你个“无效过程调用”。不提示,不报错。编译器铁面无私,白纸黑字,签了就得认。
成年人的日子,扒开一层看,底层逻辑其实就这德行。刚毕业那阵子,谁没以为生活是个拖拽式开发环境?拽个按钮,填个参数,点运行,升职加薪“叮”一声就到账。真被社会按地上摩擦过两回,才咂摸出味儿来。早他妈摸到系统底层了。那些摸不着的潜规则,逢年过节死贵的随礼,凌晨两点突然砸过来的改需求通知……全成了庞大又晦涩的 Win32 API。你没法再靠一腔热血瞎蒙了。得自己老老实实查文档,写声明。
说真的,前阵子我特烦这种“声明”。总觉着只要身段放低点,诚意掏干净,哪怕多熬几个大夜,对方总得给个笑脸吧?后来饭局上喝多了两杯,接连碰了软钉子,才回过味来。系统压根不吃感情牌。参数传递就那回事儿。你递过去的是 ByRef 的指望,人家接口里写的是 ByVal 的敷衍。类型对不上,关系当场崩盘。你只能一遍遍改自己的声明。把那些飘在云端的“必须怎样”,换成接地气的 Long 或者 String。别把这叫妥协。我看顶多叫看清了人家接口的真实定义。免得自己白跑一趟。
书里花了挺大篇幅讲消息循环。Windows 这玩意儿,内核就是个收消息、分消息、处理消息的队列。咱们每天睁眼第一件事,不也是机械性地刷手机、翻微信吗?工作群里突然的@,家里长辈发来的九宫格语音条,社交软件上跳出来的小红点,还有那些没头没尾砸过来的 KPI 焦虑。API 塞给你一个 WindowProc,也就是窗口过程。言下之意是:权限给你了。接下来,看你的。哪些该接,哪些该晾着,哪些直接甩给默认处理程序,全得你自己掂量。
刚接手这摊子事的时候,我非想把每条消息都处理得滴水不漏。结果呢?内存占用飙到 90%,窗口直接卡死。人也被拖得连轴转,精疲力竭。后来才摸清一点门道。有些消息,压根不值得你单独写个处理函数。声明里直接留空,或者调默认过程扔回给系统,完事。生活里的精神内耗,十有八九是咱们自己非要在消息队列前设路障。非得给领导没回的消息编理由。非为朋友突然的沉默补解释。说真的,允许某些消息超时。允许某些窗口失去焦点。程序才能接着往下跑。这事儿大概就是这么个意思。抓得太紧,反而全得挂。
现在我也没法拍着胸脯说,彻底吃透了这套底层逻辑。声明语句写得还是磕磕绊绊。参数传着传着,偶尔还是会串门。但说不清为啥,我居然不太怕程序崩溃了。崩溃就崩溃呗。真不是系统在故意搞你,也不是你多无能,纯粹是某次调用的返回值超出了预期值。关掉窗口。重新编译。再跑一遍就是了。咱们本来就不是什么能掌控全局的操作系统。说白了,只不过是在自己那一小块可怜的内存里,老老实实敲自己的 WindowProc 罢了。
屏幕暗下去的时候,桌面壁纸上那棵树的影子,好像透亮了些。明天太阳一出来,大概照样有新消息涌进来。新的声明还得接着更新。能不能写出最优雅的调用方式?我心里真没底。可能永远也写不出吧。但至少清楚,该在哪个参数里留点活口。别把边界卡死。至于系统会不会甩出个 1001 错误码,随它在后台跑吧。只要还能瞅见自己这扇小窗口亮着。不黑屏,就成。