Johannes Klauß
Johannes Klauß

Reputation: 11020

open cmd and read and write into it

I need to start a process that starts the commandline (it should not pop up, so something like a background process).

Then I need to write stuff to it and periodically read the last line of the cmd.

Since my C++ skills aren't that great I don't know how to achieve this.

In a pseudocode way I thought about something like this:

startProcess();
writeToCmd();
readFromCmd() { // Call that every given interval (e.g. 1000 ms)
    if(returnValue >= 100) {
        stopProcess();
    }
}

I'm pretty sure it'll not be that easy. It would be really great if someone can help me out here. The programm is for windows.

Edit after the suggestions: This is what I've done so far (I did it a little bit different.)

int errorCode;

// Variables for CreateProcess()
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;
PHANDLE hInRead, hInWrite;
LPDWORD bytesWritten, bytesRead;

// The CommandLine input
TCHAR tcsCommandLine[] = _T("cmd /c format H: /fs:FAT32 /V:device");
//TCHAR tcsCommandLine[] = _T("cmd /c start D:\\foo.txt");

sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW; // SW_HIDE FOR PRODUCTION
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = hInRead;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

ZeroMemory(&pi, sizeof(pi));

errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);

info = GetDriveInfo(m_wsNANDMountPoint);

if(info.m_uSizeInMB > 2048) {
    log("Wrong Mounting Point. Device has more than 2GB space.");

    return false;
}
else {
    // Start Formatting
    if(!CreateProcess(NULL, tcsCommandLine,
        NULL, NULL,
        TRUE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL, NULL,
        &si,
        &pi)) {

        log("CreateProcess failed. Could not format Drive");
        return false;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    WriteFile(hInWrite, "#13#10'J'#13#10", 5, bytesWritten, NULL);
    CloseHandle(hInWrite);

    // Wait until child process exits
    WaitForSingleObject(pi.hProcess, 1100);
}

return true;

After a little bit of debugging, I recognized that the code doesn't break at ZeroMemory(), but on

errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);

with an Access violation writing location error. I have no idea what I'm doing wrong. It would be really great if you guys could help me out.

Upvotes: 0

Views: 7367

Answers (3)

Software_Designer
Software_Designer

Reputation: 8587

Let me add this to these excellent answers:

This great link demonstrates console read and write : http://www.adrianxw.dk/SoftwareSite/Consoles/Consoles2.html

To do stuff periodically, use SetTimer(). http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

The SetTimer function executes a function every x milliseconds. Example: The following console program works like this: It sets a timer using SetTimer then loops in a message loop. The message loop receives and processes WM_TIMER messages and the timer callback also is called for each time interval. Simply put the stuff you want done in the TimerProc() function.

#define STRICT 1 
#include <windows.h>
#include <iostream.h>

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) 
{
   //put the stuff you want done in here

  cout << "Doing stuff Time: " << dwTime << '\n';
  cout << "--------------------------------------------------\n" ;
  cout.flush();
}

int main(int argc, char *argv[], char *envp[]) 
{
    int Counter=0;
    int usage_Time_millisec=1000;
    MSG Msg;

    UINT TimerId = SetTimer(NULL, 0, usage_Time_millisec, &TimerProc); //bind TimerProc() to SetTimer() 

    cout << "TimerId: " << TimerId << '\n';

   if (!TimerId) return 16;

   while (GetMessage(&Msg, NULL, 0, 0)) 
   {
        ++Counter;
        if (Msg.message == WM_TIMER)
        cout << "Doing stuff Counter: " << Counter << "; timer message\n";
        else
        cout << "Doing stuff Counter: " << Counter << "; message: " << Msg.message << '\n';
        DispatchMessage(&Msg);
   }

   KillTimer(NULL, TimerId);

return 0;

}

Upvotes: -1

Mike Kwan
Mike Kwan

Reputation: 24447

What you need to do in this instance is to create a console with a hidden window. If you use CreateProcess to launch the console, you should be able to set the visibility of the window through the STARTUPINFO structure.

The next step is to redirect the input and output of your console. You can do this by attaching the 3 console handles (input, output, error) to pipes and reading that from your parent process. This MSDN article describes how to do exactly this.

Upvotes: 2

Shahbaz
Shahbaz

Reputation: 47493

The command line consists of two parts you would be interested in.

  1. A place to execute programs
  2. A buffer for whatever is written on the screen

Since you don't need the screen to be visible, then you need these two things in your program. So from here on, forget about cmd.

To execute programs in your program, you have many ways. If you want the execution lines to look exactly the way you write it in cmd, you can use system (although Windows versions of fork/exec make more sense). For example:

system("my_prog.exe --option file.txt");

Which executes my_prog.exe with --option and file.txt as arguments.

Now the second one, you said you wanted to read the last line from cmd. The idea to realize this is to have the output of everything in a file, instead of in cmd.

If you are only interested in the last line at every instance, you can redirect the output of your programs to a file like this:

system("my_prog.exe --option file.txt > output.txt");

or if you want to keep the whole history, you can append instead of overwrite:

system("my_prog.exe --option file.txt >> output.txt");

If you also want to redirect stderr, you can write:

system("my_prog.exe --option file.txt &> output.txt");

The notation may be linuxy, try it in your windows see if it works (manually in a normal cmd). You could also search google for "shell redirect" and you get a lot of results.

Anyway, if you want the last line of cmd to also include the command itself, you can overwrite/append the command line to that particular yourself in the program.

Upvotes: 1

Related Questions