正确的「记事本」打开方式:能渲染3D图像,还能玩贪吃蛇

简介: 云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 渲染3D图像,一个「记事本」就够了。 最近,GitHub上一名叫“Kyle Halladay”的小哥,便上传了这样一个项目,用记事本来渲染图像。

云栖号资讯:【点击查看更多行业资讯
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!


渲染3D图像,一个「记事本」就够了。

最近,GitHub上一名叫“Kyle Halladay”的小哥,便上传了这样一个项目,用记事本来渲染图像。

效果是这样的:

1

立方体旋转、阴影变化,还挺有内味的。

还有贪吃蛇效果的:

2

那么,小哥是如何拿记事本,就做到这些效果的呢?

正确的「记事本」打开方式

据小哥介绍,所有的输入和渲染效果,都是在记事本中完成。

在此之前,需要做一些设置工作。

首先,是将键盘事件(Key Event),发送到正在运行的记事本。

这里就要用到 Visual Studio 提供的一个叫 Spy + + 的工具,可以列出组成给定应用程序的所有窗口。

3

Spy + + 显示了要找的记事本子窗口是“编辑”窗口。

一旦我知道了这一点,就只需要搞清楚 Win32函数调用的正确组合,用来获得该 UI 元素的 HWND,然后将输入发送过去。

得到的 HWND 是这样的:

{
  HWND curWnd = GetTopWindow(0); //0 arg means to get the window at the top of the Z order
  char classNameBuf[256];

while (curWnd != NULL){
    DWORD curPid;
    DWORD dwThreadId = GetWindowThreadProcessId(curWnd, &curPid);

    if (curPid == pid){
      GetClassName(curWnd, classNameBuf, 256);
      if (strcmp(className, classNameBuf) == 0) return curWnd;

      HWND childWindow = FindWindowEx(curWnd, NULL, className, NULL);
      if (childWindow != NULL) return childWindow;
    }
    curWnd = GetNextWindow(curWnd, GW_HWNDNEXT);
  }
  return NULL;

一旦拿到了正确的控件 HWND,在记事本的编辑控件中绘制一个字符,便是使用 PostMessage 向它发送一个 WM char 事件的问题。

接下来,就是建一个内存扫描器 (Memory Scanner),这里要用到一个叫做 CheatEngine 的工具。

基本算法如下:

1

内存扫描程序需要做的第一件事,就是遍历进程分配的内存。

因为 Windows 上每个64位进程的虚拟内存范围是相同的,所以需要制作一个指向地址0的指针,然后使用 VirtualQueryEx 获取目标程序的虚拟地址信息。

将具有相同内存属性的内容页,组织到 MEMORY basic information 结构中,因此,可能是 VirtualQueryEx 为给定地址返回的结构包含超过1页的信息。

一旦有了第一个 MEMORY basic information 结构,在内存中进行迭代只需要将当前结构的 BaseAddress 和 RegionSize 成员添加到一起,并将新地址提供给 VirtualQueryEx 以获得下一组连续的页面。

char* FindBytePatternInProcessMemory(HANDLE process, const char* pattern, size_t patternLen)
{
  char* basePtr = (char*)0x0;

  MEMORY_BASIC_INFORMATION memInfo;

  while (VirtualQueryEx(process, (void*)basePtr, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)))
  {
    const DWORD mem_commit = 0x1000;
    const DWORD page_readwrite = 0x04;
    if (memInfo.State == mem_commit && memInfo.Protect == page_readwrite)
    {
      // search this memory for our pattern
    }

    basePtr = (char*)memInfo.BaseAddress + memInfo.RegionSize;
  }
}

然后,是在进程内存中,搜索字节模式 (Byte Pattern)的工作,此处需要一个叫做 ReadProcessMemory 的工具。

一旦内存被复制到本地可见的缓冲区,搜索字节模式就很容易了。

