Use CreateProcess to Run a Batch File
Some problems:
- You need to pass the
/C
option tocmd.exe
in order to make it execute the .bat file. - The second parameter to
CreateProcess
must be a modifiable string. Not a literal. - You need to escape backslash characters in literals.
lpszCurrentVariable
points to the buffer returned byGetEnvironmentStrings
. You cannot modify that buffer. You need to allocate a new buffer of sufficient length and copy the environment into it. Then add your modifications.- Environment blocks are double null terminated. Standard string functions are of no use with double null terminated strings.
- Using functions like
StringCchCopy
rather than C runtime functions is just confusing. Don't take MSDN example code as being the paragon of style. - C strings are a bind to work with. But you use C++ so use
std::wstring
and other standard library classes and function. - You need to define
WINDOWS_LEAN_AND_MEAN
before importingWindows.h
. - For C++,
int main(void)
is incorrect. The no argumentmain
isint main()
.
The following code shows you how to do this:
#include <cstring>
#include <string>
#include <iostream>
#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
std::wstring GetEnvString()
{
wchar_t* env = GetEnvironmentStrings();
if (!env)
abort();
const wchar_t* var = env;
size_t totallen = 0;
size_t len;
while ((len = wcslen(var)) > 0)
{
totallen += len + 1;
var += len + 1;
}
std::wstring result(env, totallen);
FreeEnvironmentStrings(env);
return result;
}
int main()
{
std::wstring env = GetEnvString();
env += L"myvar=boo";
env.push_back('\0'); // somewhat awkward way to embed a null-terminator
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
wchar_t cmdline[] = L"cmd.exe /C C:\\Desktop\\MyBatFile.bat";
if (!CreateProcess(NULL, cmdline, NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT,
(LPVOID)env.c_str(), NULL, &si, &pi))
{
std::cout << GetLastError();
abort();
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Run a batch file using createProcess()
Assumming a standard configuration, the answer is no, it is not required. You can include the batch file in the lpCommandLine
argument. The remaining arguments just follow the batch file with quotes where needed.
test.cmd
@echo off
setlocal enableextensions disabledelayedexpansion
echo %1
echo %~1
echo %2
echo %~2
test.c
#define _WIN32_WINNT 0x0500
#include <windows.h>
void main(void){
// Spawn process variables
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
CreateProcess(
NULL
, "\"test.cmd\" \"x=1 y=2\" \"x=3 y=4\""
, NULL
, NULL
, TRUE
, 0
, NULL
, NULL
, &si
, &pi
);
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
};
Output
W:\>test.exe
"x=1 y=2"
x=1 y=2
"x=3 y=4"
x=3 y=4
c++ Execute batch file with createprocess
Below is a pseudo code for running bat in background.
//... Prepare
//
// Get Current Dir
#define BUFSIZE MAX_PATH
TCHAR myBat[BUFSIZE];
DWORD dwRet;
dwRet = GetCurrentDirectory(BUFSIZE, myBat);
// Append .bat name
myBat += "this_one.bat"
//... Execute
//
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
wchar_t cmdline[] = L"cmd.exe /C "+ myBat ;
wchar_t cmdline2[] = L"start /MIN /B \"\" \""+ myBat +"\"";
// For kiosk windows
//wchar_t cmdline[] = L"%systemroot%\\system32\\cmd.exe /C "+ myBat ;
if (!CreateProcess(NULL, cmdline, NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT,
NULL, NULL, &si, &pi))
{
std::cout << GetLastError();
abort();
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
run batch file with /y using createprocess vs2010
Try this
::CreateProcess(L"cmd.exe", L"/c run.bat /y", NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
NULL, NULL, &startInfo, &procInfo )
As it says on MSDN
To run a batch file, 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.
Launching a bat file using CreateProcess windows API
Using FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
for dwShareMode
parameter of CreateFile
API for file handles solves the problem
CreateFile(filehandlepate, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &secureAttr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
Start windows batch from C++ CreateProcess has different behavior
I just found a solution: I changed the line (in the batch buildMySolution.bat
):
call "C:\Program Files(x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"
to:
call C:\PROGRA~2\micros~1.0\vc\vcvarsall.bat
Believe it or not: using DOS names and removing quotes makes it work!!!
Bug or feature, I'm not sure...
Related Topics
Opencv Cv::Mat and Eigen::Matrix
Reduce Flicker with Gdi+ and C++
Function in C++ Returns by Value or by Reference
Easy Way Find Uninitialized Member Variables
Linking to Msvc Dll from Mingw
Compiling with -Static-Libgcc -Static-Libstdc++ Still Results in Dynamic Dependency on Libc.So
Does "Std::Size_T" Make Sense in C++
Can Google Mock a Method with a Smart Pointer Return Type
C++ Vector, What Happens Whenever It Expands/Reallocate on Stack
Initialise Eigen::Vector with Std::Vector
Why Does the Standard Differentiate Between Direct-List-Initialization and Copy-List-Initialization
How to Solve the Error Lnk2019: Unresolved External Symbol - Function
What Is the Best Modern C++ Approach to Construct and Manipulate a 2D Array
What Does Lpcwstr Stand for and How Should It Be Handled With
Why Is Nvidia Pascal Gpus Slow on Running Cuda Kernels When Using Cudamallocmanaged