翻译《The Old New Thing》 - The new scratch program

7a192c04fb484e14ba672bbba3d9d7b8.png

The new scratch program - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050422-08/?p=35813

Raymond Chen 2005年4月22日


译注:此篇是 翻译《The Old New Thing》 - The scratch program 姊妹篇,对 scratch 程序作作了升级,采用了现代 C++ 编程风格,避免了全局状态,并通过虚函数和基类指针提供了扩展性。

 

         我认为是时候更新我们过去一年来一直在使用的 scratch 程序了。我听说有一种叫做 C++ 的新语言,它很快就会变得非常流行,所以让我们也来跟风吧!

#define STRICT
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <windowsx.h>
#include <ole2.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <shlobj.h>
#include <shellapi.h>
HINSTANCE g_hinst;
class Window
{
public:
 HWND GetHWND() { return m_hwnd; }
protected:
 virtual LRESULT HandleMessage(
                         UINT uMsg, WPARAM wParam, LPARAM lParam);
 virtual void PaintContent(PAINTSTRUCT *pps) { }
 virtual LPCTSTR ClassName() = 0;
 virtual BOOL WinRegisterClass(WNDCLASS *pwc)
     { return RegisterClass(pwc); }
 virtual ~Window() { }
 HWND WinCreateWindow(DWORD dwExStyle, LPCTSTR pszName,
       DWORD dwStyle, int x, int y, int cx, int cy,
       HWND hwndParent, HMENU hmenu)
 {
  Register();
  return CreateWindowEx(dwExStyle, ClassName(), pszName, dwStyle,
                  x, y, cx, cy, hwndParent, hmenu, g_hinst, this);
 }
private:
 void Register();
 void OnPaint();
 void OnPrintClient(HDC hdc);
 static LRESULT CALLBACK s_WndProc(HWND hwnd,
     UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
 HWND m_hwnd;
};
void Window::Register()
{
    WNDCLASS wc;
    wc.style         = 0;
    wc.lpfnWndProc   = Window::s_WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = g_hinst;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = ClassName();
    WinRegisterClass(&wc);
}
LRESULT CALLBACK Window::s_WndProc(
               HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 Window *self;
 if (uMsg == WM_NCCREATE) {
  LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
  self = reinterpret_cast<Window *>(lpcs->lpCreateParams);
  self->m_hwnd = hwnd;
  SetWindowLongPtr(hwnd, GWLP_USERDATA,
            reinterpret_cast<LPARAM>(self));
 } else {
  self = reinterpret_cast<Window *>
            (GetWindowLongPtr(hwnd, GWLP_USERDATA));
 }
 if (self) {
  return self->HandleMessage(uMsg, wParam, lParam);
 } else {
  return DefWindowProc(hwnd, uMsg, wParam, lParam);
 }
}
LRESULT Window::HandleMessage(
                          UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 LRESULT lres;
 switch (uMsg) {
 case WM_NCDESTROY:
  lres = DefWindowProc(m_hwnd, uMsg, wParam, lParam);
  SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
  delete this;
  return lres;
 case WM_PAINT:
  OnPaint();
  return 0;
 case WM_PRINTCLIENT:
  OnPrintClient(reinterpret_cast<HDC>(wParam));
  return 0;
 }
 return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
void Window::OnPaint()
{
 PAINTSTRUCT ps;
 BeginPaint(m_hwnd, &ps);
 PaintContent(&ps);
 EndPaint(m_hwnd, &ps);
}
void Window::OnPrintClient(HDC hdc)
{
 PAINTSTRUCT ps;
 ps.hdc = hdc;
 GetClientRect(m_hwnd, &ps.rcPaint);
 PaintContent(&ps);
}
class RootWindow : public Window
{
public:
 virtual LPCTSTR ClassName() { return TEXT("Scratch"); }
 static RootWindow *Create();
protected:
 LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
 LRESULT OnCreate();
private:
 HWND m_hwndChild;
};
LRESULT RootWindow::OnCreate()
{
 return 0;
}
LRESULT RootWindow::HandleMessage(
                          UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 switch (uMsg) {
  case WM_CREATE:
   return OnCreate();
  case WM_NCDESTROY:
   // Death of the root window ends the thread
   PostQuitMessage(0);
   break;
  case WM_SIZE:
   if (m_hwndChild) {
    SetWindowPos(m_hwndChild, NULL, 0, 0,
                 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
                 SWP_NOZORDER | SWP_NOACTIVATE);
   }
   return 0;
  case WM_SETFOCUS:
   if (m_hwndChild) {
    SetFocus(m_hwndChild);
   }
   return 0;
 }
 return __super::HandleMessage(uMsg, wParam, lParam);
}
RootWindow *RootWindow::Create()
{
 RootWindow *self = new RootWindow();
 if (self && self->WinCreateWindow(0,
       TEXT("Scratch"), WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
       NULL, NULL)) {
      return self;
  }
 delete self;
 return NULL;
}
int PASCAL
WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd)
{
 g_hinst = hinst;
 if (SUCCEEDED(CoInitialize(NULL))) {
  InitCommonControls();
  RootWindow *prw = RootWindow::Create();
  if (prw) {
   ShowWindow(prw->GetHWND(), nShowCmd);
   MSG msg;
   while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
  }
  CoUninitialize();
 }
 return 0;
}

