Jump to content
  • Advertisement
Sign in to follow this  
piejacked

Running a DOS program... secretly!

This topic is 4907 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm writing a Windows front end for an old DOS program, but I still want to use the old DOS program underneath the front end. I can't modify the DOS program itself; I don't have the source code and have very little understanding of how it works. The DOS program requires user input on the cmd line. I'm using a script to run the DOS program from my MFC code and automatically enter specific key presses, depending on what the user selected on the front end window. The thing is, whenever I run the DOS executable an ugly command prompt appears in the foreground. It would be nice to have the DOS prompt hidden while my script automates the key presses, so that all the user sees is an hourglass in front of the main window. There must be a way to do this. I really, really can't touch the DOS program code, or else I'd just transplant it into my MFC code.

Share this post


Link to post
Share on other sites
Advertisement
you might be able to pull apart the open source "DosBox" program, but i don't know how much time that would take or if its worth it to you.

Share this post


Link to post
Share on other sites
Quote:
Original post by Malchivus
you might be able to pull apart the open source "DosBox" program, but i don't know how much time that would take or if its worth it to you.

It might be. I'll look it up on Google, thanks.

Share this post


Link to post
Share on other sites
Not my code, but the site that hosts it appears to be down. Redirecting console program (DOS or WIN32) input/output is relatively common (google for console redirection or something similar) and is just a matter of manually creating the process, while specifying your own input/output streams (instead of screen/keyboard)


#include "stdafx.h"

DWORD main( int argc, char *argv[ ] )
{
HANDLE hSTDOUT = INVALID_HANDLE_VALUE;
HANDLE hFile = INVALID_HANDLE_VALUE;

HANDLE hChildSTDOUTRead = INVALID_HANDLE_VALUE;
HANDLE hChildSTDOUTWrite = INVALID_HANDLE_VALUE;
HANDLE hChildSTDOUTReadDuplicate = INVALID_HANDLE_VALUE;

/*
Step 1. Save the handle to the current STDOUT
We'll need it again later.
*/

hSTDOUT = ::GetStdHandle( STD_OUTPUT_HANDLE );

/*
Step 2. Create a pipe that gets the child process' STDOUT
*/


// Set the bInheritHandle flag so pipe handles are inherited
// if the pipe handles aren't inherited they can't be used
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength = sizeof( SECURITY_ATTRIBUTES );
SecurityAttributes.bInheritHandle = TRUE;
SecurityAttributes.lpSecurityDescriptor = NULL;

if( !::CreatePipe( &hChildSTDOUTRead, &hChildSTDOUTWrite, &SecurityAttributes, 0 ) )
return 0;

/*
Step 3. Set a write handle to the pipe to be STDOUT.
now if we do ::printf( ) or any other output to STDOUT
it will get re-directed to the pipe instead of the console.
Any child process we create gets this "new" STDOUT.
*/

if( !::SetStdHandle( STD_OUTPUT_HANDLE, hChildSTDOUTWrite ) )
{
::CloseHandle( hChildSTDOUTRead );
::CloseHandle( hChildSTDOUTWrite );
return 0;
}

/*
Step 4. Since the child process doesn't need our pipe read handle,
because it won't read from it's STDOUT, we create noninheritable
read handle and close the inheritable read handle.
Also, the child process will close the STDOUT read/write handles
on it's own, so after we call ::CreateProcess( ) successfully we
can't use them again, thus the duplication.
*/


if( !::DuplicateHandle( ::GetCurrentProcess( ), hChildSTDOUTRead, ::GetCurrentProcess( ), &hChildSTDOUTReadDuplicate, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
{
::CloseHandle( hChildSTDOUTRead );
::CloseHandle( hChildSTDOUTWrite );
return 0;
}
::CloseHandle( hChildSTDOUTRead );

/*
Step 5. Start the child process
*/

PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;

::memset( &siStartInfo, 0, sizeof( STARTUPINFO ) );
siStartInfo.cb = sizeof( STARTUPINFO );

if( !::CreateProcess( NULL, "c:\\batch\\GetNameAndAddress.exe www.BeginThread.com", NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo ) )
{
::CloseHandle( hChildSTDOUTRead );
::CloseHandle( hChildSTDOUTWrite );
::CloseHandle( hChildSTDOUTReadDuplicate );
return 0;
}

/*
Step 6. Restore our STDOUT
*/

if( !::SetStdHandle( STD_OUTPUT_HANDLE, hSTDOUT ) )
{
::CloseHandle( hChildSTDOUTRead );
::CloseHandle( hChildSTDOUTWrite );
::CloseHandle( hChildSTDOUTReadDuplicate );
return 0;
}

/*
Step 7. Open our file for saving the STDOUT of the child process
*/

if( argc 1 )
hFile = ::CreateFile( argv[ 1 ], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

if( hFile == INVALID_HANDLE_VALUE )
{
::CloseHandle( hChildSTDOUTWrite );
::CloseHandle( hChildSTDOUTReadDuplicate );
return 0;
}

/* Step 8. Close the write end of the pipe before reading from the
read end of the pipe.
*/

if( !::CloseHandle( hChildSTDOUTWrite ) )
{
::CloseHandle( hChildSTDOUTReadDuplicate );
::CloseHandle( hFile );
return 0;
}
hChildSTDOUTWrite = INVALID_HANDLE_VALUE;

/*
Step 9. Read from pipe that is the standard output for child process.
Save the output to the file
*/

DWORD dwRead;
DWORD dwWritten;
CHAR Buf[ 0x00001000 ];

while( ::ReadFile( hChildSTDOUTReadDuplicate, Buf, sizeof( Buf ), &dwRead, NULL ) && dwRead && ::WriteFile( hFile, Buf, dwRead, &dwWritten, NULL ) );

/*
Step 10. Clean everything up
*/

::CloseHandle( hFile );
::CloseHandle( hChildSTDOUTReadDuplicate );

return 1;
}




If you understand Delphi there are about a million different examples/tutorials/libraries for doing exactly what you are doing (creating a Windows front end/extension for a legacy command line program).

Share this post


Link to post
Share on other sites
I've recently done something similar, however I didn't support input to the console app, programming (this should be trivial).

Another question, have anyone found a way to capture conio output?
I.e, console programs that uses printf for output works fine (they use stdout).
If the programs are using cprintf instead the output is not redirected to stdout, thus my attempt to capture it will fail.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!