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);
}
Related
I am using CreateProcess api to start a batch file. The Code works fine on windows 7 but it is failing on Windows 10.
Below is the snippet of code:
CString param; //it holds the very long string of command line arguments
wstring excFile = L"C:\\program files\\BatchFile.bat";
wstring csExcuPath = L"C:\\program files";
wstring exeWithParam = excFile + _T(" ");
exeWithParam = exeWithParam.append(param);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR lpExeWithParam[8191];
_tcscpy_s(lpExeWithParam, exeWithParam.c_str());
BOOL bStatus = CreateProcess(NULL, lpExeWithParam, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB, NULL, csExcuPath.c_str(), &si, &pi);
DWORD err;
if (!bStatus)
{
err = GetLastError();
}
With the above code, it is invoking a batch file which will start an executable with given parameters. This code is not working only Windows 10 in our product.
GetLastError is returning error code 122 which code for error "The data area passed to a system call is too small." How to figure out what is causing this error and how it can be resolved?
However, when using the same code in a sample test application is not giving any error and passing.
Any clue/hint why is causing it to fail on Windows 10.
You need to execute cmd.exe with the .bat file as a parameter, don't try to execute the .bat directly.
Also, you don't need lpExeWithParam, you can pass exeWithParam directly to CreateProcess().
Try something more like this instead:
CString param; //it holds the very long string of command line arguments
...
wstring excFile = L"C:\\program files\\BatchFile.bat";
wstring csExcuPath = L"C:\\program files";
wstring exeWithParam = L"cmd.exe /c \"" + excFile + L"\" ";
exeWithParam.append(param);
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = {};
BOOL bStatus = CreateProcessW(NULL, &exeWithParam[0]/*or exeWithParam.data() in C++17*/, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB, NULL, csExcuPath.c_str(), &si, &pi);
if (!bStatus)
{
DWORD err = GetLastError();
...
}
else
{
...
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
Error 122 equates to ERROR_INSUFFICIENT_BUFFER and I think the clue here is "it holds the very long string of command line arguments".
Just how long is it? The limit may be lower on Windows 10 - I recommend you experiment (binary chop).
Also, the documentation for CreateProcess states that you must launch cmd.exe explicitly to run a batch file, so I guess you should do what it says.
I think to run a batch file you must set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file
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.
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 am trying to create a process that send command to cmd.exe and receive Error 2,
Why? It's posible? How?
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
String pathexe = "C:\Windows\system32\cmd.exe";
String command= "notepad.exe";
if(!CreateProcess(
pathexe.c_str(), // lpApplicationName
command.c_str(), // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
FALSE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
))
{
AnsiString error = GetLastError();
ShowMessage("Error: " + error);
}
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
PD: 1) It is assumed that you can use CreateProcess () for this purpose, I should not do it with ShellExecute () or system().
2) I have read about it in the forum and can not find a solution to this error, there are many answers to similar questions but do not address the error, other functions are proposed, or mix with the route command.
3) I do not think that issue permits because I built while the manifest.
4) I currently use C ++ Builder, in win7, 32bits but not important.
5) I guess the issue will be voted as negative and duplicate (as usual) but the proposed testing examples also receive errors.
Thanks to all
FIRST CONCLUSIONS:
Error 2: The system cannot find the file specified.
Link funtion: https://msdn.microsoft.com/es-es/library/windows/desktop/ms679360(v=vs.85).aspx
Link error: https://msdn.microsoft.com/es-es/library/windows/desktop/ms681382(v=vs.85).aspx
With error 2: check syntax, file path and existence.
works:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
String command = "notepad.exe";
if(!CreateProcess(
NULL, // lpApplicationName
commmand.c_str(), // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
FALSE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
))
{
AnsiString error = GetLastError();
ShowMessage("Error: " + error);
}
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
This example works also for exe
String command = "cd C:\\sample\\calc.exe";
But no with cmd´s general commands, there must be a way to send commands to cmd as:
notepad.exe && cd C:\sample\ && sample1.txt
THANKS TO ALL
You're trying to run this command:
cmd notepad
(You aren't doing that quite right, either; the lpCommandLine argument should include the entire string, not just notepad, and you haven't quoted the backslashes properly.)
But even once you fix those problems, it won't work, because you've got the syntax wrong. You'll find it won't work if typed on the command line either!
Instead, try:
String pathexe = "C:\\Windows\\system32\\cmd.exe";
String command= "cmd /c notepad.exe";
The /c option means "run this command". You can use /k instead if you want the command window to stay open after the command has finished, though it's unusual for a program to do so.
One final note: I'm assuming here than notepad is just a stand-in for a more complicated command. If you actually want to run notepad, or any other executable, you shouldn't be invoking cmd.exe at all:
String command= "notepad";
if(!CreateProcess(
NULL, // lpApplicationName
command.c_str(), // lpCommandLine
...
You only need to call on cmd.exe if you need to run a built-in command, or a composite command line.
(Actually, calling cmd.exe is considered poor practice even in those cases; in Windows, you are generally expected do that sort of thing for yourself via the API rather than farming out the job to the command interpreter. But there are edge cases, and your mileage may vary.)
i hev problem with CreatProcess function introduced in windows.h header for c++.
whenever i try to pass it a TCHAR variable containing a cmd command it returns error : CreateProcess failed (2) .
and for this am waiting for your explanations and solutions.
consider code below:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int _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 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return 0;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // 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 0;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
notice:when i launch an application with specifying its path ..it works fine like=> "c:\code.exe";
If you want to run a command DOS, you have to run the shell cmd before.
CreateProcess doesn't do that for you.
The option /c of cmd permits to run a command in the shell and terminate. You just have to build a command line of the type cmd /c <your command here>.
I compiled your code on VS2012 and I tried : test.exe "cmd /c dir" and it works like a charm.
From the Microsoft documentation :
To run a batch file (or a batch command), 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.
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
In order to execute a command implemented by the command shell aka cmd.exe, you need to actually run cmd.exe. CreateProcess doesn't automatically do that for you.
Build a command line of the form cmd.exe /c <your command here>. /c means "run one command, then terminate".