{"id":109067,"date":"2023-11-27T07:00:00","date_gmt":"2023-11-27T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109067"},"modified":"2023-11-27T08:48:33","modified_gmt":"2023-11-27T16:48:33","slug":"20231127-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231127-00\/?p=109067","title":{"rendered":"In Windows 3.1 and Windows 95, what is a &#8220;grabber&#8221;?"},"content":{"rendered":"<p>Twitter user @indiocolifa asked <a href=\"https:\/\/twitter.com\/indiocolifa\/status\/1559939987319263238\"> what &#8220;grabbers&#8221; were in Windows 3.1 and Windows 95<\/a>.<\/p>\n<p>Windows 3.0 Enhanced Mode introduced the ability to run MS-DOS programs in a virtual machine. This by itself was already quite an achievement, but it didn&#8217;t stop there. It also let you put the MS-DOS session <i>in a window<\/i>, and run it on the screen along with your other Windows programs.<\/p>\n<p>This was crazy.\u00b9<\/p>\n<p>Here&#8217;s how it worked.<\/p>\n<p>The virtual display driver is the driver whose job it was to make each virtual machine think it had its own video card. When the program running in the virtual machine modifies video memory, the virtual display driver notifies another driver whose job it is to bridge the gap between the virtual machines and the graphical user interface. This bridge driver has a buddy application running on the Windows desktop, called <code>WINOLDAP<\/code>, one copy for each MS-DOS virtual machine.\u00b2 The name <code>WINOLDAP<\/code> stands for &#8220;Window for Old Apps&#8221;, where &#8220;Window&#8221; referred to new-hotness GUI windows, and &#8220;old apps&#8221; referred to old and busted MS-DOS apps.<\/p>\n<p>When <code>WINOLDAP<\/code> receives the notification that there was a change to video memory, it tells the &#8220;grabber&#8221; that the game was afoot.<\/p>\n<p>Each video driver has its own grabber, short for &#8220;video frame grabber&#8221;. When called by <code>WINOLDAP<\/code>, the grabber communicates with its partner video driver to get the new video data, figure out what parts of the screen changed, and convert the raw video memory into Windows text and graphics calls in order to reproduce the contents in a GUI window. After obtaining the raw changed pages from the video driver, the grabbers try to be clever and do things like diff the previous and new screen contents to render only the parts that changed, and to convert large blank areas to simple <code>Fill\u00adRect<\/code> calls instead of printing a lot of space characters. They also look for ways to re-use the old screen contents: If the screen appears to have scrolled upward one line, then instead of rendering the entire contents again, it did a <code>ScrollWindow<\/code> to move the existing pixels, and then painted the single new line at the bottom. Of course, the effort to speed up rendering by minimizing the number of graphics rendering calls needs to be balanced against the extra cost of doing all the diffing and scroll detection, so there was a constant trade-off being made: The extra work you do looking for, say, scrolling optimizations, might end up costing more than it saved.<\/p>\n<p>In Windows 95, I was the one responsible for the grabbers, and I made some improvements to text rendering performance, and a lot of improvements to graphics rendering performance. In particular, Windows 3.1 could not run graphical MS-DOS programs in a window, but Windows 95 could: The video driver folks were able to improve graphics virtualization, and my optimizations for graphics rendering made it possible to re-render the screen contents in real time.<\/p>\n<p>Of course, if you had a low-end system, that real-time rendering might be only two frames per second, but that&#8217;s good enough for a program that changes the screen relatively infrequently anyway, such as a program for printing greeting cards. You&#8217;re not going to be playing DOOM in a windowed MS-DOS session.\u2074<\/p>\n<p>\u00b9 Oh, and I should also note that this was 1990, so everything was written in assembly language.\u00b3<\/p>\n<p>\u00b2 We saw some time ago how that driver <a title=\"How did Windows 3.1s virtual machine manager get the information to show in the text-mode Alt+Tab switcher?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211129-00\/?p=105979\"> worked with the <code>WINOLDAP<\/code> program to feed the character-mode <kbd>Alt<\/kbd>+<kbd>Tab<\/kbd> interface<\/a>.<\/p>\n<p>\u00b3 Also, we didn&#8217;t have Unicode yet, so the code is littered with <code>IFDEF<\/code>s to support compiling the operating system for Western European single-byte character sets or for East Asian double-byte character sets.<\/p>\n<p>\u2074 Even though you wouldn&#8217;t want to play DOOM in a windowed MS-DOS session, that didn&#8217;t stop people from doing it anyway, just to show it could be done.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It grabbed your MS-DOS screen and put it into a window.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-109067","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>It grabbed your MS-DOS screen and put it into a window.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109067","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109067"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109067\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}