更改调用进程的环境变量

时间:2011-05-23 08:41:47

标签: c# windows-shell

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

我有一个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)......

谢谢你的时间。

5 个答案:

答案 0 :(得分:3)

我遇到了与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现在正在解决其他问题,但可能还有其他人有同样的问题......

答案 1 :(得分:2)

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

您列出的三种解决方案中的任何一种都可以使用。 Stdout是与批处理脚本进行通信的标准方法。

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

答案 2 :(得分:1)

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

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更复杂,但这应该是一个良好的开端。

答案 3 :(得分:0)

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

退出程序
Environment.Exit(123); // where 123 = error code

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

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

答案 4 :(得分:0)

最近我自己也遇到了这个问题后,我提出了这种方法。我所做的是使用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);
} 

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