2014-09-18 441 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