{"id":108661,"date":"2023-08-29T07:00:00","date_gmt":"2023-08-29T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108661"},"modified":"2023-08-27T08:15:20","modified_gmt":"2023-08-27T15:15:20","slug":"20230829-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230829-00\/?p=108661","title":{"rendered":"The popularity of DOS\/4GW made Windows 95 game compatibility a little easier, but with higher stakes"},"content":{"rendered":"<p>By far, <a title=\"DOS\/4GW and Protected Mode\" href=\"https:\/\/pikuma.com\/blog\/what-is-dos4gw-protected-mode\"> the most popular so-called DOS Extender in the early 1990&#8217;s was DOS\/4GW<\/a>. MS-DOS game compatibility occupied a very large portion of my time during Windows 95 development, so I saw a lot of DOS Extender banners, most frequently the DOS\/4GW banner.<\/p>\n<p>Now, you might wonder, &#8220;How did these games even run in Windows 95 if they came with a DOS Extender? Wouldn&#8217;t the extender try to enter protected mode and fail, because Windows was already managing protected mode?&#8221;<\/p>\n<p>The trick is that these extenders were really two programs bundled together. One was a protected mode server, and the other was a protected mode client library.<\/p>\n<p>In the beginning, there was the Virtual Control Program Interface (VCPI), which was supported by expanded memory managers like EMM386. These expanded memory managers barely used protected mode at all: The only thing they cared about was getting access to memory above the 1MB boundary, so they set up some page tables in order to map extended memory into the expanded memory page frame, but did no other virtualization. MS-DOS ran in a virtual machine that had full hardware access, and the VCPI interface let an MS-DOS application say, &#8220;Hey, I&#8217;d like to take over complete control of the system now,&#8221; and VCPI would say &#8220;Sure, no problem!&#8221;<\/p>\n<p>The VCPI interface quickly faded in popularity because no protected mode operating system (like Windows 3.0 in enhanced mode) would let any program take over complete control of the system. You would basically be suspending the old operating system in order to let the MS-DOS program take over as its own new custom operating system. Windows 3.0 introduced a new interface called the DOS Protected Mode Interface (DPMI) which let MS-DOS programs request that their code execute in protected mode, but only in user mode. The DPMI provider remained in control of kernel mode.<\/p>\n<p>Okay, so back to DOS\/4GW. When it started up, the DOS\/4GW extender looked around to see if a DPMI server was already running. If not, then it installed itself as the DPMI server. But if a DPMI server was already running, then it allowed that DPMI server to remain in charge.<\/p>\n<p>The game communicated only with the DPMI client portion of the library, which it used to transition to 32-bit mode, allocate memory, and do all those 32-bit things that these 32-bit game wanted to 32-bit do.<\/p>\n<p>In other words, we have the following block diagram:<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" title=\"The game code runs in ring 3 and communicates with the DPMI client (the DOS\/4GW DPMI client) also in ring 3. The DPMI client communicates with a DPMI server. If running inside Windows, the DPMI server is Window sitself. If running standalone, then the DPMI server is the DOS\/4GW DPMI server.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>Inside Windows<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>Standalone<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 3px;\">DPMI server<br \/>\n(ring 0)<\/td>\n<td style=\"border: solid 1px gray; xadding: 1em;\">Windows<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; xadding: 1em;\">DOS\/4GW<br \/>\nDPMI Server<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"padding: 0;\">\u2921<\/td>\n<td>&nbsp;<\/td>\n<td style=\"padding: 0;\">\u2922<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 3px;\">DPMI client<br \/>\n(ring 3)<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; xadding: 1em;\">DOS\/4GW<br \/>\nDPMI Client<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"padding: 0;\">\u21c5<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"padding: 3px;\">Game code<br \/>\n(ring 3)<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; xadding: 1em;\">Game<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Both Windows and the DOS\/4GW DPMI server implement the DPMI interface, so the DOS\/4GW DPMI client used standard DPMI calls to communicate with both servers.<\/p>\n<p>This was great for application compatibility, because if there was some issue with how the DOS\/4GW client communicated with the DOS\/4GW server, we just had to fix it once, and it fixed a lot of games. On the other hand, if the issue couldn&#8217;t be fixed, it broke a lot of games.<\/p>\n<p>High risk, high reward.<\/p>\n<p>Miraculously, most games <i>just worked<\/i> despite running under a different DPMI server from what they were originally developed with. There were occasional issues with specific games. Popular ones include <a title=\"Getting MS-DOS games to run on Windows 95: Virtual memory\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160328-00\/?p=93204\"> games which assumed that all memory was physical<\/a> and <a title=\"Getting MS-DOS games to run on Windows 95: The interrupt flag\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160404-00\/?p=93261\"> games which assumed the interrupt flag was unvirtualized<\/a>, but for the most part, things worked well enough that the remaining issues could be treated as app-specific bugs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A popular path to protected mode.<\/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-108661","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>A popular path to protected mode.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108661","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=108661"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108661\/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=108661"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108661"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108661"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}