Running command-line commands in the background without opening a window - c++

I'm running some command line script to encrypt a file using AxCrypt software.
My code compiles and runs fine, but when I check the file afterward, it has not been encrypted.
Here is the code:
LPCWSTR loc = L"C:\\\\Axantum\\\\AxCrypt\\\\AxCrypt";
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (CreateProcessW(loc, const_cast<LPWSTR>(master), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
The master variable contains the commands, loc contains the location of the AxCrypt program.
LPCWSTR axLocation = L" C:\\\\Axantum\\\\AxCrypt\\\\AxCrypt ";
LPCWSTR flags = L" -b 2 -e -k ";
LPCWSTR passcode = L" \"***************\" ";
LPCWSTR command = L" -z ";
LPCWSTR imagelocation = L"%pathName";
std::wstring mast = std::wstring(axLocation) + flags + passcode + command + imagelocation;
LPCWSTR master = mast.c_str();

LPCWSTR loc = L"C:\\\\Axantum\\\\AxCrypt\\\\AxCrypt";
This is wrong. You have too many slashes in your literal. It needs to be this instead:
LPCWSTR loc = L"C:\\Axantum\\AxCrypt\\AxCrypt";
Same goes with axLocation.
Also, you have unnecessary spaces in your various substrings. Ultimately, you are creating this master command line, from the interpreter's perspective:
C:\\Axantum\\AxCrypt\\AxCrypt -b 2 -e -k "***************" -z %pathName
When it should look more like this:
C:\Axantum\AxCrypt\AxCrypt -b 2 -e -k "***************" -z %pathName
Try something more like this instead:
LPCWSTR axLocation = L"C:\\Axantum\\AxCrypt\\AxCrypt";
LPCWSTR flags = L"-b 2 -e -k";
LPCWSTR passcode = L"***************";
LPCWSTR command = L"-z";
LPCWSTR imagelocation = L"%pathName";
WCHAR master[STRSAFE_MAX_CCH];
StringCchPrintfW(master, STRSAFE_MAX_CCH, L"\"%s\" %s \"%s\" %s %s", axLocation, flags, passcode, command, imagelocation);
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (CreateProcessW(axLocation, master, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Lastly, %pathname looks suspicious. Is that supposed to be specified as-is like that? Or is it supposed to be an environment variable instead? If the latter, you are missing a percent sign:
%pathname%
CreateProcess() does not interpret environment variables, so if you need to pass such a variable then you would have to either:
resolve the variable yourself using ExpandEnvironmentStrings() before calling CreateProcess().
have CreateProcess() launch cmd.exe /C and let it interpret environment variables for you, eg:
StringCchPrintfW(master, STRSAFE_MAX_CCH, L"cmd /C \"%s\" %s \"%s\" %s %s", axLocation, flags, passcode, command, imagelocation);

Related

CreateProcess returns true but does not execute with regedit

I am trying to dump a portion of the windows registry in a .txt file using the CreateProcess function. The code is along the lines of
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
CString cmdLine = "\"C:\\WINDOWS\\regedit.exe\" /e \"c:\\dump\\TestReg.txt\"
\"HKEY_LOCAL_MACHINE\\SOFTWARE\\MYSOFT\\\"";
LPSTR pCmdLine = (LPSTR)(const char*)cmdLine;
BOOL oc = CreateProcess(NULL, pCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if(oc == TRUE)
{
WaitForSingleObject(pi.hProcess, 1000);
GetExitCodeProcess(pi.hProcess, &exitCode);
if(exitCode != 0) ret = -1;
}
What I know
The CreateProcess returns TRUE and the last blocks executes
The process waits for the end and exits normally
However no file is produced at the end
The command line string works fine in command line, even when it operates from the same directory where the program is operating.
I have found something that is potentially useful where someone had basically the same problem. In the end it resulted in a dependency clash but the link does not explain very well how it was detected or fixed.

How to execute a command in cmd using CreateProcess?

I'm trying to launch the command line through my c++ program and then have cmd run a command. I'm not sure what I'm doing wrong. I've looked at the MSDN documentation but I'm unable to understand what to change in my code.
Below is the chunk of code that I have written. I'm trying to launch cmd and then run the command in cmdArgs. However, on running the program it just launches the cmd without running the nslookup part of it. I've tried with other commands as well like ipconfig, but they do not get executed. Could someone help me understand what I'm doing wrong.
When I launch the program, it just opens up cmd. What I'm trying to do is have the cmdArgs runs and view the output on the cmd screen.
I'm new to c++, so if this is trivial I apologize. I've looked at other questions on the site, but it seems that the format of cmdArgs is correct - program name followed by the arg.
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
LPTSTR cmdPath = _T("C:\\Windows\\System32\\cmd.exe");
LPTSTR cmdArgs = _T("C:\\Windows\\System32\\cmd.exe nslookup myip.opendns.com. resolver1.opendns.com");
if (!CreateProcess(cmdPath, cmdArgs, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
std::cout << "Create Process failed: " << GetLastError() << std::endl;
return "Failed";
}
Your program does exactly what you asked it to to: you just start the cmd.exe executable. Just test in a console windows:
C:\Users\xxx>start /w cmd ipconfig
C:\Users\xxx>cmd ipconfig
Microsoft Windows [version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. Tous droits réservés.
C:\Users\xxx>exit
C:\Users\xxx>
So cmd.exe ipconfig just pushed a new cmd.exe without executing the remaining of the line. It is then waiting for commands coming from its standard input.
You must use cmd.exe /c ipconfig to ask the new cmd.exe to execute a command, or cmd.exe /K ipconfig if you want cmd not to exit after first command:
C:\Users\serge.ballesta>cmd /c ipconfig
Configuration IP de Windows
...
So you should write in your code:
...
LPTSTR cmdArgs = _T("C:\\Windows\\System32\\cmd.exe /k nslookup myip.opendns.com. resolver1.opendns.com");
...
Try using this:
wchar_t command[] = L"nslookup myip.opendns.com. resolver1.opendns.com";
wchar_t cmd[MAX_PATH] ;
wchar_t cmdline[ MAX_PATH + 50 ];
swprintf_s( cmdline, L"%s /c %s", cmd, command );
STARTUPINFOW startInf;
memset( &startInf, 0, sizeof startInf );
startInf.cb = sizeof(startInf);
PROCESS_INFORMATION procInf;
memset( &procInf, 0, sizeof procInf );
BOOL b = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &startInf, &procInf );
DWORD dwErr = 0;
if( b )
{
// Wait till process completes
WaitForSingleObject( procInf.hProcess, INFINITE );
// Check process’s exit code
GetExitCodeProcess( procInf.hProcess, &dwErr );
// Avoid memory leak by closing process handle
CloseHandle( procInf.hProcess );
}
else
{
dwErr = GetLastError();
}
if( dwErr )
{
wprintf(_T(“Command failed. Error %d\n”),dwErr);
}

How to use CreateProcess or ShellExecute to execute piped commands

I want to execute a few commands piped without new cmd opened (so I can't just use system())
This is the command I try to execute:
C:\\openssl.exe enc -aes-128-ofb -d -in C:\\encrypted.bin -iv a2b050be9463 -K 6ba62eb7bb2ccace -nopad | C:\\\\mplayer.exe -"
This is what I tried :
WCHAR prog[] = L"C:\\openssl.exe";
WCHAR args[] = L"enc -aes-128-ofb -d -in C:\\encrypted.bin -iv a2b050be9463 -K 6ba62eb7bb2ccace -nopad | C:\\mplayer.exe -";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcess(prog, args, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
And it didn't work (There is no error, its just not opening)
I also tried this:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
HINSTANCE hinstRun1 = ShellExecute(NULL, L"open", L"cmd.exe", str2.c_str(), L"", SW_HIDE);
CoUninitialize();
//str2 == C:\\openssl.exe enc -aes-128-ofb -d -in C:\\encrypted.bin -iv a2b050be9463 -K 6ba62eb7bb2ccace -nopad | C:\\\\mplayer.exe -")
This is also not working (Again there is no error, its just not opening)
When I tried it like this :
system(("cmd.exe /c " str2).c_str());
Everything works good (Except the part that its opened also a cmd window.)
How can I execute this line from c/c++ program without new cmd window?
If you want to be in control of everything, you need to create both processes (openssl and mplayer) yourself. So that would be two CreateProcess calls. Of course, then, you have to create the redirection yourself, as well, and this is done using CreatePipe, before creating the processes.
Here is an example (haven't compiled it, may require some tuning):
HANDLE proc1_out;
HANDLE proc2_in;
SECURITY_ATTRIBUTES security_attributes;
// create the pipe between the processes
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attributes.bInheritHandle = TRUE; // pipe handles should be inheritable by sub-processes
security_attributes.lpSecurityDescriptor = NULL;
CreatePipe(&proc2_in, &proc1_out, &security_attributes, 0);
// create the first process
WCHAR proc1_app[] = L"C:\\openssl.exe";
WCHAR proc1_cmd_line[] = L"openssl enc -aes-128-ofb -d -in C:\\encrypted.bin -iv a2b050be9463 -K 6ba62eb7bb2ccace -nopad";
PROCESS_INFORMATION proc1_info;
STARTUPINFO proc1_startup_info;
ZeroMemory(&proc1_info, sizeof(PROCESS_INFORMATION));
ZeroMemory(&proc1_startup_info, sizeof(STARTUPINFO));
proc1_startup_info.cb = sizeof(STARTUPINFO);
proc1_startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
proc1_startup_info.hStdOutput = child_output_write; // redirected output
proc1_startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
proc1_startup_info.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(proc1_app, proc1_cmd_line, NULL, NULL, TRUE, 0, NULL, NULL, &proc1_startup_info, &proc1_info);
// create the second process
WCHAR proc2_app[] = L"C:\\mplayer.exe";
WCHAR proc2_cmd_line[] = L"mplayer -";
PROCESS_INFORMATION proc2_info;
STARTUPINFO proc2_startup_info;
ZeroMemory(&proc2_info, sizeof(PROCESS_INFORMATION));
ZeroMemory(&proc2_startup_info, sizeof(STARTUPINFO));
proc2_startup_info.cb = sizeof(STARTUPINFO);
proc2_startup_info.hStdInput = proc2_in; // redirected input
proc2_startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
proc2_startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
proc2_startup_info.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(proc2_app, proc2_cmd_line, NULL, NULL, TRUE, 0, NULL, NULL, &proc2_startup_info, &proc2_info);
Notes: in the command line argument passed to CreateProcess, the first "word" in the string must be the process name (this was not what you were doing).

C++ CreateProcess - System Error #2 can't find file - what is wrong with my file path?

I am trying to open a PDF via Firefox with CreateProcess(), I am a beginner and know nothing about using CreateProcess, but in my last question someone pointed out the MSDN on it... it shows that:
To run a batch file, you must start the command interpreter;
set lpApplicationName to cmd.exe and set lpCommandLine to the
following arguments: /c plus the name of the batch file.
Therefore I created a batch file that runs perfectly fine with the system() command, there are no problems with the batch file.
I can't figure out why the system can't find the file and I don't know if its the batch file, the exe in the batch file, the PDF doc in the batch file or the location of cmd.exe... Any help is greatly appreciated...
void openPDF(char scansQueue[][MAX_NAME], int index)
{
// build batch file
char openPath[300];
char procCommand[MAX_NAME]="C:\\firefox";
char cmdEXE[MAX_NAME]="C:\\Windows\\System32\\cmd.exe";
fstream outfile;
outfile.open("C:\\firefox.bat");
copyCString(openPath,"\"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe\"");
outfile << openPath;
outfile << ' ';
copyCString(openPath,"\"C:\\Scans\\");
catArray(openPath,scansQueue[index]);
catArray(openPath,"\"");
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
cout<<"PROCESS ATTEMPT"<<endl;
if(!CreateProcess((LPCTSTR)cmdEXE ,(LPWSTR)procCommand, NULL, NULL, false, 0, NULL, NULL, &si, &pi))cout << GetLastError();cout<<"PROCESS FAILED TO EXECUTE!!!";
}
This assumes the whole batch file thing is part of an XY problem, in that you don't really need to make a batch file, you really just want to launch Firefox with a command line parameter.
I also assume you don't really need to pass the whole array of filenames with an index for which to use, instead you should just pass the filename by itself as I did where I called the function.
#include <Windows.h>
#include <stdio.h>
void MsgBoxLastError()
{
LPWSTR lpMsgBuf = NULL;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpMsgBuf,
0, NULL ) != 0)
{
MessageBox(NULL, lpMsgBuf, L"Error", MB_OK);
}
LocalFree(lpMsgBuf);
}
void OpenWithFirefox(const char* Filename)
{
const WCHAR pathToFirefox[] = L"C:/Program Files (x86)/Mozilla Firefox/firefox.exe";
const WCHAR scanPrefix[] = L"file://C:/Scans/";
WCHAR fullCommandLine[MAX_PATH] = {0};
//Build full command line
swprintf_s(fullCommandLine, L"\"%s\" \"%s%S\"", pathToFirefox, scanPrefix, Filename);
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
BOOL success = CreateProcess(NULL, fullCommandLine, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
if(success)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
{
MsgBoxLastError();
}
}
int main()
{
const int MAX_NAME = 13;
char scansQueue[][MAX_NAME] =
{
"file1.pdf",
"file2.pdf"
};
for(int i = 0; i < 2; ++i)
{
OpenWithFirefox(scansQueue[i]);
}
return 0;
}

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.