CreateProcess calling cmd.exe incl. arguments with no showing (flashing) window? - c++

The saga continues...
I've searched the web, i've searched on StackOverflow, i found many hope giving answers/solutions, but somehow they have all failed (up)on me (including the ones related to ShellExecute(Ex) ).
How to hide a (flashing) CMD window (incl. arguments) using CreateProcess??
I basically want to call/execute a set of conditional/native cmd.exe commands (i.e. FOR /F, and ||), but also an external command FIND(STR).exe. And this, without showing a (flashing) CMD window.
But even hiding something as simple as "cmd.exe /C ECHO ...flashing window is bad..." seems impossible to do.
The code i've tried (including many variations related to the dwFlags and wShowWindow flags
#include <windows.h>
int main()
{
char cmdline[] = "cmd.exe /c ECHO ...flashing window is bad...";
PROCESS_INFORMATION pi;
STARTUPINFO si;
// memset(&si,0,sizeof(STARTUPINFO));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// si.dwFlags = STARTF_USESTDHANDLES;
// si.dwFlags = CREATE_NO_WINDOW;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
// si.wShowWindow = CREATE_NO_WINDOW;
CreateProcess(NULL, (LPSTR) cmdline, NULL, NULL, 0, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
// ExitProcess;
return 0;
}
I don't want to rely on external programs i.e. .vbs (Windows Scripting Host) or shortcut tricks, but simply a standalone compiled .exe.
Is this (really) too much to ask, or am i doing it (completely) wrong?
Thanks...

Update: You also seem to confuse CreateProcess flags (its dwCreationFlags argument) with the member of STARTUPINFO structure. These are different flags, CREATE_NO_WINDOW should not be in STARTUPINFO.
You have to pass the CREATE_NO_WINDOW flag, then the console window won't show. Originally I've answered that you have to redirect the standard handles which is not correct (but still highly recommanded).
Set STARTF_USESTDHANDLES and fill in appropriate handles. If you are interested in the output of the process, create pipes, otherwise you can just open nul an pass that.

Try Using ProcessBuilder. Here is an example of some code that I have that seems to work just fine. In my code below, the shellScript is a StringBuilder that I am dynamically creating that contains the command and it's parameters that I want to execute.
String[] scriptArray = shellScript.toString().split(" ");
ProcessBuilder builder = new ProcessBuilder(scriptArray);
File outputFile = new File("/logs/AgentOutputLog.txt");
File errorFile = new File("/logs/AgentErrorLog.txt");
builder.redirectOutput(outputFile);
builder.redirectError(errorFile);
Process process = builder.start();
int errCode = process.waitFor();
//errCode = 0 means online
if(errCode == 0){
success = true;
break;
//errCode = 1 means offline
} else if (errCode == 1){
success = false;
break;
}

Related

trying to run commend on cmd throw c++ using createprocces (API)?

bool execute()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
bool flag = true;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
string f = "dir desktop"
if (CmdLine.parameter != "")
{
LPSTR l1 = const_cast<char *>(f.c_str());
CreateProcess(NULL, l1, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
flag = true;
// WaitForSingleObject(pi.hProcess, INFINITE);
// // Close process and thread handles.
// CloseHandle(pi.hProcess);
// CloseHandle(pi.hThread);
//}
}
return flag;
}
I'm trying to run cmd command by visual studio.
I'm using createprocces (API) in order to run this thing
but I can't understand why it doesn't run anything.
dir is a command understood by cmd.exe, it's not a program you can execute.
You can try the command cmd /k "dir desktop", properly expressed as a C++ string.
E.g.,
auto execute()
-> bool
{
STARTUPINFO si = { sizeof( si ) };
PROCESS_INFORMATION pi = {};
string f = "cmd /k \"dir desktop\"\0";
bool const ok = !!CreateProcess( 0, &f[0], 0, 0, false, 0, 0, 0, &si, &pi );
if( !ok ) { return false; }
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
Note how the calls to ZeroMemory have been replaced with C++ initialization.
Just by letting the compiler do its job you get shorter, more clear code that is more likely correct, and just as efficient (possibly more). Win win win.
Disclaimer: code not reviewed by compiler.
If the intent is to list the contents of the user's desktop folder, then note that dir desktop doesn't do that. As an interactive command in the command interpreter you could use dir %userprofile%\desktop, and that also works via the Windows Run-dialog. Depending on the command interpreter's behavior for command line arguments it may work directly via CreateProcess, or not.
Generally, when using Windows API level functions it's preferable to use the wchar_t-based text based functions, i.e. define UNICODE before including <windows.h> (or use the ...W functions explicitly).
If you call CreateProcess() with the first parameter set to NULL, then you have to make sure that l1 starts with the module name to call.
As dir is an internal command of the command processor and not an executable, you have to use cmd as module name and give the rest of the parameter as cmd expects them.
So try the following:
string f = "cmd /c=dir desktop";

How do I hide a command window and display all potential errors in an EditBox control?

I am creating simple application in Borland C++ Builder.
My code looks like this:
void __fastcall TForm1::Button3Click(TObject *Sender)
{
system("java -jar decompile.jar -o Source/ file.jar");
}
Now I want to hide the command window and show all potential errors in an EditBox control. The EditBox control should remain empty if there are no errors.
Edit1->Text= "ERROR";
use TMemo instead of TEdit box for log
It have multiple lines and support scrollbars. It is far better for logs.
see how to redirect commnd promt output to file
I do not use JAVA but you can try:
system("java -jar decompile.jar -o Source/ file.jar > errorlog.txt");
or:
system("java -jar decompile.jar -o Source/ file.jar >> errorlog.txt");
You can also include the application path
AnsiString exepath=ExtractFilePath(Application->ExeName);
So you save the file to known location nstead of actual path that could change easily during runtime...
see How can I run a windows batch file but hide the command window?
So you need to use CreateProcess with java.exe or command.com directly. I never done the hiding thing so follow the answer in the linked Q/A. If you do not know how to use CreateProcess (it can be overwhelming for beginers) then this is how I use it (it does not hide just starts an exe...)
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES attr0,attr1;
ZeroMemory(&si,sizeof(si));
ZeroMemory(&pi,sizeof(pi));
si.cb=sizeof(si);
attr0.nLength=sizeof(SECURITY_ATTRIBUTES);
attr0.bInheritHandle=TRUE;
attr0.lpSecurityDescriptor=NULL;
attr1=attr0;
CreateProcess(NULL,"some_app.exe > logfile.txt",&attr0,&attr1,TRUE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
And you can use:
TerminateProcess(pi.hProcess,0);
To force terminate the app ....
Now when I put all together I got this:
AnsiString s,logfile;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES attr0,attr1;
ZeroMemory(&si,sizeof(si));
ZeroMemory(&pi,sizeof(pi));
si.cb=sizeof(si);
// hide the process
si.wShowWindow=SW_HIDE;
si.dwFlags=STARTF_USESHOWWINDOW;
attr0.nLength=sizeof(SECURITY_ATTRIBUTES);
attr0.bInheritHandle=TRUE;
attr0.lpSecurityDescriptor=NULL;
attr1=attr0;
// Application local path log filename
logfile=ExtractFilePath(Application->ExeName)+"logfile.txt";
DeleteFileA(logfile); // delete old log just to be sure
// command line string to run (instead of "dir" use "java -jar decompile.jar -o Source/ file.jar")
s="cmd /c dir > \""+logfile+"\"";
CreateProcess(NULL,s.c_str(),&attr0,&attr1,TRUE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
// wait for execution with some timeout...
for (int i=0;i<100;i++)
{
if (FileExists(logfile)) break;
Sleep(100);
}
// copy the log into TMemo mm_log ...
if (FileExists(logfile)) mm_log->Lines->LoadFromFile(logfile); else mm_log->Text="No log file found";
Where mm_log is memo where I copy the log file. This example just run the dir command to show directory info... so instead use your JAVA ... as I suggested in rem. If you have older OS then instead of cmd use command. you can also use FileExists to determine which one is it ...
You need to use the Win32 CreateProcess() function instead of the C system() funtion. CreateProcess() allows you to redirect STDIN, STDOUT, and STDERR of the launched process.
Creating a Child Process with Redirected Input and Output
You can launch java.exe directly with the desired input parameters, redirecting its output using anonymous pipes created with CreatePipe(), and then read output from those pipe using ReadFile() until the process terminates. You can parse and display the output however you want.
As for hiding the command window, when calling CreateProcess(), you can either:
specify the CREATE_NO_WINDOW flag in the dwCreationFlags parameter of CreateProcess().
in the STARTUPINFO structure passed to the lpStartupInfo parameter of CreateProcess(), include the STARTF_USESHOWWINDOW flag in the STARTUPINFO::dwFlags field, and set the STARTUPINFO::wShowWindow field to SW_HIDE.
Try something like this:
HANDLE hStdErrRd = NULL;
HANDLE hStdErrWr = NULL;
SECURITY_ATTRIBUTES saAttr = {0};
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hStdErrRd, &hStdErrWr, &saAttr, 0)) {
// error handling
}
if (!SetHandleInformation(hStdErrRd, HANDLE_FLAG_INHERIT, 0)) {
// error handling
}
String CmdLine = "\"C:\\path to\\java.exe\" -jar \"C:\\path to\\decompile.jar\" -o Source/ \"C:\\path to\\file.jar\"";
STARTUPINFO si = {0};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = hStdErrWr;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi = {0};
if (CreateProcess(NULL, CmdLine.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
// must close our handle to the write-side of the pipe so the pipe will close
// when the child process terminates so ReadFile() will know to stop expecting data...
CloseHandle(hStdErrWr);
AnsiString output;
char buffer[1024];
DWORD dwBytesRead;
while (ReadFile(hStdErrRd, buffer, sizeof(buffer), &dwBytesRead, NULL))
{
if (dwNumRead == 0)
break;
output += AnsiString(buffer, dwBytesRead);
do
{
int pos = output.Pos("\n");
if (pos == 0)
break;
Memo1->Lines->Add(output.SubString(1, pos-1).TrimRight());
output.Delete(1, pos);
}
while (!output.IsEmpty());
}
if (!output.IsEmpty())
Memo1->Lines->Add(output.TrimRight());
}
else
{
// error handling
CloseHandle(hStdErrWr);
}
CloseHandle(hStdErrRd);

Beginner C++ CreateProcess () Error 2

I am trying to create a process that send command to cmd.exe and receive Error 2,
Why? It's posible? How?
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
String pathexe = "C:\Windows\system32\cmd.exe";
String command= "notepad.exe";
if(!CreateProcess(
pathexe.c_str(), // lpApplicationName
command.c_str(), // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
FALSE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
))
{
AnsiString error = GetLastError();
ShowMessage("Error: " + error);
}
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
PD: 1) It is assumed that you can use CreateProcess () for this purpose, I should not do it with ShellExecute () or system().
2) I have read about it in the forum and can not find a solution to this error, there are many answers to similar questions but do not address the error, other functions are proposed, or mix with the route command.
3) I do not think that issue permits because I built while the manifest.
4) I currently use C ++ Builder, in win7, 32bits but not important.
5) I guess the issue will be voted as negative and duplicate (as usual) but the proposed testing examples also receive errors.
Thanks to all
FIRST CONCLUSIONS:
Error 2: The system cannot find the file specified.
Link funtion: https://msdn.microsoft.com/es-es/library/windows/desktop/ms679360(v=vs.85).aspx
Link error: https://msdn.microsoft.com/es-es/library/windows/desktop/ms681382(v=vs.85).aspx
With error 2: check syntax, file path and existence.
works:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
String command = "notepad.exe";
if(!CreateProcess(
NULL, // lpApplicationName
commmand.c_str(), // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
FALSE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
))
{
AnsiString error = GetLastError();
ShowMessage("Error: " + error);
}
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
This example works also for exe
String command = "cd C:\\sample\\calc.exe";
But no with cmd´s general commands, there must be a way to send commands to cmd as:
notepad.exe && cd C:\sample\ && sample1.txt
THANKS TO ALL
You're trying to run this command:
cmd notepad
(You aren't doing that quite right, either; the lpCommandLine argument should include the entire string, not just notepad, and you haven't quoted the backslashes properly.)
But even once you fix those problems, it won't work, because you've got the syntax wrong. You'll find it won't work if typed on the command line either!
Instead, try:
String pathexe = "C:\\Windows\\system32\\cmd.exe";
String command= "cmd /c notepad.exe";
The /c option means "run this command". You can use /k instead if you want the command window to stay open after the command has finished, though it's unusual for a program to do so.
One final note: I'm assuming here than notepad is just a stand-in for a more complicated command. If you actually want to run notepad, or any other executable, you shouldn't be invoking cmd.exe at all:
String command= "notepad";
if(!CreateProcess(
NULL, // lpApplicationName
command.c_str(), // lpCommandLine
...
You only need to call on cmd.exe if you need to run a built-in command, or a composite command line.
(Actually, calling cmd.exe is considered poor practice even in those cases; in Windows, you are generally expected do that sort of thing for yourself via the API rather than farming out the job to the command interpreter. But there are edge cases, and your mileage may vary.)

How to redirect in, out and err streams from process created with CreateProcess function? [duplicate]

I tried using CreateProcess to run a simple command like hg > test.txt. I tried running the string as a whole (as opposed to separating it into an application name and its parameters). Why does CreateProcess(0, "notepad.exe test.txt", ...) work but CreateProcess(0, "hg > test.txt", ...) does not?
The code below creates a console-less process with stdout and stderr redirected to the specified file.
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE h = CreateFile(_T("out.log"),
FILE_APPEND_DATA,
FILE_SHARE_WRITE | FILE_SHARE_READ,
&sa,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL ret = FALSE;
DWORD flags = CREATE_NO_WINDOW;
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = NULL;
si.hStdError = h;
si.hStdOutput = h;
TCHAR cmd[]= TEXT("Test.exe 30");
ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
if ( ret )
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
return -1;
}
You can't use stdout redirection in the command line passed to CreateProcess. To redirect stdout you need to specify a file handle for the output in the STARTUPINFO structure.
You are also making another, more subtle, mistake. The second parameter, lpCommandLine must point to writeable memory because CreateProcess overwrites the buffer. If you happen to be using the ANSI version of the function then you will get away with this, but not for the Unicode version.
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
Microsoft has an example how to redirect the standard output:
http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx.
CreateProcess() launches processes, it is not a command line itnerpreter. It doesn't know what ">" is and won't do the stream redirection for you. You need to open the file test.txt yourself and pass the handle to it to CreateProcess inside the STARTUPINFO structure:
CreateProcess
STARTUPINFO
you should run process cmd.exe with params "/c command line".
This will redirect the output to a file or to organize a pipeline through CreateProcess.

TerminateProcess() doesn't close the application

I am trying to use the TerminateProcess to terminate an app launched by ShellExecuteEX like this:
SHELLEXECUTEINFO ExecuteInfo;
ExecuteInfo.fMask = SEE_MASK_FLAG_NO_UI; /* Odd but true */
ExecuteInfo.hwnd = NULL;
ExecuteInfo.cbSize = sizeof(ExecuteInfo);
ExecuteInfo.lpVerb = NULL;
ExecuteInfo.lpFile = "http://www.microsoft.com";
ExecuteInfo.lpParameters = "";
ExecuteInfo.lpDirectory = NULL;
ExecuteInfo.nShow = SW_SHOW;;
ShellExecuteEx(&ExecuteInfo);
//WaitForSingleObject(ExecuteInfo.hProcess, 0);
Sleep(4000);
TerminateProcess(ExecuteInfo.hProcess, 0);
IE gets opened but it never closes. Am I doing something wrong?
According to MSDN, fMask must be set to SEE_MASK_NOCLOSEPROCESS for .hProcess to get set. I would add a test to see if it is NULL. As a side note I've always had better luck using CreateProcess.
Edit:
This is how you do it using CreateProcess:
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
CreateProcess( NULL,
"C:\\Program Files\\Internet Explorer\\iexplore.exe http://www.google.com/",
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi );
Sleep(4000);
TerminateProcess(pi.hProcess, 0);
You should add error-checking and could query the path of the default browser using: AssocQueryString like this:
AssocQueryString(0,ASSOCSTR_EXECUTABLE,"http","open", szExe, &cchExe);
You can get more information by checking the returned hProcess (e.g., in a debugger). Also make sure you have the SEE_MASK_NOCLOSEPROCESS flag set.
But my psychic powers say: Opening an IE document doesn't necessarily create a new process. And, if it does, it may not be the one you think it is: The process you may have created may have spawned yet another process to actually host the document. Raymond Chen mentions that about halfway down this blog post.