2011-05-23 63 views
5

这一个看起来微不足道,但答案几乎没有我了。更改调用进程的环境变量

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

谢谢你的时间。

回答

0

我的英美烟草公司有点生疏,但我认为可以通过%ERRORLEVEL%从外部运行的流程中检索“退出”代码。如果是这样的情况下,通过

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

一定要退出你的程序不能添加任何的消息,所以你必须做的是,在.bat文件。

如果不是这种情况,stdout可能是最好的方法。

+0

确实如此。控制台应用程序的结果通常通过返回码返回。显然''Environment.Exit()'在框架上有点粗糙......所以一个简单的'return x'是首选的方法。但是,我想知道是否有一种方法可以将**另一个值**推送到父shell环境中。例如错误代码123以字符串形式的解释... 我现在正在使用stdout ...将其重定向到一个文件,将其读回到一个shell var,删除该文件...略有肮脏,但它的作品。 – JamesH 2011-05-23 14:10:42

1

如果你想放一些输出值到一个变量在批处理,您可以使用下面的结构:

6.1.7601 

“有usebackq”的意思是:我的操作系统

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

输出我们使用的是后引号,它能够在用双引号括起来的命令中使用文件集。你可能不需要这个。 '令牌'表示结果字符串数组中要选择的索引(它可以是范围M-N)。如果您需要跳过行,请使用'skip = X')。'delims'是要使用的字符串分隔符(如.Net中的字符串Split())。

你会把你的控制台应用程序,而不是'ver',并调整分隔符和令牌以匹配您的具体输出。如果你有更多的变数需要填写,你需要做的更复杂一点,但这应该是一个好的开始。

2

您所要求的是能够随意写入正在运行的进程的内存空间。出于好的原因,没有SeDebugPrivilege,这是不可能的。

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

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

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 

这应该做的伎俩。是的,我知道这是一个旧的帖子,瑞恩现在正在解决其他问题,但可能还有其他人在那里有同样的问题...

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

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