Run .exe after taking PATH C++ - c++

Can you help me? I need to run a file type of .exe. I have got two test1.txt and test2.txt files and in those files there are two PATHes to pr1.exe and pr2.exe. But in the first txt file I run pr1.exe and pr2.exe , in another one there are pr2.exe and pr1.exe .
#include <iostream>
#include <fstream>
#include <process.h>
using namespace std;
int main(int argc, char *argv[]) {
cout << "argc = " << argc << endl;
for (int i = 0; i < argc; i++) {
cout << "Argument: " << i << " = " << argv[i] << endl;
}
if (argc != 2) {
cout << "Error" << endl;
exit(-1);
}
char ch;
ifstream infile;
infile.open(argv[1]);
if (!infile) {
cout << "errrrror: cant open a file" << argv[1];
exit(-1);
}
while (infile) {
infile.get(ch);
cout << ch;
}
cout << endl;
system("pause");
return 0;
}
For example: I write path of the test1.txt and it prints two PATHes of pr1.exe and pr2.exe it's like:
"C:\Users\N\Desktop\process\The 2d file\Debug\The 2d file.exe"
"C:\Users\N\Desktop\process\the 1st file\Debug\the 1st file.exe"
Can you advice me how I should run them?

What you're looking for is the CreateProcess function, more info can be found on msdn:
// start the program up
#include "windows.h"
std::wstring("pr1.exe");
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if(!CreateProcess(NULL, (LPWSTR)wstr.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
//error
}
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
Note: If you're not sending any command line paramaters with your program, you could also swap the first and second argument.

Related

WaitForSingleObject with FindFirstChangeNotification not behaving as expected [duplicate]

This question already has answers here:
FindFirstChangeNotification is notifying about changes twice
(2 answers)
Closed 1 year ago.
I have to find out if there is a new file in a directory on Windows. Following this MSDN example (Obtaining Directory Change Notifications), I came up with the following test program:
#include <iostream>
#include <Windows.h>
#include <vector>
#include <string>
std::string FindNewFile(std::vector<std::string>& vsNewFileList, std::vector<std::string>& vsOldFileList)
{
std::string sNewFileName;
int nScore = 0;
for (auto& newFile : vsNewFileList)
{
nScore = 0;
for (auto& oldFile : vsOldFileList)
if(!newFile.compare(oldFile))
nScore++;
if (nScore!=1)
{
sNewFileName = newFile;
break;
}
}
return sNewFileName;
}
void GetCurrentFilesInDir(std::string sDir, std::vector<std::string>& vsFileList)
{
WIN32_FIND_DATA ffd;
sDir += "\\*";
std::wstring wStr = std::wstring(sDir.begin(), sDir.end());
LPCWSTR lpcwsDir = (LPCWSTR)wStr.c_str();
HANDLE hFind = FindFirstFile(lpcwsDir, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
std::cout << "Nope\n";
return;
}
vsFileList.clear();
do
{
int nSize = WideCharToMultiByte(CP_ACP, 0, ffd.cFileName, -1, 0, 0, 0, 0);
char* pcStr = new char[nSize];
WideCharToMultiByte(CP_ACP, 0, ffd.cFileName, -1, pcStr, nSize, 0, 0);
//std::cout << pcStr << "\n";
vsFileList.push_back(std::string(pcStr));
delete[] pcStr;
} while (FindNextFile(hFind, &ffd) != 0);
}
int main()
{
// watch the foo directory for new files
std::string sDir = "C:\\foo";
std::vector<std::string> vsOldFileList, vsNewFileList;
GetCurrentFilesInDir(sDir, vsOldFileList);
std::wstring wStr = std::wstring(sDir.begin(), sDir.end());
LPCWSTR lpcwsDir = (LPCWSTR)wStr.c_str();
DWORD dwWaitStatus;
HANDLE dwChangeHandle;
dwChangeHandle = FindFirstChangeNotification(
lpcwsDir,
FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME);
while (TRUE)
{
// returns multiple times before and after new file appears!!
dwWaitStatus = WaitForSingleObject(dwChangeHandle, INFINITE);
switch(dwWaitStatus)
{
case WAIT_OBJECT_0:
GetCurrentFilesInDir(sDir, vsNewFileList);
std::string sNewFileName = FindNewFile(vsNewFileList, vsOldFileList);
std::cout << sNewFileName << "\n";
GetCurrentFilesInDir(sDir, vsOldFileList);
FindNextChangeNotification(dwChangeHandle);
break;
}
}
}
The problem is that, when I save a new file in C:\foo (for instance, using Notepad++ to "Save As" an open .txt file in C:\foo), the call to WaitForSingleObject() in the while loop will return 0 multiple times. Since my FindNewFile() method returns an empty string if there is no new file in the directory, I will get output like:
a.txt
or:
b.txt
Or even:
c.txt
c.txt
Can someone explain what I am missing here?
Using FindNextChangeNotification can not tell you what actually happened, and the operation of the file may involve multiple changes.
You can try to use ReadDirectoryChangesW and here is a sample:
#include <windows.h>
#include <iostream>
using namespace std;
wstring getname(FILE_NOTIFY_INFORMATION* tmp)
{
wstring s = L"";
for (int i = 0; i < tmp->FileNameLength / 2; i++)
s += tmp->FileName[i];
return s;
}
int main(int argc, const char* argv[])
{
HANDLE hDir;
char notify[1024];
DWORD cbBytes;
LPTSTR path;
FILE_NOTIFY_INFORMATION* pnotify = (FILE_NOTIFY_INFORMATION*)notify;
FILE_NOTIFY_INFORMATION* tmp;
// GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));
path = (LPTSTR)L"D:\\test";
hDir = CreateFile(path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED, NULL);
wcout << L"===CreateFile complete===" << endl;
if (hDir == INVALID_HANDLE_VALUE)
{
wcout << L"invalid handle value" << endl;
return -1;
}
FILE_NOTIFY_INFORMATION buffer[1024];
FILE_NOTIFY_INFORMATION* pbuffer;
while (TRUE)
{
wcout << L"waiting..." << endl;
WaitForSingleObject(hDir, INFINITE);
if (ReadDirectoryChangesW(hDir, &buffer, sizeof(buffer),
TRUE, FILE_NOTIFY_CHANGE_FILE_NAME,
&cbBytes, NULL, NULL))
{
pbuffer = buffer;
do {
tmp = pbuffer;
switch (tmp->Action)
{
case FILE_ACTION_ADDED:
wcout << L"Directory/File added - " << getname(tmp) << endl;
break;
case FILE_ACTION_REMOVED:
wcout << L"Directory/File removed - " << getname(tmp) << endl;
break;
case FILE_ACTION_MODIFIED:
wcout << L"Directory/File modfied - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_OLD_NAME:
wcout << L"Directory/File old name - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
wcout << L"Directory/File new name - " << getname(tmp) << endl;
break;
default:
wcout << L"unknown action\n" << endl;
break;
}
pbuffer += pbuffer->NextEntryOffset;
} while (pbuffer->NextEntryOffset);
}
else
{
wcout << "readChangesW failed now return" << endl;
return -1;
}
}
}
When you do the Save As operation, you will find:
Therefore, multiple file operations were triggered when actually saving as, and you also performed multiple comparisons when processing new file comparisons, so empty characters were output.
More reference: FindFirstChangeNotification is notifying about changes twice

CreateProcess stdout with CreateNamedPipe Overlapped

I'm trying to read the std output of an external process (pgdump ) that I started with CreateProcess. I got this working with anonymous pipes but then the output is blocked and no like when I execute it via the commandline( missing end output). I have read numerous posts and discovered that I need CreateNamedPipes with WaitForSingleObject but I can't seem to get it to work. This is my working code with anonymous pipe but blocked and I'm missing the end of the output
#include <QDebug>
#include <QString>
#include <windows.h>
#include <sstream>
#include <iostream>
#include <random>
int main()
{
#define BUFFERSIZE 256
std::string program = "\"C:\\Program Files (x86)\\PostgreSQL\\10\\bin\\pg_dump.exe\"" +
std::string( " --dbname=postgresql://postgresUser:PostGresql13#127.0.0.1:5432/employee -j1 -Fd -b -v -f "
"C:\\development\\myproject\\Build\\debug\\1-export.psql");
HANDLE hReadStdOut = NULL;
HANDLE hWriteStdOut = NULL;
SECURITY_ATTRIBUTES saAttr;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory( &saAttr, sizeof( SECURITY_ATTRIBUTES ));
ZeroMemory( &piProcInfo, sizeof( PROCESS_INFORMATION ));
ZeroMemory( &siStartInfo, sizeof( STARTUPINFO ));
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
OVERLAPPED sOverlap;
if( !CreatePipe(&hReadStdOut, &hWriteStdOut, &saAttr, 0) )
{
std::ostringstream os;
os << GetLastError();
qDebug() << "create pipe error : " << QString::fromStdString( os.str());
}
TCHAR* szCmdline = new TCHAR[ program.size() + 1];
szCmdline[ program.size()] = 0;
std::copy( program.begin(), program.end(), szCmdline );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hWriteStdOut;
siStartInfo.hStdOutput = hWriteStdOut;
siStartInfo.hStdInput = NULL;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
BOOL bSuccess = CreateProcess( NULL, szCmdline, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo,&piProcInfo );
if ( ! bSuccess )
{
std::ostringstream os;
os << GetLastError();
qDebug() << "create process error : " << QString::fromStdString( os.str());
}
else
{
CloseHandle( hWriteStdOut );
DWORD err;
DWORD nBytesRead;
char buf[BUFFERSIZE + 1];
int i(1);
for(;;)
{
std::cout << "iteration " << std::to_string( i ) << std::endl;
if( !ReadFile( hReadStdOut, buf, sizeof( buf), &nBytesRead, NULL) || !nBytesRead )
{}
if( GetLastError() == ERROR_SUCCESS )
{
}
std::cout.flush();
buf[nBytesRead] = '\0';
std::string string_ = buf;
std::cout << string_ << std::endl;
std::size_t found = string_.find("contents of");
if( !nBytesRead )
break;
i++;
}
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
}
return 0;
}
For example, if your pg_dump.exe just write one line to standard output. There are several ways:
std::cout << "Hello World!\n";
printf("Hello World!\n");
std::cout << "Hello World!\n"<< std::endl;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello World!\n", 14, &dwWritten, NULL);
If the pg_dump.exe exit after write the line, the ReadFile will not blocked and return with the line "Hello World!".
However, if the pg_dump.exe doesn't exit after write the line and continue other work. The first two write ways (1., 2.) will result in ReadFile blocked. But if you use the third or fourth way the ReadFile will block and return with the line "Hello World!".
What's the difference here is the first two write ways (std::cout << "Hello World!\n"; and printf("Hello World!\n");) has no flush operation at end of write but the third or fourth way has. std::endl and WriteFile flush the output buffer.
Summary:
Flush the output to cause it to be written to the underlying stream (which may be a file, a terminal or a pipe). Standard output is flushed at the following conditions:
When the program ends normally.
Use std::endl at the end.
Use WriteFile.
You can check if it is your case.

CreateProcess and redirecting output

There are 2 apps.
AppCMD is a command line app and AppMAIN starts AppCMD with some command line args.
Unfortunately AppMAIN does not seem to handle the output off AppCMD very well and something is going wrong.
I'd like to log the calls to AppCMD and its output to see what is going on.
In order to do so I want to replace AppCMD with another binary AppWRAP that forwards the calls to a renamed AppCMD and logs it's output.
AppWRAP should act like a transparent Man-In-The-Middle.
For testing purposes I wrote a simple AppCMD that just outputs it's command line args:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
cout << "#### Hello, I'm the test binary that wants to be wrapped." << endl;
if (argc < 2) {
cout << "#### There where no command line arguments." << endl;
}
else {
cout << "#### These are my command line arguments:";
for (int i = 1; i < argc; ++i) cout << " " << argv[i];
cout << endl;
}
cout << "#### That's pretty much everything I do ... yet ;)" << endl;
return 0;
}
I followed MSDN: Creating a Child Process with Redirected Input and Output to implement AppWrap but I got stuck since it does not return and I cant figure out why:
#include <iostream>
#include <sstream>
#include <Windows.h>
using namespace std;
const string TARGET_BINARY("TestBinary.exe");
const size_t BUFFSIZE = 4096;
HANDLE in_read = 0;
HANDLE in_write = 0;
HANDLE out_read = 0;
HANDLE out_write = 0;
int main(int argc, char *argv[])
{
stringstream call;
cout << "Hello, I'm BinTheMiddle." << endl;
//-------------------------- CREATE COMMAND LINE CALL --------------------------
call << TARGET_BINARY;
for (int i = 1; i < argc; ++i) {
call << " " << argv[i];
}
cout << "Attempting to call '" << call.str() << "'" << endl;
//------------------------------ ARRANGE IO PIPES ------------------------------
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(SECURITY_ATTRIBUTES);
security.bInheritHandle = NULL;
security.bInheritHandle = TRUE;
security.lpSecurityDescriptor = NULL;
if (!CreatePipe(&out_read, &out_write, &security, 0)) {
cout << "Error: StdoutRd CreatePipe" << endl;
return -1;
}
if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
cout << "Stdout SetHandleInformation" << endl;
return -2;
}
if (!CreatePipe(&in_read, &in_write, &security, 0)) {
cout << "Stdin CreatePipe" << endl;
return -3;
}
if (!SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0)) {
cout << "Stdin SetHandleInformation" << endl;
return -4;
}
//------------------------------ START TARGET APP ------------------------------
STARTUPINFO start;
PROCESS_INFORMATION proc;
ZeroMemory(&start, sizeof(start));
start.cb = sizeof(start);
start.hStdError = out_write;
start.hStdOutput = out_write;
start.hStdInput = in_read;
start.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&proc, sizeof(proc));
// Start the child process.
if (!CreateProcess(NULL, (LPSTR) call.str().c_str(), NULL, NULL, TRUE,
0, NULL, NULL, &start, &proc))
{
cout << "CreateProcess failed (" << GetLastError() << ")" << endl;
return -1;
}
// Wait until child process exits.
WaitForSingleObject(proc.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(proc.hProcess);
CloseHandle(proc.hThread);
//----------------------------------- OUTPUT -----------------------------------
DWORD dwRead;
CHAR chBuf[127];
while (ReadFile(out_read, chBuf, 127, &dwRead, NULL)) {
cout << "Wrapped: " << chBuf << endl;
}
return 0;
}
It seems like it is waiting for ReadFile to return. Can anybody spot what I'm doing wrong?
I call the binary this way:
> shell_cmd_wrapper.exe param1 param2
This is the console output but the binary does not return.
Hello, I'm BinTheMiddle.
Attempting to call 'TestBinary.exe param1 param2'
Wrapped:#### Hello, I'm the test binary that wants to be wrapped.
#### These are my command line arguments: param1 param2
#### That'sD
Wrapped: pretty much everything I do ... yet ;)
s to be wrapped.
#### These are my command line arguments: param1 param2
#### That'sD
(Please ignore that I don't clear the buffer)
Close the out_write and in_read handles after calling CreateProcess. Otherwise ReadFile on out_read will block when the pipe is empty because there's still a potential writer even after the child has exited -- the out_write handle in the current process.
Also, as noted by Harry Johnston in a comment, waiting for the process to exit before reading from the pipe can potentially cause a deadlock. The child will block on WriteFile if the pipe fills up.

std::getline breaks if stdin is replaced by pipe of another process

I have a simple example program that reads from std::cin and writes to std::cout. It works fine if run in cmd.exe or the visual studio debugger. The code (server.cpp):
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
int main(int argc, char* argv[])
{
std::string input;
while (std::getline(std::cin, input))
{
if (input == "dog")
{
std::cout << "cat" << std::endl;
}
else if (input == "white")
{
std::cout << "black" << std::endl;
}
else if (input == "quit")
{
std::cout << "exiting" << std::endl;
return 0;
}
else if (input != "")
{
std::cout << "unknown" << std::endl;
}
}
std::cout << "error" << std::endl;
}
Now I want to run this from another process that writes to its stdin and reads from its stdout. I create two pipes and start a process using CreateProcess with the read handle of one pipe as StdInput handle and the write handle of the other pipe as Stdouput handle. The Code (client.cpp):
#include <Windows.h>
#include <cassert>
#include <iostream>
#include <ostream>
#include <string>
namespace
{
class Server
{
public:
Server() :
m_pi()
{
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES)};
sa.bInheritHandle = TRUE;
assert(CreatePipe(&m_ro, &m_wo, &sa, 0));
assert(SetHandleInformation(m_ro, HANDLE_FLAG_INHERIT, 0));
assert(CreatePipe(&m_ri, &m_wi, &sa, 0));
assert(SetHandleInformation(m_ri, HANDLE_FLAG_INHERIT, 0));
STARTUPINFO si = {sizeof(STARTUPINFO)};
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = m_ri;
si.hStdOutput = m_wo;
assert(CreateProcess(L"..\\Debug\\server.exe", 0, 0, 0, 1, 0, 0, 0, &si, &m_pi));
}
~Server()
{
execute("quit\n");
assert(WaitForSingleObject(m_pi.hProcess, INFINITE) != WAIT_FAILED);
assert(CloseHandle(m_pi.hThread));
assert(CloseHandle(m_pi.hProcess));
assert(CloseHandle(m_wi));
assert(CloseHandle(m_ri));
assert(CloseHandle(m_wo));
assert(CloseHandle(m_ro));
}
std::string execute(std::string const& cmd)
{
DWORD num_bytes;
assert(WriteFile(m_wi, cmd.c_str(), (DWORD)cmd.size(), &num_bytes, 0));
std::string output;
DWORD n = 0;
while (n == 0)
{
Sleep(0);
assert(PeekNamedPipe(m_ro, 0, 0, 0, &n, 0));
if (n > 0)
{
output.resize(n);
assert(ReadFile(m_ro, &output[0], n, &num_bytes, 0));
}
}
return output;
}
private:
HANDLE m_wo, m_ro, m_wi, m_ri;
PROCESS_INFORMATION m_pi;
};
Server g_server;
}
int main(int argc, char* argv[])
{
std::cout << g_server.execute("white\n") << std::endl;
std::cout << g_server.execute("foobar\n") << std::endl;
std::cout << g_server.execute("dog\n") << std::endl;
}
The problem is that the client only receives the massage "error", so the std::cin of the server seems to be broken.
My question is, what did I do wrong?
You're disabling inheritance for the handle that the child will use to read from stdin - the child needs to inherit that handle. Instead of:
SetHandleInformation(m_ri, HANDLE_FLAG_INHERIT, 0);
Try the following to disable inheritance on the handle that the server process will use to write to the child's stdin:
SetHandleInformation(m_wi, HANDLE_FLAG_INHERIT, 0);

