快生活 - 生活常识大全

正确的记事本打开方式能渲染图像还能


  金磊 发自 凹非寺量子位 报道 | 公众号 QbitAI
  渲染3D图像,一个「记事本」就够了。
  最近,GitHub上一名叫"Kyle Halladay"的小哥,便上传了这样一个项目,用记事本来渲染图像。
  效果是这样的:
  立方体旋转、阴影变化,还挺有内味的。
  还有贪吃蛇效果的:
  那么,小哥是如何拿记事本,就做到这些效果的呢?
  正确的「记事本」打开方式
  据小哥介绍,所有的输入和渲染效果,都是在记事本中完成。
  在此之前,需要做一些设置工作。
  首先,是将键盘事件(Key Event),发送到正在运行的记事本。
  这里就要用到 Visual Studio 提供的一个叫 Spy + + 的工具,可以列出组成给定应用程序的所有窗口。
  Spy + + 显示了要找的记事本子窗口是"编辑"窗口。
  一旦我知道了这一点,就只需要搞清楚 Win32函数调用的正确组合,用来获得该 UI 元素的 HWND,然后将输入发送过去。
  得到的 HWND 是这样的:
  HWNDGetWindowForProcessAndClassName(DWORDpid,constchar*className){HWNDcurWnd=indow(0);//0argmeanstogetthewindowatthetopoftheZordercharclassNameBuf[256];while(curWnd!=NULL){DWORDcurPid;DWORDdwThreadId=GetWindowThreadProcessId(curWnd,&curPid);if(curPid==pid){GetClassName(curWnd,classNameBuf,256);if(strcmp(className,classNameBuf)==0)returncurWnd;HWNDchildWindow=FindWindowEx(curWnd,NULL,className,NULL);if(childWindow!=NULL)returnchildWindow;}curWnd=GetNextWindow(curWnd,GW_HWNDNEXT);}returnNULL;}
  一旦拿到了正确的控件 HWND,在记事本的编辑控件中绘制一个字符,便是使用 PostMessage 向它发送一个 WM char 事件的问题。
  接下来,就是建一个内存扫描器 (Memory Scanner),这里要用到一个叫做 CheatEngine 的工具。
  基本算法如下:
  FOREACHblockofmemoryallocatedbyourtargetprocessIFthatblockiscommittedandread/writeenabledScanthecontentsofthatblockforourbytepatternIFWEFINDITreturnthataddress
  内存扫描程序需要做的第一件事,就是遍历进程分配的内存。
  因为 Windows 上每个64位进程的虚拟内存范围是相同的,所以需要制作一个指向地址0的指针,然后使用 VirtualQueryEx 获取目标程序的虚拟地址信息。
  将具有相同内存属性的内容页,组织到 MEMORY basic information 结构中,因此,可能是 VirtualQueryEx 为给定地址返回的结构包含超过1页的信息。
  一旦有了第一个 MEMORY basic information 结构,在内存中进行迭代只需要将当前结构的 BaseAddress 和 RegionSize 成员添加到一起,并将新地址提供给 VirtualQueryEx 以获得下一组连续的页面。
  char*FindBytePatternInProcessMemory(HANDLEprocess,constchar*pattern,size_tpatternLen){char*basePtr=(char*)0x0;MEMORY_BASIC_INFORMATIONmemInfo;while(VirtualQueryEx(process,(void*)basePtr,&memInfo,sizeof(MEMORY_BASIC_INFORMATION))){constDWORDit=0x1000;constDWORDpage_readwrite=0x04;if(memInfo.State==it&&memInfo.Protect==page_readwrite){//searchthismemoryforourpattern}basePtr=(char*)memInfo.BaseAddress+memInfo.RegionSize;}}
  然后,是在进程内存中,搜索字节模式 (Byte Pattern)的工作,此处需要一个叫做 ReadProcessMemory 的工具。
  一旦内存被复制到本地可见的缓冲区,搜索字节模式就很容易了。
  char*FindPattern(char*src,size_tsrcLen,constchar*pattern,size_tpatternLen){char*cur=src;size_tcurPos=0;while(curPos char*FindBytePatternInProcessMemory(HANDLEprocess,constchar*pattern,size_tpatternLen){MEMORY_BASIC_INFORMATIONmemInfo;char*basePtr=(char*)0x0;while(VirtualQueryEx(process,(void*)basePtr,&memInfo,sizeof(MEMORY_BASIC_INFORMATION))){constDWORDit=0x1000;constDWORDpage_readwrite=0x04;if(memInfo.State==it&&memInfo.Protect==page_readwrite){char*remoteMemRegionPtr=(char*)memInfo.BaseAddress;char*localCopyContents=(char*)malloc(memInfo.RegionSize);SIZE_TbytesRead=0;if(ReadProcessMemory(process,memInfo.BaseAddress,localCopyContents,memInfo.RegionSize,&bytesRead)){char*match=FindPattern(localCopyContents,memInfo.RegionSize,pattern,patternLen);if(match){uint64_tdiff=(uint64_t)match-(uint64_t)(localCopyContents);char*processPtr=remoteMemRegionPtr+diff;returnprocessPtr;}}free(localCopyContents);}basePtr=(char*)memInfo.BaseAddress+memInfo.RegionSize;}}
  需要注意的是,记事本将屏幕上的文本缓冲区作为 UTF-16数据存储,因此提供给 FindBytePatternInMemory ()的字节模式也必须是 UTF-16。
  更多细节描述,可以参考文末的参考链接。
  更多的「记事本」玩法
  当然,关于记事本的别样玩法,还有好多。
  例如,有拿记事本完成「快排」的可视化。
  还有用记事本自制绘图软件的。
  那么,你还有更炫酷的「记事本」玩法吗?
  欢迎在评论区留言推荐~
  参考链接
  khalladay/render-with-notepadblog/2020/05/20/Rendering-With-Notepad.html:
  — 完 —
  量子位 QbitAI · 头条号签约
  关注我们,第一时间获知前沿科技动态
网站目录投稿:雨筠