Buscar este blog

miércoles, 11 de septiembre de 2013

Audio y video con gstreamer

Una opción para la programación de audio y video en .Net es gstreamer, esta es una librería cross platform que funciona en windows, linux osx y android por lo que con el diseño adecuado tu aplicación puede funcionar en todas estas plataformas.
En cuanto a .Net el soporte se da a través de la librería gstreamer-sharp que es un binding basado en interop para acceder a las dlls nativas.
Esta librería no se encuentra en el sdk oficial pero puedes obtenerla en la pagina de ossbuild que tiene instaladores del sdk que incluyen las dlls para .Net.

Es muy fácil de usar aquí el ejemplo, unas pocas lineas de código que hacen todo:

using Gst;
 
namespace ConsoleApplication1 {
    public class PlayBinTest {
        static Element pipeline = null;
        public static void Main(string[] args) {
            Application.Init();
 
            pipeline = Gst.Parse.Launch("playbin uri=http://localhost:8000/");
            pipeline.SetState(State.Playing);
            Bus bus = pipeline.Bus;
            bus.AddWatch(EventLoop);
 
            Gst.GLib.MainLoop loop = new Gst.GLib.MainLoop();
            loop.Run();
 
            pipeline.SetState(State.Null);
            System.Console.ReadLine();
        }
        static bool EventLoop(Bus bus, Message msg) {
                switch(msg.Type) {
                    case MessageType.Eos: {
                        msg.Dispose();
                        return false;
                    }
                    case MessageType.Error: {
                        System.Console.WriteLine(msg.Structure.ToString());
                            pipeline.SetState(State.Ready);
                            pipeline["uri"] = "http://localhost:8000";
                            pipeline.SetState(State.Playing);
                        return true;
                    }
                }
            return true;
        }
    }
}

viernes, 2 de agosto de 2013

Creando sistemas de archivos con .net

Si quieres desarrollar sistemas de archivos para Linux una buena alternativa es Mono.Fuse un proyecto que usa internamente FUSE, que es la forma mas conocida de crear sistemas de archivos a nivel de usuario en Linux.

Simplemente tienes que implementar las funciones que heredas de un clase incluida en la librería y listo, por ejemplo implementas OnReadSymbolicLink para obtener la dirección a la que apunta un enlace simbólico.

miércoles, 24 de julio de 2013

Visual Studio no depura

A veces cuando queremos depurar un programa en Visual Studio 2010 el entorno no inicia la depuración, el proyecto se compila sin problemas pero el programa no inicia.
Esto puede deberse al que el proceso vshost del programa "se colgó", para solucionar esto hay que abrir el administrador de tareas y matar el proceso, después de esto se debe iniciar la depuración la próxima vez.

domingo, 30 de junio de 2013

Usando Invoke con una expresión Lambda

A veces queremos usar el método Invoke de un control o form de Windows.Forms sin llenarnos de delegados, simplemente escribir el código en el lugar donde se usa, para esto podemos debemos "castear" la expresión a un objeto Action, muy simple:



Invoke((Action)(() => {
    Close();
}));

viernes, 21 de junio de 2013

Menus en click derecho de Gkt sharp

Pues resulta que en gtk los menús no aparecen cuando se da click derecho, afortunadamente Dave Glick ha publicado esta clase para solucionarlo.
Les incluyo el código ligeramente modificado si no quieren navegar a otra pagina:


using System;
using Gdk;
using GLib;
using Gtk;
 
namespace Somedave {
    public class ContextMenuEventArgs: EventArgs {
        private Widget widget;
        public Widget Widget { get { return widget; } }
 
        private bool rightClick;
        public bool RightClick { get { return rightClick; } }
 
        public ContextMenuEventArgs(Widget widget, bool rightClick) {
            this.widget = widget;
            this.rightClick = rightClick;
        }
    }
 
    public class ContextMenuHelper {
        public event EventHandler<ContextMenuEventArgs> ContextMenu;
 
        public ContextMenuHelper() { }
 
        public ContextMenuHelper(Widget widget) {
            AttachToWidget(widget);
        }
 
        public ContextMenuHelper(Widget widget, EventHandler<ContextMenuEventArgs> handler) {
            AttachToWidget(widget);
            ContextMenu += handler;
        }
 
        public void AttachToWidget(Widget widget) {
            widget.PopupMenu += Widget_PopupMenu;
            widget.ButtonPressEvent += Widget_ButtonPressEvent;
        }
 
        public void DetachFromWidget(Widget widget) {
            widget.PopupMenu -= Widget_PopupMenu;
            widget.ButtonPressEvent -= Widget_ButtonPressEvent;
        }
 
