I have a working command-line application that uses the Windows API to create a child process in a new console window. I am using the CREATE_NEW_CONSOLE flag but I need a way to keep that newly opened window from closing when the new process exits.
Here's the existing code:
STARTUPINFO si;
LPCTSTR lpAppName = "\\\\fs\\storage\\QA\\Mason\\psexec\\PSExec.exe";
string lpstr = "\\\\fs\\storage\\QA\\Mason\\psexec\\PSExec.exe \\\\" + target + " /accepteula -u user -p pass -s -realtime \\\\fs\\storage\\QA\\Mason\\psexec\\RI.bat";
LPTSTR lpCmd = CA2T(lpstr.c_str());
PROCESS_INFORMATION pi; // This structure has process id
DWORD exitCode = 9999; // Process exit code
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(lpAppName, // cmd.exe for running batch scripts
lpCmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // New Console Window 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() << endl;
getchar();
return -1;
}
// Wait until child process exits.
cout << "Waiting Installation processes to complete on " << target << endl;
DWORD result = WaitForSingleObject(pi.hProcess, INFINITE);
// Get Exit Code
if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {
cout << "GetErrorCodeProcess failed: " << GetLastError() << endl;
return -1;
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
How can I make the new console window remain open?
In this particular instance the easiest solution is to cheat, i.e.,
psexec -s \\target cmd /c "\\server\share\file.bat & pause"
You're already launching an instance of cmd.exe implicitly, to run the batch file, so this doesn't introduce any significant overhead.
For a more general solution, you would need to launch a proxy application (with CREATE_NEW_CONSOLE) that launches the target application (without CREATE_NEW_CONSOLE) and then waits. For bonus points, the proxy application would be the same as the parent application, just launched with a command-line flag that tells it what to do.
Related
std::cout << "starting valorant...";
system("d:");
system("cd" "Riot Games\\VALORANT\\live\\");
system("VALORANT.exe");
I need help opening an .exe with cmd (Valorant, in this case).
Results:
Each call to system() spawns a new instance of the shell processor (cmd.exe /c <parameters> on Windows). You can't use multiple calls to system() to issue multiple commands to a single shell instance, the way you are trying to do.
You should instead be using a single call to system() with the full path the .exe, eg:
std::cout << "starting valorant...";
system("\"d:\\Riot Games\\VALORANT\\live\\VALORANT.exe\"");
Alternatively, use an old DOS 8.3-style path (if enabled - use GetShortPathName() to get the actual path):
std::cout << "starting valorant...";
system("d:\\RiotGa~1\\VALORANT\\live\\VALORANT.exe");
Otherwise, you should use CreateProcess() instead of system():
std::cout << "starting valorant...";
STARTUPINFO si = {}
si.cb = sizeof(si);
// set other fields as needed...
PROCESS_INFORMATION pi = {};
if (CreateProcessA(NULL, "d:\\Riot Games\\VALORANT\\live\\VALORANT.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
// use pi as needed...
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
Here is what I tried :
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
cout << "Starting Notepad++..." << endl;
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInformation;
// set the size of the structures
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
ZeroMemory(&processInformation, sizeof(processInformation));
char commandLine[] = "C:\\Program Files\\Notepad++\\Notepad++.exe";
// start the program up
BOOL res = CreateProcess(NULL, // the path
commandLine, // 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
&startupInfo, // Pointer to STARTUPINFO structure
&processInformation // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
);
if (res) {
if (!(mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, processInformation.dwThreadId))) {
cout << "Failed to install mouse hook :" << endl << getLastErrorAsString() << endl;
}
WaitForSingleObject( processInformation.hProcess, INFINITE );
CloseHandle( processInformation.hProcess );
CloseHandle( processInformation.hThread );
} else {
cout << "Failed to start Notepad++" << endl;
}
return 0;
}
It starts Notepad++ successfully, but it fails to install the hook and GetLastError return the following error : The parameter is incorrect.. I have no idea which parameter is incorrect. However, the program finishes normally when I close Notepad++.
Since I start the process in the main program and the hook callback is also in the main program, I should be able to install a hook without doing any dll injection.
I haven't touched to c++ in years, and I've never been into system development, so I may be wrong in my way to do it, so can you explain to me where my error is ?
EDIT :
You're all telling me that I need to inject a dll to hook a specific process, but this is from the windows documentation of SetWindowsHookEx about the hMod parameter (3rd parameter):
A handle to the DLL containing the hook procedure pointed to by the
lpfn parameter. The hMod parameter must be set to NULL if the
dwThreadId parameter specifies a thread created by the current process
and if the hook procedure is within the code associated with the
current process.
My Thread has been created by the current process and my hook procedure is inside the code of my current process, so why it doesn't work when I'm using a not low-level hook (WH_MOUSE)?
Low-level hooks are executed, before the destination of the input has even been evaluated. That's the reason, why low-level hooks need to be global, as explained in the documentation for SetWindowsHookEx. You cannot pass a non-zero value for the dwThreadId parameter.
I have a problem that a process created inside of another one is left, when the parent one is killed with something like 'kill task'. More precisely, application launches general_service.exe. Inside of this service, I launch a new logger_runner.exe. When main application stops, it just kill general_service.exe, but in task manager I see my logger_runner.exe. When I stop general_service.exe in VS, it is left as well.
How to make my logger_runner depends on general_service ?
Thanks for the help!
This function starts my .exe
void startLogger(PROCESS_INFORMATION & processInformation) {
std::wstring commandLine = L"\"" + PathUtils::programFolder() + LR"(\logger_runner.exe)" + L"\"";
STARTUPINFOW startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
memset(&processInformation, 0, sizeof(processInformation));
wchar_t* commandLineCopy = _wcsdup(commandLine.c_str());
if (!CreateProcessW(NULL, // No module name (use command line)
commandLineCopy, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&startupInfo, // Pointer to STARTUPINFO structure
&processInformation) // Pointer to PROCESS_INFORMATION structure
)
{
free(commandLineCopy);
throw SystemException();
}
free(commandLineCopy);
}
This function should ends logger_runner.exe
void closeLogger(PROCESS_INFORMATION & processInformation) {
// Check exit code
DWORD exitCode = 0;
GetExitCodeProcess(processInformation.hProcess, &exitCode);
if (TerminateProcess(processInformation.hProcess, 0) == 0) {
std::cerr << "Could not terminate logger process\n";
}
// Close process and thread handles.
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
}
All these functions are called inside of the wrapper
class LoggerWrapper {
public:
LoggerWrapper() {
startLogger(m_processInformation);
};
~LoggerWrapper() {
closeLogger(m_processInformation);
}
private:
PROCESS_INFORMATION m_processInformation;
};
In wmain function of my general_service solution, I just call
LoggerWrapper logger
I am using this piece of code to launch a process from a GUI app. but, according to the notes of this code it is not possible to launch a process from a console app. actually i want to do that, I want a console app to launch another console process, please do you have any idea how to do that?
// This technique must be used for "console-less" parents such as GUI
// applications or detached applications.
// Using the STARTUPINFO STARTF_USESTDHANDLES flag, requires that
// the CreateProcess fInheritHandles parameter be set TRUE so that
// the file handles specified in the STARTUPINFO structure will be
// inherited by the child.
// setup the child process's handles for stdin, stdout, & stderr.
STARTUPINFO childProcStartupInfo;
memset( &childProcStartupInfo, 0, sizeof(childProcStartupInfo));
childProcStartupInfo.cb = sizeof(childProcStartupInfo);
childProcStartupInfo.hStdInput = hFromParent; // stdin
childProcStartupInfo.hStdOutput = hToParent; // stdout
childProcStartupInfo.hStdError = hToParentDup; // stderr
childProcStartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
childProcStartupInfo.wShowWindow = SW_HIDE;
// Now create the child process, inheriting handles
PROCESS_INFORMATION childProcInfo; /* for CreateProcess call */
bOk = CreateProcess(
NULL, // filename
pCmdLine, // full command line for child
NULL, // process security descriptor */
NULL, // thread security descriptor */
TRUE, // inherit handles? Also use if STARTF_USESTDHANDLES */
0, // creation flags */
NULL, // inherited environment address */
NULL, // startup dir; NULL = start in current */
&childProcStartupInfo, // pointer to startup info (input) */
&childProcInfo); // pointer to process info (output) */
did you try shellexecute? I think that works..
You can try:
ShellExecute(), ShellExecuteEx(), CreateProcess(), system(), _wsystem().
There are a few more, but one of these got to work for you!
Personally, I would go with CreateProcess and than wait for the process to quit (found on google this example: http://www.codeproject.com/Tips/333559/CreateProcess-and-wait-for-result). Notice that system()/_wsystem() are the easiest to use, but if you're not careful they can be exploited !!!
Hope it helps! :-)
Try this code:
#include <Windows.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* app_to_launch=new char[80];
strcpy(app_to_launch,"app.exe");
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
app_to_launch, // 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
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return 0;
}
I've been searching for an answer regarding this issue for a few days now, I hope you guys will be able to assist me. (I've searched and found some solutions, but each has its own issue...).
Here is the thing:
I'm writing an automation at work, which is responsible for launching an external ".exe" file of a code written by my colleagues. As those programs they write go to customers, I'm not allowed to make any modification to their code. Those programs, once launched, are waiting for specific key strokes, and prints a message when a legal key stroke has been received.
My goal is this:
To write a program which will execute the external program, send it key strokes, and receive the output from their stdout.
So far, I have been able to run the program from my program (using ShellExecute), and simulate some sort of keyboard listener (using SendMessage) to the other program. I can see that it works - I can see the output in the tested program's console.
I'm trying to fetch the messages printed on the tested program's shell in real-time (and just get a bulk of data when the program terminates) so that I could analyse it when it occurs.
Those I've tried:
Writing an external batch file with inline output redirection to a text file.
Using freopen.
Redirecting the output while exectuing "ShellExecute".
You use handles for stdin, stdout, and stderr. Create process with CreateProcess function to get that handles.
Sample code - incomplete for your case, but good example of how to do it:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
/*for test.exe
#include <iostream>
#include <string> */
void _tmain( int argc, TCHAR *argv[] )
{
/*for test.exe
std::cout << "test output" << std::endl;
for (;;)
{
std::string line;
std::getline(std::cin, line);
std::cout << "line: " << line << std::endl;
}
return;*/
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
"test.exe", // 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
)
{
printf( "CreateProcess failed (%d)\n", GetLastError() );
return;
}
/* HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;*/
HANDLE me_hStdInput = GetStdHandle(STD_INPUT_HANDLE);
HANDLE me_hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE proc_hStdInput = si.hStdInput;
HANDLE proc_hStdOutput = si.hStdOutput;
char buff[64];
DWORD chars;
while (!ReadConsole(me_hStdInput, buff, sizeof(buff), &chars, NULL))
{
for (DWORD written = 0, writtenThisTime; written < chars; written += writtenThisTime)
if (!WriteConsole(proc_hStdOutput, buff + written, chars - written, &writtenThisTime, NULL))
{
//handle error - TODO
}
}
//possibly handle error for ReadConsole - TODO
// Wait until child process exits.
//WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}