开发者用Delphi 1和Visual C++为Win3.11与OS/2开发复古GUI
来源标题:Developing Retro-GUI for Win3.11 (Delphi 1) and OS/2 (Visual C++) (2025)
一名开发者用Borland Delphi 1为Windows 3.11、用Visual C++为OS/2 Warp 3.0开发了复古GUI,用于控制自己的微控制器项目。Delphi 1是最后一个支持16位Windows应用的版本,于1995年发布。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
用真实硬件做复古计算,是理解现代计算机如何学会运行和通信的绝佳方式。我为 OS/2 Warp 3.0 和 Windows 3.11 开发了一些 GUI,用来控制我的几个微控制器项目。 要为现代计算机开发 GUI,你可以使用流行的 C++ Qt 框架、Java 的 Android Studio,或者几十种不同的 Python 框架。但在当年,Windows 上只有一个 API:Win16-API。于是我萌生了一个念头——用 Win16-API 开发一个 GUI 应用,纯粹为了好玩。由于我持有 Embarcadero Delphi 的有效许可证,可以免费使用较旧的 Borland 编译器,我便寻找一些支持 Windows 3 的 16 位 API 的旧版本。第一个——也是最后一个——支持 16 位应用的 Delphi 是 Borland Delphi 1,发布于 1995 年 2 月 14 日。于是我下载了这个版本,创建了一个小型演示应用:一行代码,几秒钟内它就顺利跑起来了: procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage('Hello World!'); end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage('Hello World!'); end; 但用一个 1995 年发布的编译器,为 1992 年首次发布的 Windows 3.1 编写软件,总觉得有点像作弊。于是我安装了 1993 年的 Microsoft Visual C++ v1.52——它可以说是 Microsoft Windows 3.x 上最常见的开发平台。然后——天哪——我立刻感受到了 90 年代的气息: Microsoft 最早是在 VisualBasic 中加入了通过拖放组件到预设计窗口上来开发 GUI 应用的选项。而在 VisualC++ 中,所有 GUI 元素都必须用纯代码放置,没有所见即所得。在下面这张图中,你可以看到为创建用于选择 COM 端口号和速度的 GUI 而添加的一些 GUI 组件: hControl = CreateWindow("COMBOBOX", NULL, WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP, 16, 400, 65, 520, hWnd, (HMENU)IDC_COMPORT, hInst, NULL); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM1"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM2"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM3"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM4"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_SETCURSEL, 0, 0); hControl = CreateWindow("COMBOBOX", NULL, WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP, 16, 400, 65, 520, hWnd, (HMENU)IDC_COMPORT, hInst, NULL); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM1"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM2"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM3"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_ADDSTRING, 0, (LPARAM)(LPSTR)"COM4"); SendDlgItemMessage(hWnd, IDC_COMPORT, CB_SETCURSEL, 0, 0); 几分钟后我就习惯了这种编写 GUI 的方式,但脑子里想着 2020 年代的快速开发环境,继续这样写代码还是相当困难。编码过程中我很快意识到:用 Google 搜索 Win16-API 的函数或属性不会得到解决方案,因为大多数搜索查询都会被重定向到 Microsoft 的 Win32 API……毫无帮助。由于 1993 年互联网还没发明,程序员只能读书(那种有纸的东西——不是“电子书”)来学习计算机语言。在这趟回到过去的旅程中,我读了 Charles Petzold 的《Programming Windows 3.1》和 Borland 的《Windows API Volume III – Windows 3.1 Reference Guide》中的一些章节。但 Microsoft 做了一件很棒的事:在开发环境中内置了一份非常有用的本地 Win16 API 参考——Windows 3.1 SDK 在帮助系统中本地可用: 经过几天对 Win16 API 的适应,我已经能够为我的 Windows for Workgroups 3.11 编写一个功能完整的应用,通过串口进行通信,包含多个用于控制我基于 FPGA 的音频播放器的 UI 元素,以及通用的用户反馈: 现在我相当满意了,因为我已经找到了两种为老电脑开发软件的方法:一种更便捷的方式是使用 Borland Delphi 1,另一种更“感受 90 年代”的方式是使用 Visual C++。不过,我还没有完全达到目标:我们的第一台电脑——父母在 1994 年作为圣诞礼物送给我们的那台——除了 DOS 和 Windows 3.11 之外,还安装了 OS/2 Warp 3。为 OS/2 开发软件能有多难?嗯…… 1994 年,OS/2 提供了所谓的 WinOS/2 环境,你可以使用 Windows 3.11 的特殊兼容层来启动 Windows 3.x 应用。但这些应用并非原生运行在 OS/2 下,通过该层启动的应用会被标记上一个醒目的黄色边框: 于是我开始寻找更好的选择。IBM 提供了“Restructured Extended Executor”(REXX)来开发自己的应用(或者更确切地说是“脚本”)。除此之外,还可以用 GCC 编译原生应用。但我在寻找更方便的方式来开发原生 GUI 应用。搜索过程中,我偶然发现了 Windows Libraries for OS/2。有了这套库集合,应该可以让我的 Windows 应用在 OS/2 下原生运行。为此,Microsoft 为 OS/2 编译了最重要的 Windows 库:GDI.DLL、KERNEL.DLL、SYSTEM.DLL、USER.DLL 以及其他一些文件。 在 OS/2 下安装 WLO 之后,一个经过特殊标记的 Windows EXE 就可以直接在 OS/2 下运行,同时 WLO 库会把 Windows 系统调用重定向到原生 OS/2 调用。查看 WLO 那点稀少的文档,我只需要把 NE-EXE 头中的 OS2EXEFlags 设置为 0x80。于是我打开一个十六进制编辑器,在我的 Borland Delphi 1 应用的 NE 头中找到 OS2EXEFlags,把值改为 0x80:
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。