        [GLib.ConnectBefore]
        private void Widget_PopupMenu(object o, PopupMenuArgs args) {
            RaiseContextMenuEvent(args, (Widget)o, false);
        }
 
        [GLib.ConnectBefore]
        private void Widget_ButtonPressEvent(object o, ButtonPressEventArgs args) {
            if(args.Event.Button == 3 && args.Event.Type == EventType.ButtonPress) {
                RaiseContextMenuEvent(args, (Widget)o, true);
            }
        }
 
        private bool propagating = false;   //Prevent reentry
 
        private void RaiseContextMenuEvent(SignalArgs signalArgs, Widget widget, bool rightClick) {
            if(!propagating) {
                //Propagate the event
                Event evnt = Gtk.Global.CurrentEvent;
                propagating = true;
                Gtk.Global.PropagateEvent(widget, evnt);
                propagating = false;
                signalArgs.RetVal = true;     //The widget already processed the event in the propagation
 
                //Raise the context menu event
                ContextMenuEventArgs args = new ContextMenuEventArgs(widget, rightClick);
                if(ContextMenu != null) {
                    ContextMenu.Invoke(this, args);
                }
            }
        }
    }
}

viernes, 14 de junio de 2013

Registro de errores y eventos con NLog

Es muy importante llevar un registro de eventos y errores en nuestras aplicaciones de .Net, de esta manera podemos encontrar y resolver problemas inesperados, en particular es muy útil en Asp.Net donde podemos configurar los reportes para enviar los errores por correo y percatarnos de problemas en tiempo real.
En el sitio de NLog podemos descargar el instalador o las dlls de forma gratuita ya que el proyecto es open source, para la aplicación no es necesario usar el instalador solo hace falta incluir la dll en la carpeta de los binarios.

Para desarrollar lo mas practico es usar el instalador ya que el mismo provee integración con visual studio, en nuestro proyecto elegimos añadir un nuevo archivo y escogemos un archivo de configuración de NLog, esto añadirá las referencias adecuadas y un archivo de ejemplo de configuracion de NLog.



Después en las clases en las que queremos llevar un registro creamos un objeto estático de la clase Logger, la integración con Visual Studio incluye unos snipets, por que solo escribimos nlog presionamos tab dos veces y crea el código en automático:


private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();


Ahora para mandar un mensaje cualquiera tenemos varias funciones según el nivel de importancia con que queramos que aparezca el mensaje:


logger.Info("Hola");

Este mensaje tiene un nivel de importancia solo informacional.
Una característica de NLog es que podemos mandar como parte del mensaje un excepción y según nuestra configuración el mensaje puede tener un nivel de información muy detallado incluyendo el momento, el stakctrace y cuanta información requiramos de la excepción:

logger.FatalException("Error:", exception);


Suficiente como introducción más adelante hablaremos de la configuración de NLog.

jueves, 13 de junio de 2013

Obteniendo el tiempo desde la ultima actividad del usuario en Windows

El API de Windows nos proporciona una función para determinar el tiempo desde la ultima actividad del usuario: GetLastInputInfo.
Para usarla en .Net es necesario importarla desde la dll nativa user32.dll:



