正在更改调用进程的环境变量

本文关键字:进程 环境变量 调用 | 更新日期: 2023-09-27 17:57:29

这个问题看起来微不足道,但我已经有几天没有找到答案了。

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

现在,返回值是微不足道的,我的C#控制台应用程序只需设置一个返回值(如果愿意,请退出代码)。我想这根绳子也会是小菜一碟。我尝试使用定义一个新的shell变量

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

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

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

这就行了。是的,我知道这是一个老帖子,Ryan现在正在解决其他问题,但可能还有其他人也有同样的问题。。。

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

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

顺便说一下,您正在编写一个Windows批处理文件。我敢肯定这艘船已经"有点难看"了。

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

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

我的操作系统输出:

6.1.7601

"usebackq"意味着我们使用的是反引号,这样就可以在用双引号引起来的命令中使用文件集。你可能不需要这个。"tokens’表示要选择的结果字符串数组中的索引(可以是范围M-N)。如果您需要跳过行,请使用'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);
} 

这似乎对我有效。这不是最干净的方法,但会在一定程度上起作用。:)