在WIN10平台上体验Microsoft古老的Quick C 1.0编程

前言:

90年代初,微软出了Quick系统对抗Borland Turbo系列,其中包括 QuickBasic, QuickPascal和Quick C。1991年,Quick C for Windows 1.0发布,后来它被Visual C++取代。我自己觉得微软成就在那个winstub.exe桩上,后来从xp开始挖掉那个桩。为了突破DOS内存限制,DOS4GW, pharlap都有办法,但只有winstub.exe架起了微软的WINDOWS平台,其它的都被淘汰了。现在CPU有内存管理单元,这些东西都不需要了。

步骤一:QCWIN (Quick C 1.0 for Windows) 安装

在WIN10上安装VMWARE虚拟机,在虚拟机中安装XP。虚拟机挂载共享文件夹,在WIN10上将5张盘的内容放在文件夹中,XP系统中打开共享文件夹,双击运行DISK1中的SETUP.EXE

安装程序会自动顺畅地安装好5张盘的内容。下图是安装后的文件分布情况。

步骤二:运行QCWIN (Quick C 1.0 for Windows)

界面看上去很简洁,在XP theme夹持下感观上很舒服。下面分步建立一个简单程序。

步骤三:写一个简单程序

先打开QUICK CASE,用它是做一个SDI单文档界面,也是程序的主界面。

3.1 输入标题

3.2 输入菜单项

建完 File - Exit 后,在它旁边用同样的方法建 Help - About。 在Quick Case 的Design菜单项下可以设置图标及样式。

3.3 回到QCWIN程序(最小化但不要关闭QuickCase),在TOOLS下选用Dialog Editor

3.4 从任务栏上恢复QuickCase窗口(最小化但不要关闭Dialog Editor),先保存文件,然后点击Build下的生成。如果保存文件名是Hello.WIN的话,则会生成Hello.C文件和Hello.H文件。

把它最小化到任务栏,同时恢复任务栏上的Dialog Editor,保存Dialog文件并设置Include头文件。

3.5 Open装入QuickCase生成的MAK文件,然后Build或Rebuild All生成EXE文件。

步骤四:回观并感受上面的代码

生成的文件

生成的代码是WIN16 API代码,与现在的WIN32 API代码基本上相同,但个别API函数没有,比如LoadImage,需要用其它函数组合实现。生成的代码基本没改,只是读取了桌面尺寸和默认生成的主窗体尺寸,然后根据尺寸参数将主窗体放在屏幕的正中间位置。代码从注册应用程序类、创建主窗口、显示主窗口、进入主消息队列,与现在的API编程是完全一样的,这套思路从1991年到现在30年间似乎没有什么改变。