[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO {
    public static readonly int SizeOf = Marshal.SizeOf(typeof(LASTINPUTINFO));
 
    [MarshalAs(UnmanagedType.U4)]
    public UInt32 cbSize;
    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dwTime;
}
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

La función importada puede ser usada para obtener por ejemplo el total de minutos que ha estado inactiva la sesión, solo funciona para sesión en que fue llamada la función:


private double GetLastInputTime() {
    uint idleTime = 0;
    LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
    lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
    lastInputInfo.dwTime = 0;
    uint envTicks = (uint)Environment.TickCount;
    if(GetLastInputInfo(ref lastInputInfo)) {
        uint lastInputTick = lastInputInfo.dwTime;
        idleTime = envTicks - lastInputTick;
    }
    TimeSpan span = new TimeSpan(0, 0, 0, 0, (int)idleTime);
    return span.TotalMinutes;
}

Hasta la próxima!

martes, 11 de junio de 2013

Cambiar de tamaño automaticamente la imagen de un Gtk.Image

A continuación les pongo el código de una clase que cambia estomáticamente el tamaño de un Gtk.Image al crear o cambiar el tamaño del objeto, es decir el equivalente a la propiedad zoom de un PictureBox de Windows.Forms.
El proceso es captar el evento expose que ocurre al cambiar de tamaño del objeto y ahí escalar la imagen usando la clase Gdk.Pixbuf para mantener la proporción de la imagen se crea el objeto dentro de un AspectFrame.

El código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gtk;
using Gdk;
 
namespace Test {
    internal class ImageResize {
        private Gtk.Image _Wrapped = null;
        private Pixbuf original = null;
        private string _File = null;
        public ImageResize(Gtk.Image wrapped) {
            _Wrapped = wrapped;
            _Wrapped.ExposeEvent += new ExposeEventHandler(ImageResize_ExposeEvent);
        }
        void ImageResize_ExposeEvent(object o, ExposeEventArgs args) {
            Pixbuf newPix = new Pixbuf(original.Colorspace, original.HasAlpha, original.BitsPerSample, _Wrapped.Allocation.Width, _Wrapped.Allocation.Height);
            double zoom = (double)((double)_Wrapped.Allocation.Width / (double)((double)original.Width));
            original.Scale(newPix, 0, 0, _Wrapped.Allocation.Width, _Wrapped.Allocation.Height, 0, 0, zoom, zoom, InterpType.Nearest);
            _Wrapped.Pixbuf = newPix;
        }
        public string File {
            get {
                return _File;
            }
            set {
                _File = value;
                original = new Pixbuf(_File);
                ImageResize_ExposeEvent(this, null);
            }
        }
    }
}

sábado, 8 de junio de 2013

Creación de eventos en c#

En c# hay varias formas de declarar un evento cada una de diferente complejidad según lo que queramos hacer, lo forma mas simple es marcar el miembro con la palabra clave event y de tipo que sea una de las múltiples clases que hay para manejar eventos puede ser interconstruida o propia de la aplicación.
Como vemos en el siguiente ejemplo también debemos declarar las clases para los argumentos si queremos pasar un valor especial al evento.



public event MyEventHandler PropertyChanged;
 
public delegate void MyEventHandler(Object sender
        , MyEventArgs e);
    public class MyEventArgs
        : System.ComponentModel.PropertyChangedEventArgs {
        public object Value { get; private set; }
        public MyEventArgs(string propertyName, object value)
            : base(propertyName) {
            Value = value;
        }
    }

Las otras formas de declarar eventos son para casos mas complejos como "eventos read only" y por lo general no se usan.

viernes, 7 de junio de 2013

Ejecutar programas desde .Net Framework

La funcionalidad para ejecutar un programa desde .Net Framework se encuentra en el espacio de nombres System.Diagnostics y es a través de las clases Process y ProcessStartInfo.
La clase Process representa un programa en ejecución y ProcessStartInfo los parámetros con que se ejecuta el proceso entre otros: el nombre del programa, si se redirecciona la entrada y salida estándar, si se va a crear una ventana para el programa, el directorio de trabajo etc.
La forma en que se crea un proceso es usar el método  Start de la clase Process, ya sea el miembro estático con alguna de sus sobrecargas, para crear un nuevo objeto, o el miembro de instancia para usar un objeto construido previamente.
Las diferente sobrecargas nos sirven para ejecutar un programa indicando sus opciones directamente o usando un ProcessStartInfo para indicarlas, esta opción es la que nos permite mas flexibilidad.
En particular la opción  UseShellExecute es ideal para programas de linea de comandos.

A continuación el ejemplo:


using System;
using System.Diagnostics;
 
public class Class1
{
    public void StarP() {
        ProcessStartInfo stInfo = new ProcessStartInfo("prog.exe");
        stInfo.UseShellExecute = false;
        Process proc = Process.Start(stInfo);
        proc.WaitForExit();
    }
}

jueves, 6 de junio de 2013

Gestionar excepciones de manera global en Asp.Net

Asp.Net tiene una forma de pescar cualquier excepción que ocurra en el sitio de forma centralizada.
En efecto lo único que tenemos que hacer es implementar el metodo Application_Error del archivo Global.asax en un sitio web y este se ejecutara cada vez que ocurra una excepción no controlada en la aplicación.
La excepción que ocurrió esta disponible accesando la función Server.GetLastError().
Por ejemplo podemos capturar la excepción y reportarla usando nlog, mandarla por email, etc.

lunes, 3 de junio de 2013

Agregar Web Services en Visual Studio 2008 en adelante

En las versiones mas recientes de Visual Studio no se tiene la opción directa para añadir Web Services al proyecto, lo que se tiene es la opción de agregar referencias de servicios, estos servicios son los creados con WCF y aunque se puede usar un Web Service antiguo con WCF en ocasiones podemos necesitar un Web Service sin usar WPF por ejemplo si no queremos incluir la referencia a esos componentes en el proyecto.
En estos casos podemos incluir el Web Service siguiendo estos pasos.
Se selecciona agregar referencia de servicio como si fuéramos a agregar un servicio WCF.
En esta ventana seleccionamos el botón "Avanzadas..."



En la ventana que aparece seleccionamos "Agregar referencia web..."


Y finalmente nos aparece la pantalla para agregar un Web Service "clásico"



domingo, 2 de junio de 2013

Obteniendo el texto de un PDF en .Net

PdfBox es una librería que permite entre otras cosas obtener el texto de un pdf, este software es para java pero se puede usar en gracias a IKVM que permite convertir archivos de java en dlls.

El ejemplo:


using org.pdfbox.pdmodel;
using org.pdfbox.util;
using System;
 
public class GetText() {
    public string Retrieve(string fileName) {
        PDDocument doc = PDDocument.load(fileName);
        PDFTextStripper stripper = new PDFTextStripper();
        return stripper.getText(doc);
    }
}

PDFBox se puede obtener en esta página: http://www.squarepdf.net/pdfbox-in-net/

sábado, 1 de junio de 2013

Gtk Builder en .Net

Gtk Builder es la forma mas moderna de crear interfaces en gtk por medio de un editor WYSIWYG, es mas completo que stetic y el editor no truena en cada paso.
Es posible usar GTK.Builder en proyectos .Net o Mono pero la documentación es practicamente inexistente de hecho yo aprendi a usarlo en un sitio de Python pues como siempre la gente de mono tiene el proyecto completamente descuidado.
Lo básico es crear el objeto cargar el archivo xml que creamos con el programa Glade (que también funciona en Windows) obtener la ventana que queremos usar y mostrarla, es mejor crear una ventana por archivo pues despues nos puede dar problemas encontrar objetos con el mismo identificador.
Tambien debemos escribir un poco de código para poder usar los objetos que contiene el archivo ya que no hay forma de cargarlos automaticamente, solo buscamos el objeto dentro del Builder y lo asignamos a una variable de la clase.
Para las señales (eventos) lo mejor es usar las referencias que encontramos en el paso anterior y asignar los eventos directamente ya que aunque hay una función para conectar los eventos es complicada y de todos modos ya tenemos las referencias así que es más facil hacerlo de esta manera.
A continuación el codigo de ejemplo:

<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy toplevel-contextual -->
  <object class="GtkWindow" id="window1">
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="xalign">0</property>
            <property name="label" translatable="yes">label</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">button</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="yalign">0</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
 
using System;
using Gtk;
 
namespace GTKBuilder {
    class MainClass {
 
        Window thisWnd = null;
        Builder thisObject = null;
        Button button1 = null;
        Label label1 = null;
 
        public static void Main (string[] args) {
            Application.Init ();
            MainClass tester = new MainClass();
            tester.Show();
            Application.Run ();
        }
 
        MainClass() {
            InitializeComponent();
        }
 
        private void InitializeComponent(){
            thisObject = new Gtk.Builder();
            thisObject.AddFromFile("tester.glade");
            thisWnd = (Window)thisObject.GetObject("window1");
            label1 = (Label)thisObject.GetObject("label1");
            button1 = (Button)thisObject.GetObject("button1");
            button1.Clicked += (object sender, EventArgs e) => {
                label1.Text = "Hello";
            };
            thisWnd.DeleteEvent += (o, args) => {
                Application.Quit();
            };
        }
 
        public void Show() {
            thisWnd.ShowAll();
        }
    }
}

lunes, 27 de mayo de 2013

Mandar correos desde .Net Framework

En .Net Framework es posible mandar correos usando la clase SmtpClient esta funcionalidad se encuentra en los espacios de nombre System.Net y System.Net.Mail, se pueden mandar correos en formato de texto o html e incluir archivos adjuntos, es muy sencillo, a continuación el ejemplo:


public void SendMail() {
    SmtpClient sender = new SmtpClient("127.0.0.1", 25);
    sender.Credentials = new NetworkCredential("usr", "Password");
    MailMessage message = new MailMessage("from@localhost", "to@localhost");
    message.Subject = "Mail test";
    message.Body = "This is a test";
    message.IsBodyHtml = true;
    mailer.Send(message);
}
 
Hasta la proxima!

domingo, 26 de mayo de 2013

Obtener la localización de usuarios web con GeoIP

En .Net tenemos la posibilidad de obtener la localización de nuestros usuarios usando las bases de datos y clases que proporciona MaxMind de manera gratuita, hay dos versiones de las bases de datos, para localizar el país, y para encontrar datos hasta el nivel de ciudad, las diferencia es que la base de datos de países es mucho mas pequeña pero en la versión de ciudades también podemos obtener también el país pero además la zona, la ciudad el código postal y otros datos.
Para usarla hay que copiar el archivo de datos a una carpeta accesible por nuestra aplicación, instanciar la clase LookupService y llamar sus métodos basandonos siempre en la ip del cliente.
La única inconveniencia es que las clases no vienen en formato binario, pero es cuestión de minutos compilarlas y añadirlas a nuestros proyectos.
A continuación un ejemplo muy simplificado de su uso en Asp.Net:


public void Detect() {
    LookupService ls
        = new LookupService(Server.MapPath("/GeoLiteCity.dat")
        , LookupService.GEOIP_STANDARD);
    Location loc
        = ls.getLocation(Request.UserHostAddress);
    Response.Write(loc.regionName);
}

sábado, 25 de mayo de 2013

Trucos de rendimiento en linq

Usar linq es muy tentador por la forma en que hace fácil escribir código sobre colecciones de valores ya sea en objetos, xml, sql o cualquier otra forma de agrupar valores, sin embargo hay que tener mucho cuidado con su uso ya que podemos caer en trampas que hacen el código muy lento, por ejemplo: en linq a objetos es muy fácil crear una expresión que busque un objeto con un determinado valor en una propiedad, sin embargo la trampa es que linq recorre toda la colección y compara objeto por objeto con el valor buscado, en colecciones pequeñas esto no es un problema pero si manejas un número de objetos significativo tu programa se puede alentar bastante, una posible solución es usar un árbol e indizarlo usando la propiedad que vas a buscar con lo que el rendimiento puede mejorarse incluso en varios de magnitud.
Otro ejemplo linq a xml, en este caso el problema es que el xml se almacena por completo en memoria, siendo una vez mas un problema con archivos grandes que nos pueden usar hasta gigabytes de memoria para archivos de solo unos megas, en estos casos puede convenir mas usar el xmlreader que lee los elementos uno por uno desde el stream y luego los descarta usando por lo tanto poquísima memoria.

Por supuesto las necesidades de cada programa varían y puedes encontrarte en que no tengas otra solución que usar linq.

jueves, 7 de febrero de 2013

Mostrando ayuda chm en Windows Forms

En windows forms hay una clase especial para mostrar ayuda desde archivos chm para nuestra aplicación esta clase es System.Windows.Forms.Help y es una clase estatica muy fácil de usar basta llamar a uno de los métodos ShowHelp con los parámetros adecuados es decir la dirección del archivo y opcionalmente una dirección de navegación que nos mostrara la ayuda en la posición adecuada.
Para mostrar la ayuda en su inicio:

 Help.ShowHelp(this, "Desktop.chm");

Y para mostrarla en la pestaña de busqueda (sin palabra clave indicada):

 Help.ShowHelp(this, "Desktop.chm", HelpNavigator.Find, "");

jueves, 31 de enero de 2013

Usando c# en xslt

En .Net el soporte de xslt se limita a la version 1 y no parece que esto vaya a cambiar pronto asi que estamos muy limitados en cuanto a lo que se puede hacer: hay pocas funciones y no se pueden declarar funciones nuevas.
Afortunadamente Microsoft incluyo soporte para crear funciones nuevas funciones en cualquier lenguaje de .Net esto es a través del elemento <msxsl:script />
En el ejemplo creamos la función Trim que no tiene equivalente en xslt (aunque normalize-space se parece)
Hay que recordar que esto solo se soporta en m$, si vas a usar tu xslt con otras aplicaciones no va a funcionar.
Para activarlo con la clase  XslCompiledTransform se debe cargar el xslt con un objecto XsltSettings con la propiedad EnableScript en true:
XsltSettings xsltSettings = new XsltSettings();
xsltSettings.EnableScript = true;
XslCompiledTransform transform = new XslCompiledTransform(false);
transform.Load(styleSheet, xsltSettings, new XmlUrlResolver());



<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="msxsl"
    xmlns:user="urn:my-scripts"
>
    <msxsl:script language="C#" implements-prefix="user">
        <![CDATA[
            public string Trim(string input) {
                return input.Trim();
            }
        ]]>
    </msxsl:script>
    <xsl:output method="xml" indent="yes"/>
 
    <xsl:template match="/">
        <NewRoot>
            <xsl:for-each select="OldValues/OldValue">
                <NewValue>
                    <Id>
                        <xsl:value-of select="user:Trim(Id)"/>
                    </Id>
                </NewValue>
            </xsl:for-each>
        </NewRoot>
    </xsl:template>
</xsl:stylesheet>