{"id":112605,"date":"2026-08-11T07:00:00","date_gmt":"2026-08-11T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112605"},"modified":"2026-08-11T21:42:04","modified_gmt":"2026-08-12T04:42:04","slug":"20260811-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260811-00\/?p=112605","title":{"rendered":"The little-known <TT>winstart.bat<\/TT> batch file"},"content":{"rendered":"<p>Reader Otul Osan wants to know <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260123-00\/?p=112008&amp;commentid=143764#comment-143764\"> what the use case for <tt>C:\\<wbr \/>WINDOWS\\<wbr \/>WINSTART.BAT<\/tt> was, compared to <tt>C:\\<wbr \/>AUTOEXEC.BAT<\/tt><\/a> and when exactly during system startup it launches.<\/p>\n<p>In Windows 95, you could create a <tt>winstart.bat<\/tt> file in your Windows directory. During startup, the virtual machine manager initializes and creates the so-called &#8220;System virtual machine&#8221; (the &#8220;System VM&#8221;), which is the virtual machine that all Windows programs run in. But before running the user-mode kernel in that virtual machine, the virtual machine manager runs the <tt>winstart.bat<\/tt> batch file if it exists.<\/p>\n<p>In pictures: First, we boot up MS-DOS and the command prompt. (Note: All diagrams omit lots of details not relevant to the discussion and are not to scale.)<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 40ex;\">(unused)<\/td>\n<td style=\"border: solid 1px currentcolor;\">MS-DOS<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The box labeled &#8220;Stuff&#8221; is a catch-all for random things that go at low addresses, like the interrupt vector table and the BIOS data area.<\/p>\n<p>Next, <tt>command.com<\/tt> runs <tt>autoexec.bat<\/tt>, which might install some TSRs.<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 30ex;\">(unused)<\/td>\n<td style=\"border: solid 1px currentcolor;\">MS-DOS<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And then Windows starts up and initializes the virtual machine manager. The system is now running in protected mode with a virtual machine running in v86 mode, and that virtual machine is initialized with whatever was running in real mode at the time the virtual machine manager took over.\u00b9<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 30ex;\">(unused)<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td style=\"border: solid 1px currentcolor;\">ring 0: virtual machine manager<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>I crossed out MS-DOS because the virtual machine manager took over responsibility for the file system and shut off the real-mode file system in MS-DOS.<\/p>\n<p>At this point, the virtual machine manager runs <tt>winstart.bat<\/tt> inside the virtual machine, and maybe it installs another TSR.<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR2<\/td>\n<td style=\"border: solid 1px currentcolor; width: 20ex;\">(unused)<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td style=\"border: solid 1px currentcolor;\">ring 0: virtual machine manager<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And then we start the user-mode kernel that is in charge of Windows applications. That user-mode kernel switches the virtual machine into protected mode and starts running what most people think of as Windows.<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR2<\/td>\n<td style=\"border: solid 1px currentcolor; width: 20ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<tr>\n<td colspan=\"6\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>prot mode<br \/>\n(ring 3)<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"5\">GUI stuff<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td style=\"border: solid 1px currentcolor;\">ring 0: virtual machine manager<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And then from the Windows GUI, you decide to open a command prompt, which means creating a second virtual machine.<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR2<\/td>\n<td style=\"border: solid 1px currentcolor; width: 20ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<tr>\n<td colspan=\"6\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>prot mode<br \/>\n(ring 3)<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"5\">GUI stuff<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td style=\"border: solid 1px currentcolor;\" rowspan=\"3\">ring 0: virtual machine manager<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 30ex;\">COMMAND.COM<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Notice that the virtual machine running <tt>command.com<\/tt> is a copy of the system when Windows started.\u00b2 So it has TSR1 (from <tt>autoexec.bat<\/tt>) but not TSR2 (from <tt>winstart.bat<\/tt>).<\/p>\n<p>If you install a TSR in the command prompt virtual machine, you get<\/p>\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR2<\/td>\n<td style=\"border: solid 1px currentcolor; width: 20ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<tr>\n<td colspan=\"6\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>prot mode<br \/>\n(ring 3)<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"5\">GUI stuff<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td style=\"border: solid 1px currentcolor;\" rowspan=\"3\">ring 0: virtual machine manager<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">\n<table style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>v86 mode<\/td>\n<td style=\"border: solid 1px currentcolor;\">Stuff<\/td>\n<td style=\"border: solid 1px currentcolor; width: 10ex;\">TSR1<\/td>\n<td style=\"border: solid 1px currentcolor; width: 8ex;\">TSR3<\/td>\n<td style=\"border: solid 1px currentcolor; width: 22ex;\">COMMAND.COM<\/td>\n<td style=\"border: solid 1px currentcolor;\"><span style=\"text-decoration: line-through;\">MS-DOS<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Okay, now that we see how the pieces fit together, we can reverse-engineer the purpose of <tt>winstart.bat<\/tt>.<\/p>\n<p>The intended purpose of <tt>winstart.bat<\/tt> is batch file is to allow you to install TSRs that will apply only to Windows programs. For example, you might install network drivers to support your Windows programs. You might choose this option instead of installing them globally because you don&#8217;t care about networking for your MS-DOS programs and want to free up conventional memory for them. Or because those drivers don&#8217;t support running in multiple virtual machines, so you&#8217;ll take them in the System VM and forego them for your MS-DOS programs.<\/p>\n<p>What I find interesting is that most people who discover this say that it&#8217;s a feature of Windows 95. But really, it&#8217;s a feature of Windows 3.1 (and possibly even Windows 3.0). You can find it documented in the <a href=\"https:\/\/archive.org\/details\/bitsavers_microsoftr5Windows3.1ResourceKit199202_48972813\/page\/263\/mode\/2up\"> Windows 3.1 Resource Kit<\/a> on page 263. That page even has a nice table showing three ways of launching TSRs and how they are visible in the different virtual machines. (In this table, &#8220;TSR visible in virtual machines&#8221; really means &#8220;TSR visible in non-Windows virtual machines&#8221;, but the documentation takes the convention that the term &#8220;virtual machine&#8221; refers only to non-Windows virtual machines and not to the virtual machine running Windows itself, which it simply calls &#8220;Windows&#8221;.)<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Where TSR is loaded<\/th>\n<th>TSR visible in Windows?<\/th>\n<th>TSR visible in virtual machines?<\/th>\n<\/tr>\n<tr>\n<td>From MS-DOS<\/td>\n<td>Yes<\/td>\n<td>Yes, all virtual machines<\/td>\n<\/tr>\n<tr>\n<td>From WINSTART.BAT<\/td>\n<td>Yes<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td>In a single virtual machine<\/td>\n<td>No<\/td>\n<td>Only that virtual machine<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u00b9 Think about that: We booted an operating system and then booted another operating system around it, so that the original operating system was now running inside a virtual machine controlled by the second operating system. It&#8217;s like leaving your house, walking down the street, and halfway down the block, realizing that you&#8217;re now walking inside a movie studio set.<\/p>\n<p>\u00b2 It isn&#8217;t actually a copy of the system at the time Windows started. Rather, it is a copy of the system VM, but only the parts that existed at the time Windows started. How this worked is too complex to try to explain in a footnote. Maybe I&#8217;ll discuss it some other time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It had been there long before Windows 95, but nobody remembered.<\/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-112605","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>It had been there long before Windows 95, but nobody remembered.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112605","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=112605"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112605\/revisions"}],"predecessor-version":[{"id":112606,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112605\/revisions\/112606"}],"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=112605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}