更改调用进程的环境变量

这个似乎微不足道,但现在几天我的答案已经没有了。

我有一个Windows批处理文件,它调用C#程序来执行无法在批处理文件中完成的额外validation。 validation完成后,我需要将状态和字符串返回给调用shell。

现在返回值很简单,我的C#控制台应用程序只是设置一个返回值(如果你愿意,退出代码)。 我认为这根绳子也是小菜一碟。 我尝试使用以下命令定义一个新的shell变量:

Environment.SetEnvironmentVariable("ERR", "Some text"); 

这个调用应该(并且确实)在当前进程中定义一个shell变量 – 这是创建变量的C#进程。 一旦C#应用程序终止,并且创建C#应用程序的shell对该变量一无所知,该值就会丢失。 所以…一个没有特别用途的电话……完全……除非我从C3应用程序创建了一个子进程,否则它可能会inheritance我的变量。

SetEnvironmentVariable调用的EnvironmentVariableTarget.Machine和EnvironmentVariableTarget.User目标也不能解决问题,因为只有新创建的进程才能从注册表中获取这些新值。

所以我能想到的唯一可行解决方案是:

  • 写信给stdout
  • 写入文件
  • 将额外含义编码到返回值中

前两个有点难看,最后一个有其局限性和问题。

任何其他想法(如何在父进程中设置shell变量)? 也许这样的shell变量修改是一个安全问题(想想PATH)……

感谢您的时间。

我遇到了和Ryan一样的问题,我想到的唯一一个解决方法是在错误中编写一个批处理来设置变量并从批处理中调用它。

ConsoleApplication1.exe中:

 'put some sensible code here 'put result in variable myResult Dim myResult As String = Guid.NewGuid().ToString("D").ToUpperInvariant() Console.WriteLine("Normal output from the consonle app") Console.Error.WriteLine("@ECHO OFF") Console.Error.WriteLine("SET zzzResult={0}", myResult) 

Test.cmd(调用批处理):

 @ECHO OFF :Jump to folder of batch file PUSHD %~d0%~p0 :Define a temp file SET zzzTempFile=%TEMP%\TMP%Random%.CMD :Call .NET console app ConsoleApplication1.exe 2>%zzzTempFile% :Call the generated batch file CALL %zzzTempFile% :Clean up temp file DEL %zzzTempFile% :Clean up variable SET zzzTempFile= :Do something with the result ECHO Yeah, we finally got it! ECHO: ECHO The value is "%zzzResult%". ECHO: :Clean up result variable SET zzzResult= :Go back to original folder POPD 

这应该够了吧。 是的,我知道这是一个老post,Ryan现在正在解决其他问题,但可能还有其他人在那里遇到同样的问题……

你要问的是能够随意写入正在运行的进程的内存空间。 有充分理由,如果没有SeDebugPrivilege,这是不可能的。

您列出的三种解决方案中的任何一种都有效。 Stdout是与批处理脚本通信的标准方法。

顺便说一句,您正在编写Windows批处理文件。 我很确定这艘船已经航行“有点难看”。

如果要将某些输出的值放入批处理中的变量,可以使用以下构造:

 FOR /F "usebackq tokens=4 delims=\[\] " %i IN (`ver`) DO set VERSION=%i ECHO %VERSION% 

我的操作系统输出:

 6.1.7601 

‘usebackq’表示我们使用后引号,这使得能够在引用双引号的命令中使用文件集。 你可能不需要这个。 ‘tokens’表示要选择的结果字符串数组中的索引(它可以是范围MN)。 如果你需要跳过行,请使用’skip = X’)。 ‘delims’是要使用的字符串分隔符(如.Net中的string-Split())。

您将放置控制台应用程序而不是“ver”,并调整分隔符和标记以匹配您的特定输出。 如果要填充更多变量,则需要使if更复杂,但这应该是一个良好的开端。

我的BAT有点生疏,但我认为可以从外部运行的进程中检索“退出”代码,可能是通过%ERRORLEVEL% 。 如果是这种情况,请务必通过以下方式退出程序

 Environment.Exit(123); // where 123 = error code 

您无法添加任何消息,因此您必须在.bat文件中执行此操作。

如果不是这样,stdout可能是最好的方法。

在最近我自己也遇到了这个问题之后,我想出了这种方法。 我所做的是使用Process类运行bat文件,即

 // Spawn your process as you normally would... but also have it dump the environment varaibles Process process = new Process(); process.StartInfo.FileName = mybatfile.bat; process.StartInfo.Arguments = @"&&set>>envirodump.txt"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = false; process.Start(); string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); // Read the environment variable lines into a string array string[] envirolines = File.ReadAllLines("envirodump.txt"); File.Delete("envirodump.txt"); // Now simply set the environment variables in the parent process foreach(string line in a) { string var = line.Split('=')[0]; string val = line.Split('=')[1]; Environment.SetEnvironmentVariable(var, val); } 

这似乎对我有用。 这不是最干净的方法,但会在绑定中起作用。 🙂