2014-09-18 652 views
8

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

发生了什么,它会打开新的命令提示符,然后停在那里。由于某种原因,它不会运行我的.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; 
} 
+0

那一行它触发一个破发点?您不确定的行正在尝试将两个新的环境变量添加到即将启动的流程的环境块中,并且您已指出这是您正在尝试执行的操作,所以我不确定您的操作关于他们的问题可能是。 – 2014-09-18 18:11:57

+0

我实际上是试图在批处理文件中设置环境变量。但是,当我到达批处理文件(不创建新进程)时,%PATH%变量具有来自visual studio的所有树数据。所以,当我尝试将新路径附加到%PATH%变量时,它将包含冗余和过多的信息。另外,我发现崩溃是由于使用“\”而不是“\\” – user2970916 2014-09-18 18:21:49

+0

您的编辑没有解决我提出的所有问题。 – 2014-09-18 18:38:24

回答

15

一些问题:

  1. 您需要将/C选项传递给cmd.exe以使其执行.bat文件。
  2. CreateProcess的第二个参数必须是可修改的字符串。不是文字。
  3. 您需要在文字中转义反斜线字符。
  4. lpszCurrentVariable指向由GetEnvironmentStrings返回的缓冲区。您不能修改该缓冲区。您需要分配足够长度的新缓冲区并将环境复制到其中。然后添加您的修改。
  5. 环境块是双空终止的。标准字符串函数对于以双空字符结尾的字符串没有用处。
  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('\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); 
} 
+0

感谢所有帮助,但是,运行仍然给我我原来的问题: 我的批处理文件读取%PATH%变量作为本地副本(来自Visual Studio)。 这里有一个原始问题的链接: http://stackoverflow.com/questions/25917796/setting-path-variable-is-not-working – user2970916 2014-09-18 19:15:10

+0

在这里工作很好。更重要的是,你会发现我所展示的代码比你更简单,并向你展示如何避免所有可怕的C样板。 – 2014-09-18 19:15:58

+0

无论如何,从我的确切程序开始。使用系统上的有效文件名替换.bat文件名。在您的.bat文件中放置列出环境变量的'set'命令。当你这样做会发生什么? – 2014-09-18 19:19:01