使用CreateProcess运行批处理文件

时间:2014-09-18 18:03:30

标签: c++ winapi batch-file createprocess

我正在尝试使用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 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 个答案:

答案 0 :(得分:15)

一些问题:

  1. 您需要将/C选项传递给cmd.exe才能使其执行.bat文件。
  2. CreateProcess的第二个参数必须是可修改的字符串。不是文字。
  3. 您需要在文字中转义反斜杠字符。
  4. lpszCurrentVariable指向GetEnvironmentStrings返回的缓冲区。您无法修改该缓冲区。您需要分配一个足够长度的新缓冲区并将环境复制到其中。然后添加您的修改。
  5. 环境块以双空终止。标准字符串函数与双空终止字符串无关。
  6. 使用像StringCchCopy这样的函数而不是C运行时函数只会令人困惑。不要将MSDN示例代码作为样式的典范。
  7. C字符串是一个可以使用的绑定。但是你使用C ++,所以使用std::wstring和其他标准库类和函数。
  8. 您需要在导入WINDOWS_LEAN_AND_MEAN之前定义Windows.h
  9. 对于C ++,int main(void)不正确。无争论mainint main()
  10. 以下代码显示了如何执行此操作:

    #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);
    }
    
相关问题