Asistente P/Invoke Interop

Si trabajas con p/invoke tanto habitual como eventualmente y pinvoke.net esta en tus bookmarks… esta herramienta no te va a dejar indiferente 😀 Leo en el blog del BCL Team:

El equipo Interop ha publicado recientemente una nueva herramienta llamada P/Invoke Interop Assistant. Esta herramienta genera automáticamente las declaraciones en C# ó VB.NET de las llamadas p/invoke nativas. Incluye una búsqueda rápida por las librerias comunes Win32 y permite generar las declaraciones para cualquier otra libreria nativa simplemente pasando la firma nativa. Esto hace mucho más facil trabajar con interop correctamente, sin tener que comprender todas las reglas y atributos usados cuando «conecta» el desarrollo administrado y no administrado. `

image

La herramienta fue publicada en MSDN Magazine como parte del artículo Marshaling between Managed and Unmanaged Code en Enero. Ahora esta en CodePlex junto al código fuente. Altamente recomendado echarle un ojo!!

Impresionante!! La estoy usando y me va a ahorrar mucho tiempo en búsquedas 😀 Obviamente, no va a substituir a pinvoke.net porque dicha web tiene algo muy importante, ejemplos y tips (que habría sido de mi sin esta web estas dos semanas…), mientras que este programa solo te proporciona las firmas… pero esta claro que es una herramienta indispensable si se trabaja con interop 🙂

Asistente P/Invoke Interop | vtortola.NET

Recursividad y yield return. Haciendo queries a colecciones en arbol en C# 2.0

Estoy disfrutando de lo que será mi último proyecto en C# 2.0 y .NET 2.0 antes de pasar a WPF, y la verdad es que se hace amargo algunas veces cuando ya conoces C# 3.0, por ejemplo se hecha de menos LINQ 😀

En este artículo quiero demostrar como hacer queries a una colección de elementos en forma de arbol desde C# 2.0, de forma que se pueda definir el tipo de colección, criterio de búsqueda que se quiere usar y obtener los resultado conforme se vayan obteniendo.

Una función recursiva, es una función que se llama a si misma y controla cuando parar de hacerlo mediante una condición. Si esa condición no esta bien definida… a parte del cuelgue del hilo en cuestión lo más posible será terminar recibiendo una sonora StackOverflowException.

Para recorrer una estructura en arbol nada mejor que una función recursiva, un ejemplo muy simple es esta función que recorre todos los controles hijos de un control dado recursivamente:

/// <summary>
/// Recorre recursivamente todos los
/// controles hijos de un control dado.
/// </summary>
void lookRecursive(Control Parent)
{
    // Recorro los subnodos
    foreach (Control child in Parent.Controls)
    {
        Debug.Print(child.Name);
 
        // Si el subnodo tiene más subnodos
        // ejecuto recursivamente.
        if (child.Controls.Count > 0)
            lookRecursive(child);
    }
}

Podemos hacer que la función nos devuelva un elemento introduciendo una variable para el almacenamiento, si por ejemplo lo que queremos es que encuentre un determinado control por su nombre y lo devuelva (ya hay un método por ahí por la BCL que lo hace):

/// <summary>
/// Recorre recursivamente todos los
/// controles y encuentra el de un nombre
/// determinado.
/// </summary>
Control findControl(Control Parent, String Name)
{
    Control temp=null;
    // Recorro los subnodos
    foreach (Control child in Parent.Controls)
    {
        // Criterio de búsqueda
        if (child.Name == Name)
            temp = child;
        else if((temp==null) && (child.Controls.Count > 0))
            temp = findControl(child,Name);
    }
    return temp;
}

Ahora vamos a complicarlo un poco más añadiendo las siguientes características:

  • Adaptable a cualquier tipo de objetos: Usando genéricos.
  • Definir nuestro propio criterio de búsqueda: Pasando un Predicate como argumento que contenga el criterio.
  • Definir como se obtienen los sub-nodos: Pasando un delegado que lo especifique.
  • La posibilidad de que el resultado no sea único: Devolviendo una colección ó array.
  • Poder parar de recorrer cuando encontremos lo que queremos: Que la colección devuelta sea IEnumerable ó IEnumerable<T>y devolver con yield.

Asi queda:

delegate IEnumerable getChilds<T>(T Element);
IEnumerable<T> findRecursive<T>(T Parent, getChilds<T> Elements, Predicate<T> Criteria)
{
    foreach (T element in Elements.Invoke(Parent))
    {
        if (Criteria.Invoke(element))
            yield return element;
 
        foreach (T element2 in findRecursive<T>(element,Elements, Criteria))
            yield return element2;
    }
}

