Retrieve return value from executable inside a C# application

C#, English No Comments »

Recently, I encountered some difficulties trying to read the return value from an executable file. I’m was trying to call SpamAssassin from within a C# console application and couldn’t retrieve it’s return value. Since the exit code indicates whether an email is spam or ham, I had to find a way to receive that value. After struggling a bit, I found out that instead of calling directly SpamAssassin, I had first to call cmd.exe and handle it, as an argument, the path to the SpamAssassin executable. The code ended as following:

Process p = new Process();
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.Arguments = @" /C C:\spamassassin.exe -e -L < C:\SPAM_TEST.MAI";
p.StartInfo.FileName = @"C:\WINDOWS\System32\cmd.exe";
p.OutputDataReceived += (sender, arguments) => Console.WriteLine("Received output: {0}", arguments.Data);
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
Console.WriteLine("Exit code: " + p.ExitCode);
p.Close();

Here is a screenshot of the console after calling cmd.exe with a ping command:

launch_exe_from_console

DotNetWinService versión 1.0.0.0 liberado

DotNetWinService No Comments »

Acabo de liberar la versión 1.0.0.0 de DotNetWinService en codeplex. Escogí codeplex porque su navegador de código fuente es bastante práctico y claro para consultar archivos del proyecto:

DotNetWinServiceCodePlexBrowsesource

Navegador de archivos fuentes

DotNetWinService es una mezcla de varias tecnologías entras las cuales se encuentran log4Net, Spring.NETQuartz.NET. Permite implementar de forma declarativa (con XML) tareas programadas adentro de un servicio Windows. Las tareas se definen adentro del archivo spring-objects.xml:

Archivo spring-context.xml

Archivo spring-objects.xml

Existen, por lo pronto, 4 tipos de tareas disponibles:

TaskURL, para ejecutar una petición HTTP: cuando se trabaja sobre un sitio web en ASP.NET, a veces conviene mejor mantener toda la lógica de negocio adentro de una página que se ejecuta en un intervalo regular. Puede servir para generar un reporte y mandarlo por correo una vez por semana por ejemplo.

TaskEXE, para ejecutar un archivo EXE o BAT: éste procesa se carga solamente si es el único cargado en memoria, no pueden existir varias instancias del mismo proceso corriendo al mismo tiempo. Puede servir para realizar tareas más pesadas como procesar imágenes o generar reportes que ocupen más tiempo de computación.

TaskMethod, para disparar un método adentro de un assembly: solamente se soportan tipos primitivos y cadenas (System.String). En lugar de tener un archivo EXE, se carga el assembly en memoria, y mediante reflexión, se ejecuta un método (estático o de instancia).

TaskMethodInterop, para intercambiar datos entre dos métodos en el mismo assembly o en assemblies diferentes: el valor de retorno del primer método se convierte en el valor de entrada del segundo método. El parámetro es de tipo System.String.

El proyecto está desarrollado con C# y Visual Studio 2008. No duden en comentar o en aportar código.

No olvide especificar ImageFormat al guardar una imagen en C#

C# No Comments »

Ya que las imágenes son recursos generalmente pesados, siempre hay que poner mucha atención al manipularlas. Me di cuenta de lo anterior al generar thumbnails a partir de imágenes de una galería web. La primera versión de mi código era la siguiente:

Image imagenFormatoOriginal = Image.FromFile(Directory.GetCurrentDirectory() + "//test.jpg");
Image imagenFormatoThumb = imagenFormatoOriginal.GetThumbnailImage(1000, 1000, null, IntPtr.Zero);
imagenFormatoOriginal.Dispose();
imagenFormatoThumb.Save("test_thumbnail.jpg");

La imagen original pesa 1,002 KB y tiene dimensiones de 4096 por 6144 pixeles. La imagen thumbnail generada pesa 361 KB con dimensiones de 1000 por 1000. La nueva imagen representa un 36.02% del peso de la imagen original. Puede parecer un buen ratio pero en una galería de cientos de imágenes cada byte se vuelve importante tanto para el disco duro como para el ancho de banda. En el siguiente código, especificamos el formato en el cual deseamos crear el thumbnail:

Image imagenFormatoOriginal = Image.FromFile(Directory.GetCurrentDirectory() + "//test.jpg");
Image imagenFormatoThumb = imagenFormatoOriginal.GetThumbnailImage(1000, 1000, null, IntPtr.Zero);
imagenFormatoOriginal.Dispose();
imagenFormatoThumb.Save("test_thumbnail_con_formato.jpg", ImageFormat.Jpeg);

Ahora, la imagen thumbnail generada pesa 29KB y tiene dimensiones de 1000 por 1000 pixeles, lo cual representa un 0,34% del peso de la imagen original ¿Que estará suciediendo? El artículo de MSDN sobre el método ‘Save’ indica que cuando no se especifica ningún codificador, se ocupa por default el codificador del formato de gráficos de red portátiles (PNG/Portable Network Graphics). Creo que sería un mejor diseño obligar el programador a escoger siempre el formato en el cuál desea guardar su imagen o que el método ‘Save’ trate de adivinar el formato de la imagen al guardarla. Si examinamos el header de nuestros dos thumbnails generados corroboramos lo anterior. El thumbnail generado sin formato tiene un header específico del formato PNG:

Imagen en formato PNG

Imagen en formato PNG

En cambio, el header de la segunda imagen presenta las características del formato JPG, mucho más compacto y de menor calidad que PNG:

Imagen en formato JPG

Imagen en formato JPG

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in