问题
I am trying to use CreateProcess to start a new environment block and run a batch file in the new environment block. I've read through the msdn example for CreateProcess, and came up with the code shown below.
What is happening, it will open the new command prompt, and stop there. It will not run my .bat file for some reason. Using system("CALL path") will call the .bat file.
#include <iostream>
#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <strsafe.h>
#define BUFSIZE 4096
int main()
{
//system("CALL C:\\HFSS\\setup_vars.bat");
//return 0;
LPWCH chNewEnv;
LPTSTR lpszCurrentVariable;
DWORD dwFlags = 0;
TCHAR szAppName[] = TEXT("C:\\windows\\system32\\cmd.exe");
TCHAR cmdArgs[] = TEXT("C:\\HFSS\\setup_var.bat");
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL fSuccess;
// Copy environment strings into an environment block.
chNewEnv = GetEnvironmentStrings();
lpszCurrentVariable = (LPTSTR)chNewEnv;
if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, TEXT("MySetting=A"))))
{
printf("String copy failed\n");
return FALSE;
}
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, TEXT("MyVersion=2"))))
{
printf("String copy failed\n");
return FALSE;
}
// Terminate the block with a NULL byte.
lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
*lpszCurrentVariable = (TCHAR)0;
// Create the child process, specifying a new environment block.
SecureZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
#ifdef UNICODE
dwFlags = CREATE_UNICODE_ENVIRONMENT;
#endif
fSuccess = CreateProcess(szAppName, cmdArgs, NULL, NULL, TRUE, dwFlags,
(LPVOID)chNewEnv, // new environment block
NULL, &si, &pi);
if (!fSuccess)
{
printf("CreateProcess failed (%d)\n", GetLastError());
return FALSE;
}
std::cout << "In new environment\n";
WaitForSingleObject(pi.hProcess, INFINITE);
return TRUE;
}
回答1:
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);
}
来源:https://stackoverflow.com/questions/25919451/use-createprocess-to-run-a-batch-file