El delegado getChilds define como obtener subnodos de un nodo dado.

Nota: En este ejemplo, en el delegado devuelvo IEnumerable y no IEnumberable<T> (que seria lo lógico) porque Control.Controls es un ControlCollection que solo implementa dicha interfaz, no la genérica 😛

Para usarlo… por ejemplo, queremos que todos los paneles pasen a tener borde FixedSingle:

// Defino el criterio de búsqueda,
// en este caso, quiero los controles
// que sean paneles.
Predicate<Control> lookForPanels = delegate(Control c)
{
    return c is Panel;
};
 
// Defino como obtengo los hijos de 
// este tipo de objeto.
getChilds<Control> getChildControls = delegate(Control C)
{
    return C.Controls;
};
 
// Por último efectuo la búsqueda
// y obtengo los resultados.
foreach (Panel c in findRecursive<Control>(this, getChildControls, lookForPanels))
{
    c.BorderStyle = BorderStyle.FixedSingle;
}

Y si se quiere más complejo también se puede recorrer una estructura en arbol con múltiples hilos😛

Recursividad y yield return. Haciendo queries a colecciones en arbol en C# 2.0 | vtortola.NET

Listo para empezar a trabajar en Dublin

datakraftBueno pues las vacaciones se acaban y es la hora de volver a trabajar y a .NET 😀 El próximo día 23 me incorporo a Datakraft en Dublín como desarrollador y debo confesar que estoy bastante excitado con el tema, voy a tener la oportunidad de sumergirme en .NET 3.5, desarrollo Windows/web/back-end y metodologías ágiles.

Con esto completo mi instalación en Dublín al 100%, después de 2 meses y medio aprendiendo inglés en el LCI, encontrar casa y encontrar trabajo. Otro día contaré como ha sido el proceso a grandes rasgos, pero desde luego ha sido una aventura desde el primer día y sin lugar a dudas considero que fué una buena decisión, no solo por aprender inglés, si no por conocer gente de todo el mundo y la aventura del día a día defendiendote con lo poco que hablas y lo menos que entiendes. Ahora no hablo un inglés para tirar cohetes, pero suficiente para defenderme en el día a día (pero aún no entiendo Los Simpson en inglés xD), espero que en un par de años hablar y entender sin ningún tipo de problemas.

Desde aquí me gustaria agradecer a mis antiguas empresas Avanade y Experian por prestarse a dar referencias a mi nueva empresa sobre mi y a mi ex-compañero de Avanade Gerardo K. por prestarse a escribir una referencia técnica recomendándome.

Ahora una semana para España… que echo de menos muchas cosas… 🙂

Listo para empezar a trabajar en Dublin| vtortola.NET

Pooling de llamadas asincronas

Hora de volver a trabajar… asi que toca quitarle el polvo al Visual Studio que tenia abandonado ya estos meses, la buena vida se acaba… xD

En determinadas ocasiones, necesitamos lanzar un cierto número de ejecuciones en paralelo y esperar a que terminen todas para devolver el resultado final. Existen diversas formas de hacerlo, y yo voy a poner la que, después de darle un par de vueltas… me parece la mejor y más sencilla, … se puede hacer aún mejor, pero no se si más sencilla… y no se si lo que se puede mejorar merece la pena en cuanto a la complejidad que añade.

Un ejemplo práctico, este método pertenece a una clase que estoy programando para realizar pruebas de estres y carga, la clase tiene una lista de clientes y cuando se ejecuta esta función ejecuta el delegado que se pasa como argumento en paralelo en todos los clientes a la vez, recolecta las excepciones capturadas y las devuelve como una lista. Por supuesto, tiene que esperar a que terminen todas las pruebas en paralelo para poder devolver la lista 😛

