Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
739 views
in Technique[技术] by (71.8m points)

c++ - Use CreateProcess to Run a Batch File

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
");
        return FALSE;
    }

    lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
    if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, TEXT("MyVersion=2"))))
    {
        printf("String copy failed
");
        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)
", GetLastError());
        return FALSE;
    }

    std::cout << "In new environment
";
    WaitForSingleObject(pi.hProcess, INFINITE);

    return TRUE;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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(''); // 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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...