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);
}
Related
I just started writing a console app in C++. It does some verification and then it needs to find and run an executable that can be in a variety of places depending on how it was deployed. So most of the script works and even the run part works depending on the OS and location. If it is local it works and if it is windows 7 it seems to work even on the UNC. But in Windows 10 it just exits out.
The script finds the exe and runs it from the path it is in. It works when I created the application as a batch file the uses popD to move to the exe location for working directory but I can't seem to mimic that functionality in C++. I have tried SetCurrentDirectory but it won't take my string that I am trying to pass.
if (version >= minver)
{
std::string name = "testApp.exe";
std::string path = (fs::current_path().string());
for (const auto& entry : fs::recursive_directory_iterator(path))
{
std::string list = entry.path().string();
int found;
if ((found = list.find(name)) !=list.npos)
{
std::cout << list << std::endl;
\\This is the part that sometimes works and sometimes doesn't
system(list.c_str());
}
}
}
As you can start your program from console, try to use CreateProcess function in console mode:
int runProcessFromCmd( char* pcExecPath)
{
if( NULL == pcExecPath)
{
printf("empty path!");
return -1;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset( &si, 0, sizeof(si) );
memset( &pi, 0, sizeof(pi) );
si.cb = sizeof(si);
// Start child process from command line
// First parameter = NULL => we use cmd
if( !CreateProcess( NULL, pcExecPath, NULL,NULL, FALSE, 0, NULL, NULL, &si, &pi ))
{
printf( "CreateProcess failed with error (%d).\n", GetLastError() );
return -2;
}
// Wait child process
WaitForSingleObject( pi.hProcess, INFINITE );
// Close all handles
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
So in the long run I was chasing down the problem in the wrong way. Thanks to LandStalker for putting on a better path. I was right about mimicking a popD but had a hard time doing it in the right way to actually work.
I SetCurrentDirectory and then did a ShellExecute on the program name.
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";
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.
tempString = (string("cmd.exe /C \"") + tempString + "\"");
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
CreateProcess(NULL, (LPSTR)tempString.c_str(), 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT, NULL, 0, &si, &pi);
I am starting a batch script from within another process through a dll.
The issue is that the process is displaying:
error : Input redirection is not supported, exiting the process
immediately.
How can I start a batch script so that it is independent of the calling process (will not close when callee closes) and does not output in the console of the calling process?
If you don't want show the console window when executing command string, you can do as below:
tempString = (string(" /C \"") + tempString + "\"");
ShellExecute(NULL, NULL, "cmd.exe", tempString.c_str(), NULL, SW_HIDE);
The CREATE_NEW_CONSOLE flag allocates a new console for the process to use so that it does not use the same stdout as the calling process.
I need to start a process that starts the commandline (it should not pop up, so something like a background process).
Then I need to write stuff to it and periodically read the last line of the cmd.
Since my C++ skills aren't that great I don't know how to achieve this.
In a pseudocode way I thought about something like this:
startProcess();
writeToCmd();
readFromCmd() { // Call that every given interval (e.g. 1000 ms)
if(returnValue >= 100) {
stopProcess();
}
}
I'm pretty sure it'll not be that easy. It would be really great if someone can help me out here.
The programm is for windows.
Edit after the suggestions:
This is what I've done so far (I did it a little bit different.)
int errorCode;
// Variables for CreateProcess()
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;
PHANDLE hInRead, hInWrite;
LPDWORD bytesWritten, bytesRead;
// The CommandLine input
TCHAR tcsCommandLine[] = _T("cmd /c format H: /fs:FAT32 /V:device");
//TCHAR tcsCommandLine[] = _T("cmd /c start D:\\foo.txt");
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW; // SW_HIDE FOR PRODUCTION
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = hInRead;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
ZeroMemory(&pi, sizeof(pi));
errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);
info = GetDriveInfo(m_wsNANDMountPoint);
if(info.m_uSizeInMB > 2048) {
log("Wrong Mounting Point. Device has more than 2GB space.");
return false;
}
else {
// Start Formatting
if(!CreateProcess(NULL, tcsCommandLine,
NULL, NULL,
TRUE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL, NULL,
&si,
&pi)) {
log("CreateProcess failed. Could not format Drive");
return false;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
WriteFile(hInWrite, "#13#10'J'#13#10", 5, bytesWritten, NULL);
CloseHandle(hInWrite);
// Wait until child process exits
WaitForSingleObject(pi.hProcess, 1100);
}
return true;
After a little bit of debugging, I recognized that the code doesn't break at ZeroMemory(), but on
errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);
with an Access violation writing location error. I have no idea what I'm doing wrong.
It would be really great if you guys could help me out.
What you need to do in this instance is to create a console with a hidden window. If you use CreateProcess to launch the console, you should be able to set the visibility of the window through the STARTUPINFO structure.
The next step is to redirect the input and output of your console. You can do this by attaching the 3 console handles (input, output, error) to pipes and reading that from your parent process. This MSDN article describes how to do exactly this.
The command line consists of two parts you would be interested in.
A place to execute programs
A buffer for whatever is written on the screen
Since you don't need the screen to be visible, then you need these two things in your program. So from here on, forget about cmd.
To execute programs in your program, you have many ways. If you want the execution lines to look exactly the way you write it in cmd, you can use system (although Windows versions of fork/exec make more sense). For example:
system("my_prog.exe --option file.txt");
Which executes my_prog.exe with --option and file.txt as arguments.
Now the second one, you said you wanted to read the last line from cmd. The idea to realize this is to have the output of everything in a file, instead of in cmd.
If you are only interested in the last line at every instance, you can redirect the output of your programs to a file like this:
system("my_prog.exe --option file.txt > output.txt");
or if you want to keep the whole history, you can append instead of overwrite:
system("my_prog.exe --option file.txt >> output.txt");
If you also want to redirect stderr, you can write:
system("my_prog.exe --option file.txt &> output.txt");
The notation may be linuxy, try it in your windows see if it works (manually in a normal cmd). You could also search google for "shell redirect" and you get a lot of results.
Anyway, if you want the last line of cmd to also include the command itself, you can overwrite/append the command line to that particular yourself in the program.
Let me add this to these excellent answers:
This great link demonstrates console read and write : http://www.adrianxw.dk/SoftwareSite/Consoles/Consoles2.html
To do stuff periodically, use SetTimer().
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx
The SetTimer function executes a function every x milliseconds.
Example:
The following console program works like this: It sets a timer using SetTimer
then loops in a message loop. The message loop receives and processes WM_TIMER messages
and the timer callback also is called for each time interval.
Simply put the stuff you want done in the TimerProc() function.
#define STRICT 1
#include <windows.h>
#include <iostream.h>
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
//put the stuff you want done in here
cout << "Doing stuff Time: " << dwTime << '\n';
cout << "--------------------------------------------------\n" ;
cout.flush();
}
int main(int argc, char *argv[], char *envp[])
{
int Counter=0;
int usage_Time_millisec=1000;
MSG Msg;
UINT TimerId = SetTimer(NULL, 0, usage_Time_millisec, &TimerProc); //bind TimerProc() to SetTimer()
cout << "TimerId: " << TimerId << '\n';
if (!TimerId) return 16;
while (GetMessage(&Msg, NULL, 0, 0))
{
++Counter;
if (Msg.message == WM_TIMER)
cout << "Doing stuff Counter: " << Counter << "; timer message\n";
else
cout << "Doing stuff Counter: " << Counter << "; message: " << Msg.message << '\n';
DispatchMessage(&Msg);
}
KillTimer(NULL, TimerId);
return 0;
}