/* QuickCase:W KNB Version 1.00 */
#include "HELLO.h"/************************************************************************/
/*                                                                      */
/* Windows 3.0 Main Program Body                                        */
/*                                                                      */
/* The following routine is the Windows Main Program.  The Main Program */
/* is executed when a program is selected from the Windows Control      */
/* Panel or File Manager.  The WinMain routine registers and creates    */
/* the program's main window and initializes global objects.  The       */
/* WinMain routine also includes the applications message dispatch      */
/* loop.  Every window message destined for the main window or any      */
/* subordinate windows is obtained, possibly translated, and            */
/* dispatched to a window or dialog processing function. The dispatch   */
/* loop is exited when a WM_QUIT message is obtained.  Before exiting   */
/* the WinMain routine should destroy any objects created and free      */
/* memory and other resources.                                          */
/*                                                                      */
/************************************************************************/int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{/***********************************************************************//* HANDLE hInstance;       handle for this instance                    *//* HANDLE hPrevInstance;   handle for possible previous instances      *//* LPSTR  lpszCmdLine;     long pointer to exec command line           *//* int    nCmdShow;        Show code for main window display           *//***********************************************************************/MSG        msg;           /* MSG structure to store your messages        */int        nRc;           /* return value from Register Classes          */HWND hDesk;	//handle of DESKTOP as a root windowint WndMainX, WndMainY;		//new centered main windowint nWndMainWidth, nWndMainHeight;		//width and height of DESKTOPRECT rectWndDesk;		//rectanglur structure of DESKTOPRECT rectWndMain;		//rectanglur structure of main windowstrcpy(szAppName, "HELLO");hInst = hInstance;if(!hPrevInstance){/* register window classes if first instance of application         */if ((nRc = nCwRegisterClasses()) == -1){/* registering one of the windows failed                         */LoadString(hInst, IDS_ERR_REGISTER_CLASS, szString, sizeof(szString));MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);return nRc;}}hDesk = GetDesktopWindow();
GetWindowRect(hDesk, &rectWndDesk);/* create application's Main window                                    */hWndMain = CreateWindow(szAppName,               /* Window class name           */NULL,                   /* no title                     */WS_CAPTION      |        /* Title and Min/Max           */WS_SYSMENU      |        /* Add system menu box         */WS_MINIMIZEBOX  |        /* Add minimize box            */WS_MAXIMIZEBOX  |        /* Add maximize box            */WS_THICKFRAME   |        /* thick sizeable frame        */WS_CLIPCHILDREN |         /* don't draw in child windows areas */WS_OVERLAPPED,CW_USEDEFAULT, 0,        /* Use default X, Y            */CW_USEDEFAULT, 0,        /* Use default X, Y            */NULL,                    /* Parent window's handle      */NULL,                    /* Default to Class Menu       */hInst,                   /* Instance of window          */NULL);                   /* Create struct for WM_CREATE */if(hWndMain == NULL){LoadString(hInst, IDS_ERR_CREATE_WINDOW, szString, sizeof(szString));MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);return IDS_ERR_CREATE_WINDOW;}GetWindowRect(hWndMain, &rectWndMain);WndMainX = (rectWndDesk.right - rectWndMain.right + rectWndMain.left)/2;
WndMainY = (rectWndDesk.bottom - rectWndMain.bottom + rectWndMain.top)/2;
nWndMainWidth = rectWndMain.right - rectWndMain.left;
nWndMainHeight = rectWndMain.bottom - rectWndMain.top;MoveWindow(hWndMain, WndMainX, WndMainY, nWndMainWidth, nWndMainHeight, FALSE);ShowWindow(hWndMain, SW_SHOWNORMAL);    /* display main window      */UpdateWindow(hWndMain);while(GetMessage(&msg, NULL, 0, 0))        /* Until WM_QUIT message    */{TranslateMessage(&msg);DispatchMessage(&msg);}/* Do clean up before exiting from the application                     */CwUnRegisterClasses();return msg.wParam;
} /*  End of WinMain                                                    */
/************************************************************************/
/*                                                                      */
/* Main Window Procedure                                                */
/*                                                                      */
/* This procedure provides service routines for the Windows events      */
/* (messages) that Windows sends to the window, as well as the user     */
/* initiated events (messages) that are generated when the user selects */
/* the action bar and pulldown menu controls or the corresponding       */
/* keyboard accelerators.                                               */
/*                                                                      */
/* The SWITCH statement shown below distributes the window messages to  */
/* the respective message service routines, which are set apart by the  */
/* CASE statements. The window procedures must provide an appropriate   */
/* service routine for its end user initiated messages, as well as the  */
/* general Windows messages (ie. WM_CLOSE message). If a message is     */
/* sent to this procedure for which there is no programmed CASE clause  */
/* (i.e., no service routine), the message is defaulted to the          */
/* DefWindowProc function, where it is handled by Windows               */
/*                                                                      */
/************************************************************************/LONG FAR PASCAL WndProc(HWND hWnd, WORD Message, WORD wParam, LONG lParam)
{HMENU      hMenu=0;            /* handle for the menu                 */HBITMAP    hBitmap=0;          /* handle for bitmaps                  */HDC        hDC;                /* handle for the display device       */PAINTSTRUCT ps;                /* holds PAINT information             */int        nRc=0;              /* return code                         */switch (Message){case WM_COMMAND:/* The Windows messages for action bar and pulldown menu items *//* are processed here.                                         */switch (wParam){case IDM_F_EXIT:/* Place User Code to respond to the                   *//* Menu Item Named "Exit" here.                        */break;case IDM_H_ABOUT:/* Place User Code to respond to the                   *//* Menu Item Named "About" here.                       */{FARPROC lpfnDIALOGSMsgProc;lpfnDIALOGSMsgProc = MakeProcInstance((FARPROC)DIALOGSMsgProc, hInst);nRc = DialogBox(hInst, (LPSTR)"AboutBox", hWnd, lpfnDIALOGSMsgProc);FreeProcInstance(lpfnDIALOGSMsgProc);}break;default:return DefWindowProc(hWnd, Message, wParam, lParam);}break;        /* End of WM_COMMAND                             */case WM_CREATE:/* The WM_CREATE message is sent once to a window when the     *//* window is created.  The window procedure for the new window *//* receives this message after the window is created, but      *//* before the window becomes visible.                          */break;       /*  End of WM_CREATE                              */case WM_MOVE:     /*  code for moving the window                    */break;case WM_SIZE:     /*  code for sizing client area                   */break;       /* End of WM_SIZE                                 */case WM_PAINT:    /* code for the window's client area              *//* Obtain a handle to the device context                       *//* BeginPaint will sends WM_ERASEBKGND if appropriate          */memset(&ps, 0x00, sizeof(PAINTSTRUCT));hDC = BeginPaint(hWnd, &ps);/* Included in case the background is not a pure color         */SetBkMode(hDC, TRANSPARENT);/* Inform Windows painting is complete                         */EndPaint(hWnd, &ps);break;       /*  End of WM_PAINT                               */case WM_CLOSE:  /* close the window                                 *//* Destroy child windows, modeless dialogs, then, this window  */DestroyWindow(hWnd);if (hWnd == hWndMain)PostQuitMessage(0);  /* Quit the application                 */break;default:/* For any message for which you don't specifically provide a  *//* service routine, you should return the message to Windows   *//* for default message processing.                             */return DefWindowProc(hWnd, Message, wParam, lParam);}return 0L;
}     /* End of WndProc                                         */
/************************************************************************/
/*                                                                      */
/* Dialog Window Procedure                                              */
/*                                                                      */
/* This procedure is associated with the dialog box that is included in */
/* the function name of the procedure. It provides the service routines */
/* for the events (messages) that occur because the end user operates   */
/* one of the dialog box's buttons, entry fields, or controls.          */
/*                                                                      */
/* The SWITCH statement in the function distributes the dialog box      */
/* messages to the respective service routines, which are set apart by  */
/* the CASE clauses. Like any other Windows window, the Dialog Window   */
/* procedures must provide an appropriate service routine for their end */
/* user initiated messages as well as for general messages (like the    */
/* WM_CLOSE message).                                                   */
/* Dialog messages are processed internally by windows and passed to the*/
/* Dialog Message Procedure. IF processing is done for a Message the    */
/* Message procedure returns a TRUE, else , for messages not explicitly */
/* processed, it returns a FALSE                                        */
/*                                                                      */
/************************************************************************/BOOL FAR PASCAL DIALOGSMsgProc(HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
{switch(Message){case WM_INITDIALOG:cwCenter(hWndDlg, 0);/* initialize working variables                                */break; /* End of WM_INITDIALOG                                 */case WM_CLOSE:/* Closing the Dialog behaves the same as Cancel               */PostMessage(hWndDlg, WM_COMMAND, IDCANCEL, 0L);break; /* End of WM_CLOSE                                      */case WM_COMMAND:switch(wParam){case Edit1: /* Edit Control                                 */break;case IDS_ERR_REGISTER_CLASS: /* Button text: "Push"         */break;case IDCANCEL:/* Ignore data values entered into the controls        *//* and dismiss the dialog window returning FALSE       */EndDialog(hWndDlg, FALSE);break;}break;    /* End of WM_COMMAND                                 */default:return FALSE;}return TRUE;
} /* End of DIALOGSMsgProc                                      *//************************************************************************/
/*                                                                      */
/* nCwRegisterClasses Function                                          */
/*                                                                      */
/* The following function registers all the classes of all the windows  */
/* associated with this application. The function returns an error code */
/* if unsuccessful, otherwise it returns 0.                             */
/*                                                                      */
/************************************************************************/int nCwRegisterClasses(void)
{WNDCLASS   wndclass;    /* struct to define a window class             */memset(&wndclass, 0x00, sizeof(WNDCLASS));/* load WNDCLASS with window's characteristics                         */wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;wndclass.lpfnWndProc = WndProc;/* Extra storage for Class and Window objects                          */wndclass.cbClsExtra = 0;wndclass.cbWndExtra = 0;wndclass.hInstance = hInst;wndclass.hIcon = LoadIcon(hInst, "HELLO");wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);/* Create brush for erasing background                                 */wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wndclass.lpszMenuName = szAppName;   /* Menu Name is App Name */wndclass.lpszClassName = szAppName; /* Class Name is App Name */if(!RegisterClass(&wndclass))return -1;return(0);
} /* End of nCwRegisterClasses                                          *//************************************************************************/
/*  cwCenter Function                                                   */
/*                                                                      */
/*  centers a window based on the client area of its parent             */
/*                                                                      */
/************************************************************************/void cwCenter(hWnd, top)
HWND hWnd;
int top;
{POINT      pt;RECT       swp;RECT       rParent;int        iwidth;int        iheight;/* get the rectangles for the parent and the child                     */GetWindowRect(hWnd, &swp);GetClientRect(hWndMain, &rParent);/* calculate the height and width for MoveWindow                       */iwidth = swp.right - swp.left;iheight = swp.bottom - swp.top;/* find the center point and convert to screen coordinates             */pt.x = (rParent.right - rParent.left) / 2;pt.y = (rParent.bottom - rParent.top) / 2;ClientToScreen(hWndMain, &pt);/* calculate the new x, y starting point                               */pt.x = pt.x - (iwidth / 2);pt.y = pt.y - (iheight / 2);/* top will adjust the window position, up or down                     */if(top)pt.y = pt.y + top;/* move the window                                                     */MoveWindow(hWnd, pt.x, pt.y, iwidth, iheight, FALSE);
}/************************************************************************/
/*  CwUnRegisterClasses Function                                        */
/*                                                                      */
/*  Deletes any refrences to windows resources created for this         */
/*  application, frees memory, deletes instance, handles and does       */
/*  clean up prior to exiting the window                                */
/*                                                                      */
/************************************************************************/void CwUnRegisterClasses(void)
{WNDCLASS   wndclass;    /* struct to define a window class             */memset(&wndclass, 0x00, sizeof(WNDCLASS));UnregisterClass(szAppName, hInst);
}    /* End of CwUnRegisterClasses                                      */

