2011-05-23 9 views
5

Parece trivial, pero la respuesta se me escapa por unos días.Cambiando las variables de entorno del proceso de llamada

Tengo un archivo por lotes de Windows que llama a un programa C# para realizar una verificación adicional que no se puede realizar en un archivo por lotes. Una vez completada la verificación, debo devolver un estado y una cadena al shell de llamada.

Ahora el valor de retorno es trivial y mi aplicación de consola C# simplemente establece un valor de retorno (código de salida si lo desea). Y pensé que la cuerda también sería un pedazo de pastel. Me trató de definir una nueva variable de shell mediante el:

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

Esta llamada debe (y lo hace) definir una variable de entorno dentro del proceso actual - que es el proceso de C# que creó el muy variable. El valor se pierde tan pronto como finaliza la aplicación C# y el shell que creó la aplicación C# no sabe nada sobre la variable. Entonces ... Una llamada sin un uso particular ... En absoluto ... A menos que tal vez si crease un proceso hijo desde la aplicación C3, tal vez heredaría mis variables.

Los objetivos EnvironmentVariableTarget.Machine y EnvironmentVariableTarget.User para la llamada SetEnvironmentVariable tampoco resuelven el problema, ya que solo un proceso creado recientemente obtendrá estos nuevos valores del registro.

Así que la única solución de trabajo que se me ocurre es:

  • de escritura a la salida estándar
  • escribir en un archivo
  • codificar significado adicional en el valor de retorno

Los dos primeros son un poco feos y el último tiene sus limitaciones y problemas.

¿Alguna otra idea (cómo establecer una variable de shell en el proceso principal)? Tal vez tales modificaciones de la variable de shell son un problema de seguridad (piense en PATH) ...

Gracias por su tiempo.

Respuesta

0

Mi BAT está un poco oxidado, pero creo que es posible recuperar el código de 'salida' de procesos que ha ejecutado externamente, quizás a través de %ERRORLEVEL%. Si ese es el caso, asegúrese de salir de su programa a través de

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

No se puede agregar cualquier mensaje, por lo que tendrá que hacer eso en el archivo .bat.

Si este no es el caso, stdout es probablemente la mejor manera.

+0

Eso es cierto. El resultado de una aplicación de consola generalmente se devuelve a través del código de retorno. Aparentemente el 'Environment.Exit()' es un poco áspero en el marco ... por lo que un simple 'return x' es el método preferido. Sin embargo, me preguntaba si hay un método en el que podría insertar ** otro valor ** en el entorno del shell primario. Por ejemplo, la explicación del código de error 123 en forma de una cadena ... estoy usando la salida estándar en este momento ... redirección a un archivo, lo leyó de nuevo a una concha var, borrar el archivo ... Ligeramente sucio, pero funciona. – JamesH

1

Si usted quiere poner un valor de alguna salida en una variable en el lote puede utilizar la construcción siguiente:

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

de salida en mi sistema operativo:

6.1.7601 

significa 'usebackq' estamos utilizando citas entre comillas, lo que nos da la posibilidad de utilizar un conjunto de archivos en el comando citado con comillas dobles. Puede que no necesites esto. 'tokens' significa el índice en la matriz de cadenas resultante para seleccionar (puede ser un rango M-N). Si necesita saltear líneas, use 'skip = X').'delims' son los separadores de cadenas que se usan (como string-Split() en .Net).

Pondrá su aplicación de consola en lugar de 'ver' y adaptará los delimitadores y tokens para que coincidan con su salida específica. Si tiene más variables para completar necesitará hacerlas un poco más complejas, pero eso debería hacer un buen comienzo.

2

Lo que está pidiendo es poder escribir arbitrariamente en el espacio de la memoria de un proceso en ejecución. Por una buena razón, esto no es posible sin SeDebugPrivilege.

Cualquiera de las tres soluciones que enumere funcionará. Stdout es la forma estándar de comunicarse con un script por lotes.

Por cierto, está escribiendo un archivo por lotes de Windows. Estoy bastante seguro de que el barco ya navegó "un poco feo".

3

que tenían el mismo problema que Ryan y la única cosa que me vino a la mente como una solución temporal era escribir un lote por error a cabo para establecer la variable y llamarlo a partir del lote.

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 (el lote que llama):

@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 

Que debe hacer el truco. Y sí, sé que esta es una publicación anterior y Ryan está solucionando otros problemas hasta ahora, pero puede que todavía haya alguien más que tenga el mismo problema ...

0

Después de tropezar con esto yo mismo también recientemente, se le ocurrió este enfoque. Lo que hice es ejecutar el archivo del palo usando la clase de proceso, es decir

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

Esto parece haber funcionado para mí. No es el enfoque más limpio, pero funcionará en un aprieto. :)

Cuestiones relacionadas