VC++中获取子进程的环境变量 [英] Get Environment Variables of Child Process in VC++

查看:46
本文介绍了VC++中获取子进程的环境变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Okay, here's essentially what I am trying to do. I have a process P1. This process needs to invoke the Visual Studio command-line compiler cl.exe in a separate process P2 (obviously). However, as everyone who has ever used the Visual Studio command-line compiler knows, you cannot simply invoke cl.exe and expect a good experience. You instead have to first run the batch script %VSXXXCOMNTOOLS%\vsvars32.bat (where XXX is the Visual Studio version number). This script sets a few key environment variables used by the compiler (such as what to use as the include path). Using a batch script, this is insanely easy to do:

call "%VS110COMNTOOLS%\vsvars32.bat"
...
cl Foo.cpp Bar.cpp ...

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

since just calling a batch file from a batch script runs in the same process (and thus the added environment variables are persistent). This is what I used to do before I realized that I need more flexibility and decided to port my script to C++ which, so far, has worked wonderfully. That is, until I got to the point where I need to implement the actual compilation.

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

So, that's the problem I am ultimately trying to solve. The best idea I have come up with is to invoke cmd.exe /c "%VS110COMNTOOLS%\vsvars32.bat" in a separate process P3 using CreateProcess, wait for that process to terminate, and then extract the modified environment variables from that child process. That is, P1 creates P3 and waits for it to finish. P1 then sets P3's environment variables as its own. P1 then creates P2 with these environment variables set. So the code looks roughly as follows (minus all error checking):

...
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);

那将是首选的解决方案.我不完全确定这样的事情是否可能,但根据我的研究,似乎有一种方法可以在 .NETProcessExplorer> 似乎能够读取任意进程的环境,所以我认为这样的解决方案是可能的.我似乎无法找到任何能够从子进程获取环境变量的文档化函数.在MSDN.其中一个响应提到将 Merge Environment 设置为 yes.有谁知道那是什么/意味着什么?我似乎找不到关于它的任何文档.

That would be the preferred solution. I am not entirely sure if such a thing is possible, but based off my research, it appears there is a way to do this in .NET, and ProcessExplorer appears to be able to read the environment of arbitrary processes, so I would assume such a solution is possible. I just can't seem to find any documented functions that are able to get environment variables from child processes. There's also an old discussion that is similar to this on MSDN. One of the responses mentions setting Merge Environment to yes. Anyone know what that is/means? I can't seem to find any documentation on it.

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

If it turns out this is not possible, alternate solutions I have thought about is (1) writing a batch script that simply calls vsvars32.bat and then invokes cl.exe with the input arguments, (2) invoking cmd instead of cl with arguments to run vsvars32.bat and then compile (similar to 1, but more extensible... but not sure if possible), or (3) print the environment variables to a file and then read those in. I'd prefer not to use any of such solutions if possible.

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

I'm also open to alternate suggestions. Just know that 99% of what I need to do is already done, so clean, non-hacky solutions are preferred.

推荐答案

干净的方法是运行 vcvars32 来设置所有环境变量,然后运行你的进程 P1.

The clean way to do this is to run vcvars32 to set all the environment variables and then run your process P1.

cmd /C vcvars32.bat && P1

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

Note that the user doesn't have to do this manually. Create a shortcut with this target:

cmd /C ""C:\Some Path\vcvarsall.bat" && start /separate C:\SomeOtherPath\YourGui.exe"

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

This sets the environment variables and then launches your GUI app. The start /separate stops the command-prompt lingering once the GUI app has started. If you also want this to be convenient to run from the command-line you can put it all in a batch file.

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

If for some reason you don't want to do this, the simplest way to get the environment variables from a batch script is to run:

cmd /U /C vcvars32.bat && set

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

This writes the values to standard output in Unicode. You can use a pipe to retrieve the values. This is much less hacky than trying to retrieve the variables from the memory of another process.

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

N.B. If you want to test this at a command-prompt you need to run:

cmd /U /C "vcvars32.bat && set"

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

The quotes ensure that the set runs in the child command processor.

这篇关于VC++中获取子进程的环境变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