编译生成的EXE尺寸14KB,在WINXP平台上运行顺畅,再做点儿工作就可以放在WIN10或WIN11平台上独立运行了。

在WIN10平台上建立16位程序运行环境

到Github上下载otvdm并解压到C盘,安装即是简单地运行一个inf文件,原理是把16位Windows的一些东西改动到Win10上,当16位运行在Win10上运行出错时截取下来,再用16位这些东西运行试一下,再出错再提示给用户错误信息,类似16位程序的虚拟机。

在WIN10平台上运行的效果如下图

关于优化xp平台的几点说明

XP平台比较老了,在虚拟中运行的话可以优化。

1. 现在机器的分辨率都比较高,要在设置中将分辨率设在120DPI到150DPI,同时选大字体、大图标,达到比较好的外观效果。

2. 现在的3键鼠标必须在XP上安装微软4,12版的鼠标驱动程序,其它版本的不管用。用意主要是激活滚轮。

3. 在控制面板中去掉Internet explorer的对勾,安装MyPal浏览器,它能正常访问现在的互联网。

4. 可以安装外挂万能无笔输入法和其它自己喜欢的输入法。与母机共享文件可以在虚拟机上外挂母机的共享文件夹,也可以通过网络邻居方式使用母机上的WebDAV空间。如何在IIS上配置WebDAV服务,在我的笔记《IIS WebDAV配置,https绑定及asp设置》中有详细记录。IIS WebDAV配置,https绑定及asp设置_Mongnewer的博客-CSDN博客

