Changing environment variables of the calling process

我与影子孤独终老i 提交于 2019-11-29 10:50:52

I had the same problem as Ryan and the only thing that came to my mind as a work-around was to write a batch in error out to set the variable and to call it from the batch.

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 (the calling batch):

@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

That should do the trick. And yes, I do know this is an old post and Ryan is solving other issues by now, but there might be still somebody else out there having the same problem...

What you are asking is to be able to arbitrarily write to the memory space of a running process. For good reason, this is not possible without SeDebugPrivilege.

Any of the three solutions you list will work. Stdout is the standard way to communicate with a batch script.

By the way, you're writing a Windows batch file. I'm pretty sure the ship has already sailed on "a bit ugly".

If you want to put a value of some output into a variable in the batch you can use the following construct:

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

Output on my OS:

6.1.7601

'usebackq' means we are using back quotes which gives the ability to use a fileset in the command quoted with double quotes. You may not need this. 'tokens' means the index in the resulting string array to select (it can be a range M-N). If you need to skip lines use 'skip=X'). 'delims' are the string separators to use (like string-Split() in .Net).

You will put your console app instead of 'ver' and adapt the delimiters and tokens to match your specific output. If you have more variables to fill you will need to make the if a bit more complex but that should make a good start.

My BAT is a bit rusty, but I think it's possible to retrieve the 'exit' code from processes you've run externally, perhaps via %ERRORLEVEL%. If that's the case, make sure to exit your program via

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

You can't add any messages, so you'll have to do that in the .bat file.

If this isn't the case, stdout is probably the best way.

After stumbling on this myself as well recently, I came up with this approach. What I did is run the bat file using the Process class, i.e.

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

This seems to have worked for me. It's not the cleanest approach, but will work in a bind. :)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!