A Fix for Win95Cmd's Pipes

Win95Cmd.exe is a port of the NT/2000/XP command processor for Windows 95/98 systems, the 2000 version can be downloaded from http://www.neuro.gatech.edu/users/cwilson/cygutils/consize/Win95Cmd.exe (also check out the Cygwin Utilities page). Win95Cmd is also available from Microsoft (in a huge SDK somewhere).

Win95Cmd is useful for Win9x users who wish to use the more powerful NT-style "dos" commands, or want to verify that a batch is Cmd-compatible. Cmd-compatible does not equate to NT-compatible, depending on what external programs are called, but it is a useful metric for those wishing cross-platform compatibility.Win95Cmd supports almost all of Cmd.exe's internal commands, the major exceptions are FOR /F and until just a few days ago, the lowly pipe. Then I ran across a post by Charles Dye that explains why pipes don't work and how to fix the situation. Excellent! I was blown away by the "why" - Cmd uses %comspec% to launch multiple threads. The autorun registry workaround is slick, had I known about the comspec thing I probably would have solved using a crude batch, something like...

This works but is limiting. The autorun key makes the required setting no matter how Win95Cmd came to be running without having to think about it (oops no pipes, not running from my batch.. back goes the key).

I'm not crazy about editing the registry, and sometimes I move the file around or change Win95Cmd versions, so I made a batch file that automates the process. The batch is for English Win9x but should be adaptable to other languages if necessary. Making the batch wasn't as trivial as I thought! Finding the file's path wasn't a big deal but converting it to a valid registry (.reg) file took more effort: I discovered that filenames in registry files must have the backslashes doubled for RegEdit to import properly. At first I thought of using Win95Cmd itself to perform this feat but to no avail, FOR /F doesn't work. Next I considered inserting my homemade batch-embedded search and replace binary I often use but that code is scary looking, larger than I'd like, and provides little or no opportunity for learning. So I settled on a DEBUG solution that assembles a small machine code program. All the code does is output a "set regspec=" string to standard out followed by a loop that reads standard input and appends it to the set with the "\" characters doubled. Programming it wasn't that difficult, even for a PC-assembler newbe like me.

The registry file needed to set comspec when Win95Cmd runs, thus allowing pipes to work, looks like...

--------- cut -----------------
REGEDIT4

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"AutoRun"="set comspec=c:\\batch\\Win95Cmd.exe"

--------- stop cutting --------

The extra line at the end is important. You really don't need a batch to do this, just copy the above to a text file, edit the path to point to your Win95Cmd.exe, rename to something.reg and double-click. But in the interest of extreme batch programming (and because I like to click on icons that just do it) here's a batch that searches for the Win95Cmd executable and sets the registry entry according to its location. DEBUG is required, and if Win95Cmd is not found in a path directory, deep searching is limited to the C: drive. Edit the batch code to specify another drive to search, or if your DIR command does list directories like Directory of C:\ETC\Whatever.