感觉IT的黄金时期是DOS到Windows的变革阶段,似乎那时全世界都在拥抱IT,甚至写个DBASE程序都能让人羡慕,那时有知识的人很受社会尊重,这与现在普遍叫喊的“内卷”似乎是完全不一样的状况。时代久远,翻遍互联网可能也找不到一篇如何用Quick C for windows的文章可参考了,我体验了就放记到CSDN笔记上吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/150491.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ElasticSearch】深入了解 ElasticSearch:开源搜索引擎的力量

文章目录 前言一、初识 ElasticSearch 搜索引擎1.1 ElasticSearch 的核心概念1.2 ElasticSearch 的演进历程1.3 ElasticSearch 的优势与未来 二、正排索引与倒排索引:数据库与 ElasticSearch 的差异2.1 对正排索引的认识2.2 对倒排索引的认识2.3 正排索引 vs. 倒排索…

【yolov系列:yolov7改进添加SIAM注意力机制】

yolo系列文章目录 文章目录 yolo系列文章目录一、SimAM注意力机制是什么?二、YOLOv7使用SimAM注意力机制1.在yolov7的models下面新建SimAM.py文件2.在common里面导入在这里插入图片描述 总结 一、SimAM注意力机制是什么? 论文题目:SimAM: A …

P1017 [NOIP2000 提高组] 进制转换

#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std;void zhuan(int n,int r) {if(n0) return ;int mn%r;//m为余数 if(m<0) m-r,nr;//如果余数小于0&#xff0c;转化为正数//将余数转化为ascll码方便输出…

土木硕设计院在职转码上岸

一、个人介绍 双非土木硕&#xff0c;98年&#xff0c;目前在北京&#xff0c;职位为前端开发工程师&#xff0c;设计院在职期间自学转码上岸&#x1f33f; 二、背景 本人于19年开始土木研究生生涯&#xff0c;研二期间去地产实习近半年(碧桂园和世茂&#xff0c;这两家的地产…

flex 布局:元素/文字靠右