private List<Exception> test(Int32 Times, Int32 Interval, TestDlg_ Test)
{
    List<Exception> errors = new List<Exception>();
    List<IAsyncResult> working = new List<IAsyncResult>();
 
    lock (working) // Bloqueo hasta que lanze todos los clientes
    {
        foreach (IImApplicationClient client in this.Clients)
        {
            working.Add(Test.BeginInvoke(client, Times, Interval,
                delegate(IAsyncResult IA)
                {
                    try
                    {
                        Test.EndInvoke(IA);
                        lock (working)
                        {
                            working.Remove(IA);         // Lo elimino de la lista,
                            if (working.Count == 0)     // y si era el último...
                                Monitor.Pulse(working); // envio pulso para liberar
                        }                               // la espera
                    }
                    catch (Exception ex)
                    {
                        IImApplicationClient asynClient =
                            IA.AsyncState as IImApplicationClient;
                        lock(errors)
                            errors.Add(new Exception
                                (client != null ? asynClient.Id : "Id unknown.", ex));
                    }
                }, client));
        }
 
        if (working.Count > 0) // Si se han lanzado clientes...
            Monitor.Wait(working); // bloqueo en espera.
    }
 
    return errors;
}

El planteamiento es el siguiente:

  • Se usa una lista para tener controladas las llamadas asíncronas.
  • Cada vez que se lanza una llamada asíncrona, el IAsyncResult resultante se añade a la lista.
  • Se bloquea la lista hasta que todas han sido lanzadas, y si se ha lanzado más de una, se ejecuta un Monitor.Wait para que se detenga la ejecución ahí hasta que se realize un Monitor.Pulse.
  • Cada vez que una llamada asíncrona termina, se elimina su IAsyncResult de la lista.
  • Si el IAsyncResult es el último que quedaba, se realiza un Monitor.Pulse para que la ejecución pueda seguir puesto que ya finalizaron todas las llamadas asíncronas.

Sugerencias, como siempre, bienvenidas 😀

Pooling de llamadas asincronas| vtortola.NET

Visual Basic .NET vs C# .NET: ¿Cual es mejor y por que?

Hoy Second Nug tiene el honor de presentar a dos ponentes de excepción, Guillermo Som (el Guille) y Marino Posadas (el Ave Fénix), en la que será una gran batalla donde dos voces con gran experiencia expondrán sus mejores bazas en un duelo sin igual: VB .NET vs C# .NET.
Sabremos por qué se decantaron por un lenguaje u otro y nos presentarán su evolución en las nuevas versiones del .NET Framework. Nos desvelaran secretos y trucos de sus defendidos y veremos si es cierto aquello de que lo que se puede hacer con uno, se puede realmente hacer con el otro.
Además los asistentes podrán resolver sus dudas preguntando a nuestros expertos y participar en el resultado final de la contienda.
El eterno dilema al descubierto. ¿Quién será el vencedor?

El evento será a las 19:30 – 21:30 (GMT+2), y como en las anteriores ocasiones, se retransmitirá vía Web a través de Live Meeting.

Si no tienes Live Meeting, puedes descargarlo en el siguiente enlace.

Podéis registraros en el evento en el siguiente enlace.

Trabajando con el registro de Windows desde C# y .NET

Manejar el registro de Windows es algo… en parte tedioso por lo extenso y medianamente documentado que esta lo que contiene. En mi humilde opinión, es algo a evitar siempre que sea posible en virtud de los archivos de configuración; pero en ocasiones necesitamos crear/modificar entradas que afectan al funcionamiento de otros programas ó del propio Windows desde nuestras aplicaciones, asi que hay que arremangarse y meterle mano 😀

Primero un pequeño repaso de como se estructura la información a grandes rasgos. Podemos ver el registro mediante la aplicación regedit.exe. Encontramos 5 elementos principales, que así por encima vienen a ser:

  • HKEY_CLASSES_ROOT (HKCR) : Contiene las realciones entre los identificadores de programa y clases que se usan por COM+, asociaciones de archivo e información de ejecución de aplicaciones.
  • HKEY_USERS (HKU) : Contiene un elemento por cada usuario del sistema y en cada uno se almacenan sus preferencias y configuraciones individuales.
  • HKEY_CURRENT_USER (HKCU) : Es como un enlace simbólico a la entrada en HKU correspondiente al usuario actual.
  • HKEY_LOCAL_MACHINE (HKLM) : Información del sistema y del hardware.
  • HKEY_CURRENT_CONFIG (HKCC) : Es como un enlace simbólico a la entrada en HKLM correspondiente a la configuración hardware actual.

La información esta estructurada en forma de arbol mediante claves y valores. Las claves son como carpetas que puede contener otras claves, y los valores son una pareja key-value donde podemos asignar un valor. Los valores pueden ser de tipo:

  • REG_DWORD : Número de 4 bytes, se usa para almacenar valores boleanos.
  • REG_BINARY : Almacena datos binarios.
  • REG_SZ : Cadena de texto.
  • REG_MULTI_SZ : Almacena arrays de strings.
  • REG_EXPAND_SZ : Almacena una variable en formato de string.