        这个程序的基本思想与我们旧的临时程序相同,但现在它有了新鲜的柠檬味 C++ 气息。我们不是在全局变量中保存状态,而是声明了一个 C++ 类并将其与窗口关联起来。

        为了简单起见,对象的生命周期与窗口本身绑定在一起。

        首先,有一个基本的 Window 类,我们将把它作为我们未来任何“与窗口关联的类”工作的基类。

        目前唯一的派生类是 RootWindow,这是顶级框架窗口,目前是程序使用的唯一窗口。

        你可能已经猜到,随着需求的出现,我们以后可能会有其他派生类。

   WinRegisterClass 方法之所以是虚拟的(并且没有做任何有趣的事情),是为了让派生类可以修改注册类时使用的 WNDCLASS

        我目前没有立即需要它,但如果我需要,拿来就能用。

        我们使用 GWLP_USERDATA 窗口长指针来存储关联类的指针,从而允许我们从窗口句柄中恢复对象。

        请注意,在 RootWindow::HandleMessage 方法中,我使用了 Visual C++ 的 __super 扩展。如果你不想依赖非标准扩展,你可以改为编写:

class RootWindow : public Window {
public:
 typedef Window super;
 ...(其余代码)
}

并使用 super 代替 __super

这个程序本身没有做什么有趣的事情;它只是未来示例的一个框架。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

普通人副业要趁早,5种靠谱且持久的赚钱副业

中年危机、35岁被裁&#xff0c;这些听起来就让人焦虑的词汇&#xff0c;是否也让你感到不安&#xff1f;别担心&#xff0c;只要你早早开启副业之旅&#xff0c;这些都不是问题。 今天&#xff0c;我要为你介绍的这5种副业&#xff0c;不仅能帮你赚钱&#xff0c;还能让你的能…

前端高频面试题 5.08

事件委托 事件委托是前端开发中常用的一种优化性能和代码可维护性的方法&#xff0c;它基于DOM的事件冒泡机制。当一个元素触发事件时&#xff0c;这个事件会按照从顶层到底层的顺序传播&#xff0c;直到最底层的元素&#xff08;通常是文档的根节点&#xff09;。事件委托利用…

张大哥笔记:如果不想继续打工,互联网创业或许是最好的出路!

互联网时代最好的出路&#xff0c;就是选择创业&#xff0c;不要选择打工。选择打工很亏&#xff0c;你学到的是打工的本事。而创业&#xff0c;看似不赚钱&#xff0c;看似倒霉&#xff0c;但是会锻炼出了你一天赚几千&#xff0c;甚至几万的本事。 随着互联网越来越被人们所…

Educational Codeforces Round 165 (Div. 2) A~E

A.Two Friends (思维) 题意&#xff1a; 小 A A A想开一个派对。他有 n n n个朋友&#xff0c;他希望至少有 2 2 2个朋友参加他的派对。 i i i 这个朋友最好的朋友是 p i p_i pi​ 。所有的 p i p_i pi​ 都是不同的&#xff0c;对于每一个 i ∈ [ 1 , n ] i \in [1, n] …

C++之泛型编程---有限双端队列结构容器

引言 为了解决工业领域代码容器的通用化&#xff0c;可以考虑C里的泛型编程概念。假设一个场景需要实时保存最近的n个数据并按照顺序依次处理时&#xff0c;就需要定义一种新的容器来满足要求。当容器不满时&#xff0c;添加数据直接到队尾&#xff0c;当容器数据已经为n个时&a…

毕设UI设计不会前端怎么办?今天看到了一款自动生成UI的项目-OpenUI

试用地址&#xff1a;Create a new Elemint (openui.fly.dev) OpenUI 是由 W&B 开发开源项目&#xff0c;旨在简化用户界面(UI)组件的构建过程。它通过允许开发者使用想象力描述 UI&#xff0c;然后实时看到渲染效果&#xff0c;使得 UI 开发变得有趣、快速且灵活。 这个…

CSS-盒子模型元素溢出

作用&#xff1a;控制溢出的元素的内容的显示方式 属性&#xff1a;overflow 属性值 属性值效果hidden溢出隐藏scroll溢出滚动&#xff08;无论是否溢出&#xff0c;都显示滚动条位置&#xff09;auto溢出滚动&#xff08;溢出才显示滚动条位置&#xff09; <!DOCTYPE html&…

npm无法安装node-sass 的问题

安装 node-sass 的问题呈现&#xff1a;4.9.0版本无法下载 Downloading binary from https://github.com/sass/node-sass/releases/download/v4.9.0/win32-x64-72_binding.node Cannot download "https://github.com/sass/node-sass/releases/download/v4.9.0/win32-x64-…

Pytorch学习笔记——卷积操作

一、认识卷积操作 卷积操作是一种数学运算&#xff0c;它涉及两个函数&#xff1a;输入函数&#xff08;通常是图像&#xff09;和卷积核&#xff08;也称为滤波器或特征检测器&#xff09;。卷积核在输入函数上滑动&#xff0c;将核中的每个元素与其覆盖的输入函数区域中的对应…

华为数据之道第四部分导读

目录 导读 第四部分 第10章 未来已来&#xff1a;数据成为企业核心竞争力 数据&#xff1a;新的生产要素 数据被列为生产要素&#xff1a;制度层面的肯定 数据将进入企业的资产负债表 数据资产的价值由市场决定 大规模数据交互的企业数据生态 数据生态离不开底层技术的…

618大促买什么数码好物最划算?必囤不后悔好物清单来了!

随着年度618购物盛宴的临近&#xff0c;作为数码领域的资深狂热者&#xff0c;满怀激情与憧憬为大家精心挑选了一系列令人瞩目的数码产品。无论你是热衷于追逐最新科技潮流的先锋&#xff0c;还是期望通过数码设备提升生活品质的优雅用户&#xff0c;这里都定有一款能触动你内心…

(动画详解)LeetCode20.有效的括号

题目描述 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 解题思路 栈的方法 遍历整个字符串 当检测到左括号的时候&#xff0c;就让左括号入栈 当检测到右括号的时候&#xff0c;就让左括号出栈与右括号对比 如果相等则继续比较直到结束&#xff0c;如果不相等…

在Linux中安装Docker

如果之前安装过旧版本的 Docker&#xff0c;可以使用下面命令卸载&#xff1a; yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine…

[华为OD]C卷 BFS 亲子游戏 200

题目&#xff1a; 宝宝和妈妈参加亲子游戏&#xff0c;在一个二维矩阵&#xff08;N*N&#xff09;的格子地图上&#xff0c;宝宝和妈妈抽签决定各自 的位置&#xff0c;地图上每个格子有不同的Q糖果数量&#xff0c;部分格子有障碍物。 游戏规则Q是妈妈必须在最短的时间&a…

我独自升级崛起账号注册 我独自升级怎么注册账号

近期&#xff0c;《我独自升级》这部动画凭借爆棚的人气&#xff0c;在各大平台上掀起了一阵观看热潮&#xff0c;其影响力不容小觑。借此时机&#xff0c;韩国游戏巨头网石集团敏捷响应&#xff0c;顺势推出了同名游戏《我独自升级&#xff1a;ARISE》&#xff0c;为粉丝们搭建…

淘宝/天猫商品描述API(taobao.item_get_desc)返回值详解

淘宝/天猫的商品描述API&#xff08;taobao.item_get_desc&#xff09;允许开发者获取指定商品的详细描述信息。这对于需要进行商品数据分析、构建商品详情页面或进行其他与商品相关的应用开发非常有用。下面&#xff0c;我们将详细解析这个API的返回值。 一、API概述 taobao.…

接收区块链的CCF会议--NDSS 2025 截止7.10 附录用率

会议名称&#xff1a;Network and Distributed System Security Symposium (NDSS) CCF等级&#xff1a;CCF A类学术会议 类别&#xff1a;网络与信息安全 录用率&#xff1a;2024年接收率19.5% Submissions are solicited in, but not limited to, the following areas: Ant…

【Qt】掌握Qt界面开发:窗口属性与资源嵌入技巧解析

文章目录 前言&#xff1a;1. windowTitle: 窗口标题2. windowIcon&#xff1a;窗口图标3. qrc 机制&#xff1a;4. windowOpacity&#xff1a;半透明效果总结&#xff1a; 前言&#xff1a; 在软件开发中&#xff0c;用户界面&#xff08;UI&#xff09;的构建是一个重要环节…

Deepsort算法研究

目录 1. 基于检测的多目标跟踪策略 1.1 多目标跟踪任务模型 1.2 多目标跟踪算法 SORT 1.3 DeepSORT 算法 2 . 基于轨迹的学生行为分类模型 2.1 学生行为分类规则 2.2 实际场景分析 1. 基于检测的多目标跟踪策略 多目标跟踪任务涉及跟踪多个目标的身份信息关联&#x…

C++类和对象(基础篇)

前言&#xff1a; 其实任何东西&#xff0c;只要你想学&#xff0c;没人能挡得住你&#xff0c;而且其实学的也很快。那么本篇开始学习类和对象&#xff08;C的&#xff0c;由于作者有Java基础&#xff0c;可能有些东西过得很快&#xff09;。 struct在C中的含义&#xff1a; …