Use CreateProcess to Run a Batch File

Some problems:

  1. You need to pass the /C option to cmd.exe in order to make it execute the .bat file.
  2. The second parameter to CreateProcess must be a modifiable string. Not a literal.
  3. You need to escape backslash characters in literals.
  4. lpszCurrentVariable points to the buffer returned by GetEnvironmentStrings. 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.
  5. Environment blocks are double null terminated. Standard string functions are of no use with double null terminated strings.
  6. Using functions like StringCchCopy rather than C runtime functions is just confusing. Don’t take MSDN example code as being the paragon of style.
  7. C strings are a bind to work with. But you use C++ so use std::wstring and other standard library classes and function.
  8. You need to define WINDOWS_LEAN_AND_MEAN before importing Windows.h.
  9. For C++, int main(void) is incorrect. The no argument main is int 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);
}

Leave a Comment