Ahora vamos a meterle mano, lo primero que necesitamos es el namespace Microsoft.Win32 , y nuestras clases para trabajar serán RegistryRegistryKey. Lo primero, es llegar donde vamos a trabajar:

 

// Abrimos la clave del registro con la que queremos trabajar
RegistryKey rk1 = Registry.LocalMachine;
 

Trabajando con claves:

// Nos movemos hasta la subclave donde queremos trabajar.
// El parámetro boleano indica si la abrimos en solo lectura (false)
// ó en lectura/escritura (true).
rk1 = rk1.OpenSubKey(@"SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon",true);
 
// Si devuelve null es que la clave no existe
if (rk1 == null)
    Console.WriteLine("No existe esa clave");
 
// Crear una nueva clave
// El método devuelve un RegistryKey apuntando
// a la nueva entrada.
RegistryKey rk2 = rk1.CreateSubKey("Prueba");
 
// Obtener todas las subclaves contenidas en esta:
String[] subKeys = rk1.GetSubKeyNames();
 
// Borrar una clave vacia:
rk.DeleteSubKey("Prueba");
                
// Borrar una clave recursivamente:
rk.DeleteSubKeyTree("Prueba");
 

Trabajando con key-values:

// Crea un key-value indicando su nombre, valor y tipo:
rk2.SetValue("ValorPrueba", 0,RegistryValueKind.String);
 
// Obtener todos los nombres de key-values que hay en una clave:
String[] values = rk2.GetValueNames();
 
// Obtener el valor de un key-value:
Console.WriteLine(rk2.GetValueKind("ValorPrueba").ToString());
 
// Obtener el tipo de dato de registro 
// que contiene un key-value:
RegistryValueKind rvk = rk2.GetValueKind("ValorPrueba");
 
// Borrar un key-value:
// El parámetro boleano indica que salte una excepción
// si el key-value a borrar no existe.

rk2.DeleteValue("ValorPrueba", true);

 

Aunque los Setup Project que creamos con Visual Studio tiene capacidad para añadir claves y key-values al registro, su funcionalidad esta muy limitada, por ejemplo… no podriamos crear un key-value que contuviese el path de la aplicación que estemos instalando a no ser que lo pusieramos harcodeado.

 

Trabajando con el registro de Windows desde C# y .NET | vtortola.NET

Evento: Windows Communication Foundation al Descubierto en SNUG

El próximo 1 de Abril podréis asistir a un nuevo Webcast en el que podréis sacar el máximo provecho de sistemas, tanto nuevos como ya existentes, a través de Windows Communication Foundation. Para esta nueva charla, contaremos con la presencia de Hadi Hariri como ponente de excepción, que nos deleitará con todo lo que esta nueva herramienta nos puede ofrecer.

El evento será a las 19:30 – 21:30 (GMT+1), y como en las anteriores ocasiones, se retransmitirá vía Web a través de Live Meeting.

  • Si no tienes Live Meeting, puedes descargarlo en el siguiente enlace.
  • Podéis registraros en el evento en el siguiente enlace.

Yo para variar, me lo perderé en directo porque será mi segundo día en Dublin y tengo clase hasta las 19:00, pero lo bueno de estos eventos es poderlos ver a posteriori en diferido 😀 y este en concreto me interesa muchísimo.

Menealó

Evento: Windows Communication Foundation al Descubierto en SNUG | vtortola.NET

Chatarra a precio de oro III, Microsoft es asi

Y no se confundan, Microsoft nada pinta aquí… al menos para mi, pero si para el SAT 😀  Sigo con mi lucha con la chatarra (parte I, parte II), alcanzado ahora nuevas cotas de asombro con el SAT. Una de mis reglas cuando hablo con el SAT, es ser tan humilde como pueda, prestar atención a lo que dice y evitar dar a entender que soy un usuario avanzado, en este caso… mucho menos decir que soy programador.

Una vez instalada la aplicación en red, la primera cosa que se me ocurre (yo y mis ocurrencias…), es lanzar el cliente como usuario Invitado … a lo que recibo un error de que no puede escribir a un archivo que el programa de instalación ha dejado caer en C: … nada más y nada menos, no se me ocurre otra cosa que llamar al SAT (más ocurrencias bobas…) para preguntar como ejecutar la aplicación con una cuenta desprivilegiada para que nadie pueda cargarse la máquina… la respuesta… increible:

