Reputation: 11020
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
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
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
Reputation: 47493
The command line consists of two parts you would be interested in.
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