C++ open a file with 2 constraints - c++

In c++ I want to open my text file with notepad, BUT:
Not to stop the program or wait to close the notepad...
Not to create a console/cmd tab (I'am using Visual studio 2017, windows)
Is it possible ?
I have this :
_popen("notepad.exe C:\X\X\X.txt", "r");
but it open a cmd tab.

(Windows only solution)
By modifying the example: https://learn.microsoft.com/en-us/windows/win32/procthread/creating-processes
for C++:
#include <iostream>
#include <Windows.h>
int main(int argc, char* argv[])
{
if (argc != 2)
{
std::cout << "Usage: " << argv[0] << " [cmdline]\n";
return EXIT_FAILURE;
}
STARTUPINFOA si = {sizeof(si)};
PROCESS_INFORMATION pi = {};
// Start the child process.
if (!CreateProcessA(nullptr, // No module name (use command line)
argv[1], // Command line
nullptr, // Process handle not inheritable
nullptr, // Thread handle not inheritable
false, // Set handle inheritance to FALSE
0, // No creation flags
nullptr, // Use parent's environment block
nullptr, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi)) // Pointer to PROCESS_INFORMATION structure
{
std::cout << "CreateProcess failed (" << GetLastError() << ").\n";
return EXIT_FAILURE;
}
// Wait until child process exits.
//WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return EXIT_SUCCESS;
}

Related

How to get the returned exit value of an invoked program to store it internally? [duplicate]

This question already has an answer here:
checking the return value of a command executed using CreateProcess
(1 answer)
Closed 2 years ago.
This question is related to a previously asked question found here:
I'm able to invoke another executable within my runProgram() function. However, before this runProgram() function returns back to main() and closes the handle for the process. I need to retrieve the value that the executable returns when it exits...
Here is my current application:
#include <Windows.h>
#include <exception>
#include <stdio.h>
#include <tchar.h>
#include <cstdint>
#include <iostream>
uint32_t runProgram(LPCSTR lpApplicationName) {
STARTUPINFOA si;
PROCESS_INFORMATION pi;
// Set the size of the structures
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Run the program
CreateProcessA(
lpApplicationName, // the path
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // Opens file in seperate console
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure
);
uint32_t error = GetLastError();
if ( error != 0)
std::cerr << error << "\n";
// How to retrieve and store the result from the exiting program above...?
uint32_t cache_size = 0;
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return cache_size;
}
int main() {
try {
const uint32_t cache_size = runProgram("CacheQuerry.exe");
std::cout << cache_size << '\n';
}
catch (const std::exception& e) {
std::cerr << e.what() << "\n\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
And I want to store the return value from this executable into runProgram()'s local variable: cache_size.
Here is the main.cpp from the invoked program:
#include "CacheQuerry.h"
int main() {
int error = cache_info();
if (error != 0)
std::cout << error << '\n';
else
std::cout << '\n';
std::cout << "l1d_cache_size = " << l1d_cache_size() << std::endl;
std::cout << "cache line size = " << cache_line_size() << '\n';
return l1d_cache_size();
}
The invoked program will return the value produced by l1d_cache_size() when this program exits. This is the value that I want to store within runProgram()'s cache_size variable. How do I get this return value after the program exits? The implementation of the function call found in "CacheQuerry.h" shouldn't be relevant here, but if you need to see it's implementation don't hesitate to ask. These are two separate projects within the same solution. The 1st main.cpp which is in its own project relies on the 2nd main.cpp within its own project.
You can get it by calling GetExitCodeProcess (pi.hProcess), after waiting on the handle but before you close it.
The exact code you need is:
DWORD exit_code;
BOOL ok = GetExitCodeProcess (pi.hProcess, &exit_code);
Strange this is not mentioned in the Remarks section for CreateProcess at all.

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.

Exceptions constantly thrown when launching app with my custom WINAPI Debugger

I'm in the process of experimenting with creating my own custom debugger with C++ in Visual Studio 2017. Testing a few console applications it is fine. However when I launch notepad with it, it is OK until I hit File -> Open dialog and it goes into constant loop with output these two exceptions code and the open dialog box doesn't open:
Exception: 3221356611
Exception: 998
When same process was launched under WinDbg these exceptions didn't occur.
The code is compiled as x86 and launching 32-bit process on Windows 10 1803 build 17134.523 x64.
Any suggestions on what might cause these?
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <iostream>
#include <map>
std::map < LPVOID, std::wstring > DllNameMap;
int main()
{
std::wstring filename(L"c:\\windows\\syswow64\\notepad.exe");
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
DEBUG_EVENT debugEvent;
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
(LPWSTR)filename.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_SUSPENDED, // 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
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return -1;
}
if (DebugActiveProcess(pi.dwProcessId))
{
ResumeThread(pi.hThread);
std::cout << "Debugger attached!" << std::endl;
EnterDebugLoop(&debugEvent,pi.hProcess);
}
return 0;
}
void EnterDebugLoop(const LPDEBUG_EVENT DebugEv,HANDLE hProcess)
{
DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation
for (;;)
{
// Wait for a debugging event to occur. The second parameter indicates
// that the function does not return until a debugging event occurs.
WaitForDebugEvent(DebugEv, INFINITE);
// Process the debugging event code.
switch (DebugEv->dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
// Process the exception code. When handling
// exceptions, remember to set the continuation
// status parameter (dwContinueStatus). This value
// is used by the ContinueDebugEvent function.
std::cout << "Exception: " << DebugEv->u.Exception.ExceptionRecord.ExceptionCode << std::endl;
switch (DebugEv->u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
std::cout << "ACCESS VIOLATION" << std::endl;
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_BREAKPOINT:
std::cout << "BREAKPOINT" << std::endl;
// First chance: Display the current
// instruction and register values.
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
std::cout << "DATATYPE MISALIGNMENT" << std::endl;
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_SINGLE_STEP:
std::cout << "SINGLE STEP" << std::endl;
// First chance: Update the display of the
// current instruction and register values.
break;
case DBG_CONTROL_C:
std::cout << "CTRL+C" << std::endl;
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
default:
// Handle other exceptions.
break;
}
break;
case CREATE_THREAD_DEBUG_EVENT:
std::cout << "Create Thread" << std::endl;
// As needed, examine or change the thread's registers
// with the GetThreadContext and SetThreadContext functions;
// and suspend and resume thread execution with the
// SuspendThread and ResumeThread functions.
break;
case CREATE_PROCESS_DEBUG_EVENT:
std::cout << "Create Process" << std::endl;
// As needed, examine or change the registers of the
// process's initial thread with the GetThreadContext and
// SetThreadContext functions; read from and write to the
// process's virtual memory with the ReadProcessMemory and
// WriteProcessMemory functions; and suspend and resume
// thread execution with the SuspendThread and ResumeThread
// functions. Be sure to close the handle to the process image
// file with CloseHandle.
//dwContinueStatus = OnCreateProcessDebugEvent(DebugEv);
break;
case EXIT_THREAD_DEBUG_EVENT:
// Display the thread's exit code.
std::cout << "Exit Thread Exit Code " << DebugEv->u.ExitThread.dwExitCode << std::endl;
//dwContinueStatus = OnExitThreadDebugEvent(DebugEv);
break;
case EXIT_PROCESS_DEBUG_EVENT:
// Display the process's exit code.
std::cout << "Exit process Exit Code " << DebugEv->u.ExitProcess.dwExitCode << std::endl;
///dwContinueStatus = OnExitProcessDebugEvent(DebugEv);
break;
case LOAD_DLL_DEBUG_EVENT:
{
PVOID pDllPath = NULL;
PUCHAR DllPath[(MAX_PATH + 1) * sizeof(WCHAR)];
DWORD dwLen = 0;
ZeroMemory(DllPath, sizeof(DllPath));
if (DebugEv->u.LoadDll.lpImageName == NULL)
{
break;
}
// read DLL name pointer value
if (ReadProcessMemory(
hProcess,
DebugEv->u.LoadDll.lpImageName,
&pDllPath, sizeof(PVOID),
&dwLen) && pDllPath)
{
dwLen = (DebugEv->u.LoadDll.fUnicode ? MAX_PATH * sizeof(WCHAR) : MAX_PATH);
// read DLL name
if (ReadProcessMemory(
hProcess,
pDllPath,
DllPath, dwLen,
&dwLen))
{
char szDllPath[MAX_PATH], *lpszDllName = NULL;
if (DebugEv->u.LoadDll.fUnicode)
{
std::wstring path((wchar_t*)DllPath);
DllNameMap.insert(std::make_pair(DebugEv->u.LoadDll.lpBaseOfDll, path));
std::wcout << "Image loaded (Unicode): " << path.c_str() << std::endl;
}
else
{
// todo: Add to DllNameMAp
std::wcout << "Image loaded: " << DllPath << std::endl;
}
}
else
{
std::cout << "Error processing memory : " << GetLastError() << std::endl;
}
}
else
{
std::wcout << "ERROR reading process memory : " << GetLastError() << std::endl;
}
}
// Read the debugging information included in the newly
// loaded DLL. Be sure to close the handle to the loaded DLL
// with CloseHandle.
///dwContinueStatus = OnLoadDllDebugEvent(DebugEv);
break;
case UNLOAD_DLL_DEBUG_EVENT:
std::wcout << "Unload DLL: " << DllNameMap[DebugEv->u.UnloadDll.lpBaseOfDll] << std::endl;
break;
case OUTPUT_DEBUG_STRING_EVENT:
// Display the output debugging string.
std::wcout << "Debug Event" << std::endl;
if (DebugEv->u.DebugString.fUnicode)
{
std::wcout << (wchar_t)DebugEv->u.DebugString.lpDebugStringData << std::endl;
}
//dwContinueStatus = OnOutputDebugStringEvent(DebugEv);
break;
case RIP_EVENT:
//dwContinueStatus = OnRipEvent(DebugEv);
break;
}
// Resume executing the thread that reported the debugging event.
ContinueDebugEvent(DebugEv->dwProcessId,
DebugEv->dwThreadId,
dwContinueStatus);
}
}
3221356611 this is 0xC0020043 - RPC_NT_INTERNAL_ERROR
998 this is 0x3e6 - ERROR_NOACCESS (Invalid access to memory
location)
your main error that you unconditionally return DBG_CONTINUE always. but on EXCEPTION_DEBUG_EVENT you mast return this code only if you handle exception. otherwise (and if dwFirstChance == TRUE so this is first chance exception) you must return DBG_EXCEPTION_NOT_HANDLED. if you return DBG_CONTINUE - the program begin continue execute from current context. if you return DBG_EXCEPTION_NOT_HANDLED - the KiUserExceptionDispatcher will be called in target process, which call RtlDispatchException and where will be called exception handlers. read more - Structured Exception Handling
but because you never return DBG_EXCEPTION_NOT_HANDLED - program exception handlers never called. by your 2 exceptions codes even easy locate place, where this happens:
the RpcpRaiseException is called, which internal call RaiseException(ERROR_NOACCESS..) so you view 998 exception. if you return DBG_EXCEPTION_NOT_HANDLED here - application byself handle this exception and never return from RaiseException call. context will be swithched to __except{} block. but because you return DBG_CONTINUE - the RaiseException return control and RpcReportFatalError called, which internal call RaiseException(RPC_NT_INTERNAL_ERROR..) so you and view 3221356611 (0xC0020043)
your next error that you not close hFile on LOAD_DLL_DEBUG_EVENT - When the debugger is finished with this file, it should close the handle using the CloseHandle function. the same error on CREATE_PROCESS_DEBUG_EVENT
also your error in how you begin debug process - you must not use CREATE_SUSPENDED flag, must not use DebugActiveProcess and ResumeThread. you need only set DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS and all. not need create process in suspended state and main not call DebugActiveProcess here. this api call is bad designed, it create additional thread in target process. for say xp at this stage this at all was fatal.

Sending Message to other process

for (int i = 0; i < n; i++)
{
const char* cstr = strings[i].c_str();
swprintf_s(fullCommandLine, L"\"%s\" \"%s\" %S", pathToModule, pathToFile, cstr);
if(CreateProcess(NULL,
(LPWSTR)fullCommandLine,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi))
{
cout << "succes";
}
else cout << "fail";
}
I'm creating n procesess to find string in given file like this, and In my module(wchich looks for given string in file) I want to send messages to other n-1 processes to quit
while (file >> readout)
{
if (readout == search)
{
cout << "I found string";
SendMessage(/*what should be here*/);
}
}
From where I could get handles to those other processes?
Please see my PostThreadMessage to Console Application.
I created that because it certainly is possible to send a message to a console program, we just must make a message loop, just as it is possible to show a window from a console program.
Note that PostThreadMessage needs a thread id, not a process id. Every process also has a thread id and a process's thread id is in the PROCESS_INFORMATION from CreateProcess.
The following is a larger example but easier to use for demonstrating that PostThreadMessage works in console programs. This program will call itself (passing its thread id) if there is no argument for it then it will wait for the new process to send messages. If there is an argument then it will assume the argument is a thread id and send a message to that thread followed by a WM_QUIT.
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szCmdline[300];
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = NULL;
siStartInfo.hStdOutput = NULL;
siStartInfo.hStdInput = NULL;
DWORD dwThread;
MSG Msg;
TCHAR ThreadIdBuffer[40];
// if no argument then execute ourself then wait for a message from that thread
if (argc == 1) {
_itot_s(GetCurrentThreadId(), ThreadIdBuffer, 40, 10);
szCmdline[0] = '"';
szCmdline[1] = 0;
_tcscat_s(szCmdline, 300, argv[0]); // ourself
int n = _tcslen(szCmdline);
szCmdline[n++] = '"';
szCmdline[n++] = ' ';
szCmdline[n++] = 0;
_tcscat_s(szCmdline, 300, ThreadIdBuffer); // our thread id
bSuccess = CreateProcess(argv[0], // execute ourself
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (!bSuccess) {
std::cout << "Process not started\n";
return 0;
}
std::cout << "Waiting\n";
// Now wait for the other process to send us a message
while (GetMessage(&Msg, NULL, 0, WM_USER)) {
if (Msg.message == WM_COMMAND)
std::cout << "WM_COMMAND\n";
else
std::cout << "Message: " << Msg.message << '\n';
}
std::cout << "End of message loop\n";
return 0;
}
// if there is an argument then assume it is a threadid of another one of us
std::cout << "Press Enter to send the message\n";
if (std::wcin.get() != '\n')
return 0;
dwThread = _wtoi(argv[1]);
if (!PostThreadMessage(dwThread, WM_COMMAND, (WPARAM)0, (LPARAM)0))
std::cout << GetLastError() << " PostThreadMessage error\n";
if (!PostThreadMessage(dwThread, WM_QUIT, (WPARAM)0, (LPARAM)0))
std::cout << GetLastError() << " PostThreadMessage error\n";
return 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.