«… es así y la aplicación necesita que se ejecute como administrador, es un requerimiento de Microsoft… es lo que hay…»  [ … ] «… vamos… deberia ser un usuario malintencionado…»

Aún estoy recuperandome del sock. Bien, pues siguiendo los consejos de Josue en Geeks.ms y mi colega Joe_Dalton de BandaAncha.st me lanzo a crear una Windows shell para contener al usuario en una interfaz de la que no puedan ejecutar nada, además deshabilito el Task Manager, ahora parece que todo irá bien y no hay posibilidad de catástrofe ya que los ordenadores no tienen teclado tampoco.

Comienzan los problemas de verdad, sin saber porque … se cuelga «algo» en el servidor. Los clientes siguen funcionando, es decir… siguen accediendo a la bd en forma de archivos que hay en el recurso compartido y trabajando normalmente, pero en el servidor es imposible abrir el módulo de gestión ni abrir la aplicación cliente, obtengo errores de timeout y procesos colgados indefinidadmente, tampoco funciona el BDE Administrator del panel de control, nos vemos obligados a reiniciar la máquina… y vuelve a funcionar. Llamo al SAT (iluso yo) … simplemente para preguntar como solventar el problema sin reiniciar la máquina, ya que eso supone que los clientes pierdan el trabajo no guardado ó hacerles que terminen, paren, reiniciar y volver a abrir de nuevo… con la mala imagen que da eso, es decir… que me diga algún servicio de Borland que reniciar … no sé… algo xD, la respuesta tan asombrosa ó más como la anterior:

«… Microsoft no proveé de ninguna herramienta para hacer eso, es lo mismo que si se te cuelga alguna aplicación y tienes que reiniciar, no se puede hacer nada, Microsoft es así…»

Intentando recuperar la respiración, me reincorporo, me sacudo el polvo de la ropa después de haber rodado varias veces por el suelo y vuelvo a sentarme en la silla de nuevo, minutos después me llaman de la sala diciendo que hay un equipo que «no va». Me acerco y un mensaje alerta algo como «Cannot set focus on a unexistent window», doy a aceptar y la pantalla se queda sin datos… y sin que funcione ningún botón, toca matarla y reiniciarla. Llamo al SAT de nuevo … «hola, soy el de antes», la respuesta… ya para llorar:

«… eso es porque el usuario va muy rápido, cuando se inicia el test sale una ventana de bienvenida y hay que darle a aceptar, si se pulsa sobre la ventana de fondo sin darle a aceptar… pasa eso…, la ventana esa se puso para ese fin, que terminase de cargar la otra… si le das antes … pues normal que se quede asi…»

En fin… Ahora mismo, mientras escribo esto estaba esperando a que el SAT me coja de nuevo el teléfono porque hay otro cliente que se ha quedado … literalmente congelado, ni el cronómetro que hay en una de las esquinas corre… pero justo ahora mismo, después de 5min congelado ha saltado el error : «Lock time out, table xxx.db» …

¿Alguien tiene idea de que se puede hacer? Han transcurrido los 15 días de prueba ya… con lo que no creo que se pueda devolver… pero una cosa es que no te guste, otra cosa es … ESTO.  Este post se va a hacer interminable xD, ahora mismo estoy sacando un captura de pantalla de un volcado de datos (ó eso parece) sobre el formulario después de otro error de «Lock time out». No sé si reir ó llorar…

Locktimeoutyvolcado

Aquí queda el testimonio de mi indignación e impotencia 🙁

 

Chatarra a precio de oro III, Microsoft es asi | vtortola.NET

Forzando la captura de excepciones no manejadas en WPF

En .NET 2.0 y WinForms había una forma que ahora ya no es del todo válida en WPF ya que han desaparecido el método Application.SetUnhandledExceptionMode y el evento Application.ThreadException, en su lugar tenemos Application.DispatcherUnhandledException:

<Application x:Class="KiosimWPF.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml" 
    DispatcherUnhandledException="App_DispatcherUnhandledException">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Luego en el handler del evento podemos evitar que la excepción tumbe la aplicación:

void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    // Proceso la excepción:
    Trace.Write(String.Format("({0}):{1}nn{2}",e.Exception.GetType().Name,
                                            e.Exception.Message,
                                            e.Exception.StackTrace));
 
    // Evito que la excepción siga subiendo y tumbe
    // la aplicación marcándola como manejada:
    e.Handled = true;
}

Más info: Información general sobre la administración de aplicaciones (WPF).

Forzando la captura de excepciones no manejadas en WPF| vtortola.NET