:: FIXCMD.BAT - adds registry entry that fixes Win95Cmd's pipes.
:: When run, searches hard-drive for Win95Cmd.exe, starting with
:: the path first. Uses the first copy found and creates and enters
:: a registry entry that sets comspec to Win95Cmd whenever it runs.
:: This batch was written October 3, 2002 by Terry Newton.
:: Current dir must be writeable. Requires DEBUG.
::
:: Win95Cmd is a port of Win 2000's command processor and can
:: be downloaded from: http://www.neuro.gatech.edu/users/cwilson/
:: cygutils/consize/Win95Cmd.exe (url wrapped). Pipes do not work
:: unless the comspec evar is set to the exe while it is running.
:: Thanks to Charles Dye for figuring this out!
::
@echo off
if .%1==.Goto %1 %2
%comspec% /e:32768 /c %0 Goto Shell
goto Done
:Shell
:: --- Adjust below as needed ---
:: set drive=drive to search if not on path...
set drive=C:
:: set dir=1st word output by DIR for directory... case matters
:: (a batch file with this basename will be created)
set dir=Directory
:: set dn=%%word-1 containing actual directory, 3rd word is %%2
set dn=%%2
:: set ba=base name for temps...
set ba=$$temp$$
:: ------------------------------
md %ba%
cd %ba%
echo Searching for Win95Cmd.exe on path...
for %%a in (CmdSpec regspec) do set %%a=
%0 Goto SearchPath %path%
:SearchPath
if .%3==. goto SearchHD
if exist %3\Win95Cmd.exe set CmdSpec=%3\Win95Cmd.exe
if exist %3Win95Cmd.exe set CmdSpec=%3Win95Cmd.exe
if not .%CmdSpec%==. goto Found
shift
goto SearchPath
:SearchHD
echo Searching drive %drive%... (may take a few minutes)
:: create a temp batch containing: Directory of [actual dir]
dir %drive%\Win95Cmd.exe /s | find "%dir%" > %ba%.bat
:: create a Directory.bat that extracts CmdSpec
echo> %dir%.bat set CmdSpec=%dn%Win95Cmd.exe
echo>>%dir%.bat if exist %%CmdSpec%% goto end
echo>>%dir%.bat set CmdSpec=%dn%
echo>>%dir%.bat :loop
echo>>%dir%.bat shift
echo>>%dir%.bat if .%dn%==. goto finish
echo>>%dir%.bat set CmdSpec=%%CmdSpec%% %dn%
echo>>%dir%.bat goto loop
echo>>%dir%.bat :finish
echo>>%dir%.bat set CmdSpec=%%CmdSpec%%\Win95Cmd.exe
echo>>%dir%.bat if not exist "%%CmdSpec%%" set CmdSpec=
echo>>%dir%.bat :end
:: try to set CmdSpec...
call %ba%.bat
del %ba%.bat
del %dir%.bat
if not .%CmdSpec%==. goto Found
echo Sorry, Win95Cmd.exe was not found.
goto Backout
:Found
echo Found %CmdSpec%
echo Creating registry entry...
:: this is tricky.. in filespecs \ must be replaced with \\
:: debug assembler that doubles all \ chars...
for %%a in (scr reg) do if exist %ba%.%%a del %ba%.%%a
>>%ba%.scr for %%a in (a100 CALL120) do echo %%a
>>%ba%.scr echo MOVAH,8
>>%ba%.scr echo INT21
>>%ba%.scr echo MOVDL,AL
>>%ba%.scr echo MOVAH,2
>>%ba%.scr echo CMPDL,5C
>>%ba%.scr for %%a in (JNZ112 INT21 INT21) do echo %%a
>>%ba%.scr echo MOVAH,B
>>%ba%.scr echo INT21
>>%ba%.scr echo CMPAL,0
>>%ba%.scr for %%a in (JZ11E JMP103 INT20) do echo %%a
>>%ba%.scr echo MOVDX,128
>>%ba%.scr echo MOVAH,9
>>%ba%.scr for %%a in (.INT21 .RET .) do echo%%a
>>%ba%.scr echo e128'set regspec=$'
>>%ba%.scr echo n %ba%.com
>>%ba%.scr for %%a in (rcx 35 w q) do echo %%a
debug<%ba%.scr>nul
echo %CmdSpec%|%ba%.com>%ba%.bat
call %ba%.bat
if .%regspec%==. echo DEBUG missing? something didn't work.
if .%regspec%==. goto Backout
set key=[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
>>%ba%.reg for %%a in (.REGEDIT4 .) do echo%%a
>>%ba%.reg echo %key%
>>%ba%.reg echo "AutoRun"="set comspec=%regspec%"
>>%ba%.reg echo.
start /wait regedit.exe /s %ba%.reg
for %%a in (scr com bat reg) do del %ba%.%%a
echo Done.
:Backout
cd..
rd %ba%
:Done