char* FindPattern(char* src, size_t srcLen, const char* pattern, size_t patternLen)
{
  char* cur = src;
  size_t curPos = 0;

  while (curPos < srcLen){
    if (memcmp(cur, pattern, patternLen) == 0){
      return cur;
    }

    curPos++;
    cur = &src[curPos];
  }
  return nullptr;
}
char* FindBytePatternInProcessMemory(HANDLE process, const char* pattern, size_t patternLen)
{
  MEMORY_BASIC_INFORMATION memInfo;
  char* basePtr = (char*)0x0;

  while (VirtualQueryEx(process, (void*)basePtr, &memInfo, sizeof(MEMORY_BASIC_INFORMATION))){
    const DWORD mem_commit = 0x1000;
    const DWORD page_readwrite = 0x04;
    if (memInfo.State == mem_commit && memInfo.Protect == page_readwrite){
      char* remoteMemRegionPtr = (char*)memInfo.BaseAddress;
      char* localCopyContents = (char*)malloc(memInfo.RegionSize);

      SIZE_T bytesRead = 0;
      if (ReadProcessMemory(process, memInfo.BaseAddress, localCopyContents, memInfo.RegionSize, &bytesRead)){
        char* match = FindPattern(localCopyContents, memInfo.RegionSize, pattern, patternLen);

        if (match){
          uint64_t diff = (uint64_t)match - (uint64_t)(localCopyContents);
          char* processPtr = remoteMemRegionPtr + diff;
          return processPtr;
        }
      }
      free(localCopyContents);
    }
    basePtr = (char*)memInfo.BaseAddress + memInfo.RegionSize;
  }
}

需要注意的是,记事本将屏幕上的文本缓冲区作为 UTF-16数据存储,因此提供给 FindBytePatternInMemory ()的字节模式也必须是 UTF-16。

更多细节描述,可以参考文末的参考链接。

更多的「记事本」玩法

当然,关于记事本的别样玩法,还有好多。

例如,有拿记事本完成「快排」的可视化。

3

还有用记事本自制绘图软件的。

4

那么,你还有更炫酷的「记事本」玩法吗?

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

原文发布时间:2020-05-24
本文作者:金磊
本文来自:“量子位公众号”,了解相关信息可以关注“公众号 QbitAI”

相关文章
|
11月前
|
人机交互 Windows
零基础VB教程047期:如何制作自己的记事本第2节?CommonDialog控件讲解
零基础VB教程047期:如何制作自己的记事本第2节?CommonDialog控件讲解
105 0
|
C语言 C++
【VS使用】如何换VS2022背景颜色和分屏观看多文件,还有快捷复制粘贴?
【VS使用】如何换VS2022背景颜色和分屏观看多文件,还有快捷复制粘贴?
269 0
【VS使用】如何换VS2022背景颜色和分屏观看多文件,还有快捷复制粘贴?
|
数据可视化
搭建完菜单后运行不显示菜单的原因及其解决方法(拼图小游戏)
在搭建完菜单以后,程序不报错也能运行,但是运行结果就是一个框,就跟没有搭建过菜单一样,如下图所示,没有我们想象中的菜单栏,更别说有下拉菜单了,但是如果将搭建菜单的代码单独放到一个测试类中去测试一下的话,会显示出来菜单,也就是说我们搭建菜单的核心代码是没有问题的
123 0
搭建完菜单后运行不显示菜单的原因及其解决方法(拼图小游戏)
|
Shell
【开发小技巧】添加鼠标右键通过xx打开文件夹菜单
【开发小技巧】添加鼠标右键通过xx打开文件夹菜单
257 0
【开发小技巧】添加鼠标右键通过xx打开文件夹菜单
|
数据采集 JavaScript Python
Python爬虫:selenium打开新窗口和多窗口切换
Python爬虫:selenium打开新窗口和多窗口切换
955 0
解决Typora打开后没反应,一片空白,无法编辑的问题
解决Typora打开后没反应,一片空白,无法编辑的问题
|
Web App开发 Java
小玩意 - Chrome插件——GreenChrome(双击关闭标签,新窗口打开新地址)
小玩意 - Chrome插件——GreenChrome(双击关闭标签,新窗口打开新地址)
967 0
小玩意 - Chrome插件——GreenChrome(双击关闭标签,新窗口打开新地址)
“想玩点花式?” 试试快捷键操作编辑器吧(Unity3D)
在使用Unity中可能需要使用快捷键执行一些操作,或者修改Unity自带的快捷键,接下来就看一下,如何设置自定义快捷键吧
|
C#
wpf 复制/剪切到本地系统剪切板中以供右键粘贴用
原文:wpf 复制/剪切到本地系统剪切板中以供右键粘贴用   http://www.cnblogs.com/yhdkzy/archive/2012/11/27/2790655.html   ///         /// 复制或剪切文件到剪切板         /// ...
1220 0
|
API 图形学 Android开发
Unity复制粘贴剪切板各平台源码
Unity直接复制粘贴剪切板一句代码。 本文提供全流程,中文翻译。 助力快速完成 Unity 复制粘贴的实现 为初学者节省宝贵的时间,避免采坑! 现实测,在2018 、2019版本后 直接用一个 API 即可实现 GUIUtility.systemCopyBuffer Chinar测试 安卓 与PC 端 尚未发现任何问题 例如:直接复制一些信息,让玩家可以直接粘贴的方式,分享给好友。
3127 0

热门文章

最新文章