前言 略 使用flex的justify-content属性控制元素的摆放位置 靠右 <view class"more">展开更多<text class"iconfont20231007 icon-zhankai"></text></view>.more {display: flex;flex-direction: row;color: #636363;justify-co…

校招秋招,性格和职业有关系吗?

企业在招聘应届毕业生时不再局限于普通的面试或者笔试&#xff0c;在互联网时代&#xff0c;为了能够更好的匹配需要的优质人才&#xff0c;企业会通过各种测试来提高招聘的准确率以及成功率。也许以前很多人都听说过性格和职业是有一定关系的&#xff0c;但是如何确定自己的性…

Go复合类型之数组类型

Go复合类型之数组 文章目录 Go复合类型之数组一、数组(Array)介绍1.1 基本介绍1.2 数组的特点 二、数组的声明与初始化2.1 数组声明2.2 常见的数据类型声明方法2.3 数组的初始化方式一&#xff1a;使用初始值列表初始化数组方法二&#xff1a;根据初始值个数自动推断数组长度方…

【C++】STL详解(十二)—— 用哈希表封装出unordered_map和unordered_set

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C学习 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C】STL…

阿里云ECS服务器上启动的portainer无法访问的问题

如下图&#xff0c;在阿里云ECS服务器上安装并启动了portainer&#xff0c;但是在自己电脑上访问不了远程的portainer。 最后发现是要在网络安全组里开放9000端口号&#xff0c;具体操作如下&#xff1a; 在云服务器管理控制台点击左侧菜单中的网络与安全-安全组&#xff0c;然…

黑豹程序员-架构师学习路线图-百科:Database数据库

文章目录 1、什么是Database2、发展历史3、数据库排行网4、总结 1、什么是Database 当今世界是一个充满着数据的互联网世界&#xff0c;各处都充斥着大量的数据。即这个互联网世界就是数据世界。 支撑这个数据世界的基石就是数据库&#xff0c;数据库也可以称为数据的仓库。 …

基于虚拟同步发电机控制的双机并联Simulink仿真模型

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【Redis】五大数据类型 、历史概述、nosql分类

文章目录 NoSql概述NoSql年代缓存 Memcached MySQL垂直拆分&#xff08;读写分离&#xff09;分库分表水平拆分Mysql集群最近为什么要用 NoSqlNoSql的四大分类 Redis测试性能 五大数据类型keyStringSetHashZset 前言&#xff1a;本文为看狂神视频记录的笔记 NoSql概述 NoSql年…

一篇理解http协议

一、http协议。 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种在Web中广泛使用的应用层协议&#xff0c;它定义了客户端和服务器之间的通信规则&#xff0c;简化了Web应用程序的开发和交互过程。其实传输是由TCP协议完成的。 HT…

idea Springboot 图书管理系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 图书管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#…

[NISACTF 2022]popchains - 反序列化+伪协议

[NISACTF 2022]popchains 一、解题流程二、小小疑惑 一、解题流程 1、链条&#xff1a;Road_is_Long&#xff08;construct->wakeup【page$r】-> toString【string$m】&#xff09;-> Make_a_Change&#xff08;construct->get【effort$t】&#xff09;-> Try_W…

基于Springboot实现简历管理系统演示【项目源码+论文说明】分享

基于Springboot实现简历管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;简历系统当然也不能排除在外。简历系统是以实际运用为开发背景&#xff0c;运用软件…

想要精通算法和SQL的成长之路 - 并查集的运用和案例(省份数量)

想要精通算法和SQL的成长之路 - 并查集的运用 前言一. 并查集的使用和模板1.1 初始化1.2 find 查找函数1.3 union 合并集合1.4 connected 判断相连性1.5 完整代码 二. 运用案例 - 省份数量 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 并查集的使用和模板 先说一下并查集…

Qt之显示PDF文件

之前使用过mupdf库&#xff0c;能够成功显示pdf&#xff0c;但是我用着有BUG&#xff0c;不太理解它的代码&#xff0c;搞了好久都不行。后面又试了其他库&#xff0c;如pdfium、popler、下载了很多例程&#xff0c;都跑不起来&#xff01;后面偶然得知xpdf库&#xff0c;看起来…

蛋仔派对如何获得蛋币,蛋仔派对怎么切换账号

在蛋仔派对游戏中&#xff0c;蛋币是一种虚拟货币&#xff0c;用以购买游戏道具或提升游戏体验。以下是五种可能的获得蛋币的方式&#xff1a; 关注【娱乐天梯】&#xff0c;获取内部福利号 1. 完成挑战和任务&#xff1a;玩家可以通过完成不同类型的任务和挑战来获取蛋币。任务…