在VC++中获取子进程的环境变量

Dun*_*can 5 windows winapi visual-c++

好的,这基本上就是我想要做的.我有一个过程P1.此过程需要cl.exe在单独的进程中调用Visual Studio命令行编译器P2(显然).但是,正如使用Visual Studio命令行编译器的每个人都知道的那样,您不能简单地调用cl.exe并期望获得良好的体验.您必须首先运行批处理脚本%VSXXXCOMNTOOLS%\vsvars32.bat(XXXVisual Studio版本号在哪里).此脚本设置编译器使用的一些关键环境变量(例如用作包含路径的内容).使用批处理脚本,这非常容易:

call "%VS110COMNTOOLS%\vsvars32.bat"
...
cl Foo.cpp Bar.cpp ...
Run Code Online (Sandbox Code Playgroud)

因为只是从批处理脚本调用批处理文件在同一个进程中运行(因此添加的环境变量是持久的).在我意识到我需要更多的灵活性并决定将我的脚本移植到C++之前,这是我过去常常做的事情,到目前为止,C++运行得非常好.也就是说,直到我达到我需要实现实际编译的程度.

所以,这是我最终要解决的问题.我想出最好的办法是调用cmd.exe /c "%VS110COMNTOOLS%\vsvars32.bat"一个单独的进程P3使用CreateProcess,等待进程结束,然后提取该子进程修改后的环境变量.也就是说,P1创建P3并等待它完成.P1然后将P3环境变量设置为自己的环境变量.P1然后创建P2这些环境变量集.所以代码大致如下(减去所有错误检查):

...
CreateProcess(TEXT("cmd"), TEXT("/c \"%VS110COMNTOOLS%\vsvars32.bat\""), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

WaitForSingleObject(pi.hProcess, INFINITE);

/* Set current process environment using pi.hProcess */
CloseHandle(pi.hProcess);

...

CreateProcess(TEXT("cl"), TEXT("..."), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
Run Code Online (Sandbox Code Playgroud)

那将是首选的解决方案.我不完全确定这样的事情是否可行,但根据我的研究,似乎有一种方法可以在.NET中执行此操作,而ProcessExplorer似乎能够读取任意进程的环境,所以我会假设这样解决方案是可能的.我似乎无法找到任何能够从子进程获取环境变量的文档化函数.在MSDN上还有一个与此类似的讨论.其中一个答复提及设置到.任何人都知道那是什么意思?我似乎无法找到任何文件.Merge Environmentyes

如果事实证明这是不可能的,我想到的替代解决方案是(1)编写一个简单调用vsvars32.bat然后cl.exe使用输入参数调用的批处理脚本,(2)调用cmd而不是cl使用参数运行vsvars32.bat然后编译(类似于1,但更具可扩展性......但不确定是否可能),或者(3)将环境变量打印到文件中然后读取它们.如果可能的话,我宁愿不使用任何此类解决方案.

我也愿意接受其他建议.只要知道我需要做的99%已经完成,所以首选干净,非hacky解决方案.

arx*_*arx 5

执行此操作的简洁方法是运行vcvars32以设置所有环境变量,然后运行您的进程P1

cmd /C vcvars32.bat && P1
Run Code Online (Sandbox Code Playgroud)

请注意,用户不必手动执行此操作。使用此目标创建快捷方式:

cmd /C ""C:\Some Path\vcvarsall.bat" && start /separate C:\SomeOtherPath\YourGui.exe"
Run Code Online (Sandbox Code Playgroud)

这将设置环境变量,然后启动您的 GUI 应用程序。start /separate一旦 GUI 应用程序启动,命令提示符就会停止。如果您还希望可以方便地从命令行运行,您可以将其全部放入批处理文件中。

如果由于某种原因您不想这样做,从批处理脚本获取环境变量的最简单方法是运行:

cmd /U /C vcvars32.bat && set
Run Code Online (Sandbox Code Playgroud)

这会将值以 Unicode 格式写入标准输出。您可以使用管道来检索值。这比尝试从另一个进程的内存中检索变量要简单得多。

注意:如果您想在命令提示符下测试它,您需要运行:

cmd /U /C "vcvars32.bat && set"
Run Code Online (Sandbox Code Playgroud)

引号确保set在子命令处理器中运行。

  • +1 用于管道输出,以便可以捕获它。原始进程可以调用 CreateProcess() 来运行具有重定向输出的 cmd.exe(MSDN 上有示例),然后在调用 CreateProcess() 时将捕获的值包含在 lpEnvironment 参数中来运行cl.exe`。 (2认同)