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

2023-10-07 06:44

本文主要是介绍在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笔记上吧。

这篇关于在WIN10平台上体验Microsoft古老的Quick C 1.0编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/156735

相关文章

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。