Open and close application using c++ on windows

I want to make a program that opens a windows explorer window, waits for 5 seconds, and then closes the window. I've tried the following:
#include "stdafx.h"
#include <windows.h>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
void _tmain( int argc, TCHAR *argv[] ) {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 ) {
cout << "Usage: " << argv[0] << "<path>";
return;
}
// Build the command string.
wstring app = L"explorer.exe ";
wstring str_command = app + argv[1];
wchar_t* command = const_cast<wchar_t*>( str_command.c_str() );
// Open the window.
if( !CreateProcess( NULL, // No module name (use command line)
command, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
) {
cout << "CreateProcess failed: " << GetLastError();
return;
}
cout << "Opened window!" << endl;
// Wait for it.
Sleep(5000);
cout << "Done waiting. Closing... ";
// Close explorer.
HANDLE explorer = OpenProcess(PROCESS_TERMINATE, false, pi.dwProcessId);
if( !explorer ) {
cout << "OpenProcess failed: " << GetLastError();
return;
}
if( !TerminateProcess( explorer, 0 ) ) {
cout << "TerminateProcess failed: " << GetLastError();
return;
}
// Close process and thread handles.
CloseHandle( explorer );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
cout << "Done.";
}
I get it to open well enough, but I can't get it to close. TerminateProcess fails with error code 5. I've also tried posting a WM_CLOSE message to the window. I get a success value out of that, but the window stays open.
Please help!
I found this thread:
Close all browser windows?
It says:
Use the InternetExplorer object to open each window and invoke the Quit method when done. This has the added benefit of closing only the windows you opened (so that windows opened by the user or other applications are unaffected).
https://msdn.microsoft.com/library/aa752127.aspx
I know that this does not help much (missing snippets), but at least something.