使用CreateProcess运行批处理文件

Use CreateProcess to Run a Batch File

本文关键字:批处理文件 运行 CreateProcess 使用      更新时间:2023-10-16

我正在尝试使用CreateProcess启动一个新的环境块,并在新的环境中运行一个批处理文件。我已经阅读了CreateProcess的msdn示例,并得出了如下所示的代码。

发生了什么,它将打开新的命令提示符,并在那里停止。由于某种原因,它不会运行我的.bat文件。使用系统("CALL路径")将调用.bat文件。

#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 failedn");
        return FALSE;
    }
    lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
    if (FAILED(StringCchCopy(lpszCurrentVariable, BUFSIZE, TEXT("MyVersion=2"))))
    {
        printf("String copy failedn");
        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 environmentn";
    WaitForSingleObject(pi.hProcess, INFINITE);
    return TRUE;
}

一些问题:

  1. 您需要将/C选项传递给cmd.exe,以便使其执行.bat文件
  2. CreateProcess的第二个参数必须是可修改的字符串。不是字面意思
  3. 您需要对文字中的反斜杠字符进行转义
  4. CCD_ 4指向CCD_。您不能修改该缓冲区。你需要分配一个足够长的新缓冲区,并将环境复制到其中。然后添加你的修改
  5. 环境块以双null结尾。标准字符串函数对以双null结尾的字符串没有任何用处
  6. 使用像StringCchCopy这样的函数而不是C运行时函数只是令人困惑。不要把MSDN示例代码看作是风格的典范
  7. C字符串是一个可以使用的绑定。但是您使用C++,所以使用std::wstring和其他标准库类和函数
  8. 在导入Windows.h之前,您需要定义WINDOWS_LEAN_AND_MEAN
  9. 对于C++,int main(void)是不正确的。无自变量mainint main()

以下代码向您展示了如何做到这一点:

#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);
}