C#

Patrones de Comportamiento (VI): Patrón Observer


Objetivo:

«Definir una dependencia uno-a-muchos entre objetos de forma de que, cuando el estado de uno de ellos cambia, todos los objetos dependientes son notificados y actualizados de forma automática».

Design Patterns: Elements of Reusable Object-Oriented Software

Podemos afirmar sin rubor alguno que el patrón Observer es uno de los más importantes (y utilizados) de todos los patrones de diseño vistos hasta el momento. Su filosofía es simple: un objeto, denominado sujeto (Subject) posee un estado. Cuando su estado cambia, es capaz de «avisar» a sus subcriptores (Observers) de este cambio de estado. De este modo, los objetos suscritos al objeto no tienen que preocuparse de cuándo se produce un cambio de estado: éste se encargará de informar de forma activa a todos aquellos objetos que hayan decidido suscribirse.

Este tipo de suscripción puede ser de dos tipos:

  • Suscripción push: el objeto informa a sus suscriptores con sus valores tan pronto como su estado cambie.
  • Suscripción pull: el objeto es interrogado por sus suscriptores si su estado ha cambiado desde la última vez que se tanteó.

Este esquema respeta al máximo el principio de bajo acoplamiento. El Subject y el Observer pueden interactuar entre ellos, pero apenas tienen conocimiento del uno sobre el otro. Dado que hemos basado el diseño en abstracciones, no en concreciones, no será necesario modificar el Subject para añadir nuevos Observers (bastará con que implemente la interfaz IObserver). Del mismo modo, un Observer podrá suscribirse a más de un Subject si éste implementa la interfaz ISubject.

(más…)

Patrones de Comportamiento (V): Patrón State


Objetivo:

«Permitir que un objeto modifique su comportamiento cuando su estado interno cambie. Parecerá que el objeto cambia de clase».

DesignPatterns: Elements of Reusable Object-Oriented Software

El patrón State tiene la misión fundamental de encapsular el comportamiento de un objeto dependiendo del estado en el que éste se encuentre. ¿A qué nos referimos con estado? Estrictamente hablando, podemos definir el estado de un objeto como el conjunto actual de los valores de los atributos de un objeto. Desde un punto de vista más coloquial, y refiriéndonos al patrón que estamos presentando, podríamos definir un estado como un conjunto de características que harán que el objeto tenga unas características concretas. O hablando en plata: desde el punto de vista de la orientación a objetos, podemos decir que el estado de un vehículo es de velocidad instantánea igual a cero, sin consumo de combustible, a una distancia de entre cero y veinte centímetros de la acera y con el habitáculo vacío. Desde un punto de vista coloquial (que ahora mismo es el que nos interesa), podemos decir que la suma de esos atributos nos informa de que el vehículo se encuentra en estado aparcado.

(más…)

Patrones de Comportamiento (IV): Patrón Strategy


Objetivo:

«Definir una familia de algoritmos, encapsular cada uno de ellos y hacerlos intercambiables. Strategy permite cambiar el algoritmo independientemente de los clientes que lo utilicen».

Design Patterns: Elements of Reusable Object-Oriented Software

En el artículo anterior veíamos cómo un patrón de diseño puede ayudarnos a encapsular distintos algoritmos a partir de una «plantilla» cuyos hijos se encargaban de especializar. El patrón Strategy, por su parte, no bucea en los detalles, sino que va un paso más allá: encapsulará un algoritmo completo ignorando los detalles de su implementación, permitiendo intercambiarlo en tiempo de ejecución para permitir actuar a la clase cliente con un comportamiento distinto.

El nombre de este patrón evoca la posibilidad de realizar un cambio de estrategia en tiempo de ejecución sustituyendo un objeto que se encargará de implementarla. No nos preocupará el «cómo». De hecho, ni siquiera nos importará «el qué»: la clase que actúa como interfaz del patrón únicamente tendrá que exponer el método o métodos que deberá invocar el cliente.

(más…)

Patrones de Comportamiento (III): Template Method


Objetivo:

«Permitir que ciertos pasos de un algoritmo definidos en un método de una clase sean redefinidos en sus clases derivadas sin necesidad de sobrecargar la operación entera».

Design Patterns: Elements of Reusable Object-Oriented Software

Si el patrón Command nos permite encapsular una invocación a un método, el patrón Template Method o Método Modelo establece una forma de encapsular algoritmos. Este patrón se basa en un principio muy sencillo: si un algoritmo puede aplicarse a varios supuestos en los que únicamente cambie un pequeño número de operaciones, la idea será utilizar una clase para modelarlo a través de sus operaciones. Esta clase base se encargará de definir los pasos comunes del algoritmo, mientras que las clases que hereden de ella implementarán los detalles propios de cada caso concreto, es decir, el código específico para cada caso.

El procedimiento es sencillo:

  • Se declara una clase abstracta, que será la plantilla o modelo. Esta clase definirá una serie de funciones y métodos. Aquellas que sean comunes estarán implementadas. Aquellas que dependan de cada caso concreto, se declararán como abstractas, obligando a las clases hijas a implementarlas.
  • Cada clase derivada implementará los métodos específicos, acudiendo a la clase base para ejecutar el código común.
  • La clase base también se encargará de la lógica del algoritmo, ejecutando los pasos en un orden preestablecido (las clases hijas no deberían poder modificar el algoritmo, únicamente definir la funcionalidad específica que tienen que implementar).

Dado que la clase padre es la que se encarga de llamar los métodos de las clases derivadas (los pasos del algoritmo estarán implementado en la clase base), se trata de una aplicación manifiesta del principio de inversión de dependencias: la clase base no tiene por qué saber nada acerca de sus hijas, pero aún así, se encargará de invocar su funcionalidad cuando sea necesario. El principio de Hollywood («no nos llames, nosotros te llamaremos») vuelve a entrar en escena.

(más…)

Patrones de Comportamiento (II): Patrón Command


Objetivo:

«Encapsular una petición como un objeto, de modo que puedan parametrizarse otros objetos con distintas peticiones o colas de peticiones y proporcionar soporte para realizar operaciones que puedan deshacerse».

Design Patterns: Elements of Reusable Object-Oriented Software

Cuando decimos que un patrón es «estructural» es sencillo imaginar que su cometido será modelar las clases de tal forma que cumplan un cometido concreto. Sin embargo, el concepto de diseñar clases orientando su funcionalidad hacia el comportamiento es algo más complicado. El patrón command u orden (como decía mi profesor de programación en primero de carrera, command se debería traducir por órden, no por comando, ya que un comando es un señor militar que pega tiros en la selva) tiene como objetivo encapsular la invocación de un método. Dicho así sin más, suena sencillo de entender pero… ¿cómo lo implementamos? La definición, a diferencia del patrón anterior, es un conglomerado de términos incomprensibles, ¿verdad? Encapsular una petición como un objeto. Vale, lo pillo. Pero ¿parametrizarse? ¿Soporte para realizar peticiones que puedan deshacerse?

(más…)

Patrones de Comportamiento (I): Patrón Iterator


Objetivo:

«Proporcionar una forma de acceder a los elementos de un objeto agregado de forma secuencial sin exponer sus detalles».

Design Patterns: Elements of Reusable Object-Oriented Software

Pese a que no seamos conscientes de ello, cuando programamos utilizamos el patrón Iterator a diario. Casi todas las estructuras de datos que representan colecciones utilizan de algún modo este patrón para proporcionar acceso secuencial a los elementos que las conforman, y tanto Java como .NET ofrecen interfaces que nos invitan a implementar este patrón codificando su comportamiento.

Ojo al detalle: hemos dicho recorrer secuencialmente, esto es, hacer uso de un proceso que sea capaz de situarse en el primer elemento de una colección y obtener la información de ese contenido. Tras esto, dado que hemos dicho que se trata de una operación secuencial, deberemos ser capaces de pasar del elemento actual al elemento al siguiente, obteniendo también su contenido. Por último, será necesario implementar algún mecanismo que nos informe si hemos alcanzado el final de la colección para detener el proceso de iteración.

Por lo tanto, el patrón Iterator debe proporcionar la siguiente funcionalidad:

  • Obtener una referencia al elemento actual de la colección.
  • Obtener una referencia al siguiente elemento de la colección (el situado a continuación del elemento actual).
  • Obtener información sobre si existen más elementos después del actual.
  • Reiniciar la colección para que el iterador apunte nuevamente al primer elemento de la colección.

Seguramente podremos pensar que no tiene mucho sentido implementar nuestro propio patrón Iterator, ya que prácticamente todas las colecciones implementan todas estas operaciones (e incluso alguna más). Sin embargo, existirán muchos supuestos en los que nos será útil.

(más…)

Patrones Estructurales (VII): Patrón Proxy


Objetivo:

«Proporcionar un sustituto o intermediario para otro objeto de modo que pueda controlarse el acceso que se tiene hacia él».

Design Patterns: Elements of Reusable Object-Oriented Software

Supongo que todos conocemos el concepto de proxy, al menos en su acepción aplicada a la navegación web. Se trata de una máquina que actúa de intermediaria a la hora de servir páginas web (u otros servicios). En la configuración de área local podemos indicar la IP de esta máquina y será esta máquina la que se conecte a la URL por nosotros y la envíe a nuestro equipo.

De este modo, un equipo no se conectará directamente a la URL, sino que lo hará a través de este intermediario. ¿Por qué hacer esto? Por múltiples motivos: podemos, por ejemplo, restringir las URLs que nuestros clientes (ordenadores de la red local) pueden visitar. O cachear las páginas que se visitan con más frecuencia, haciendo innecesario el acceso a la web «real» en los casos en los que el acceso se repita, proporcionando un ahorro en ancho de banda. En resumen, un proxy será una entidad en la que delegaremos la ejecución de ciertas tareas y que decidirá, en última instancia, qué acciones realizar antes y después de éstas. Los proxies, por tanto, podrían dedicarse perfectamente a la política 🙂

(más…)

Patrones Estructurales (VI): Patrón Composite


Objetivo:

«Componer objetos en árboles para representar jerarquías todo-parte. Composite permite a los clientes tratar objetos individuales y objetos compuestos de una manera uniforme».

Design Patterns: Elements of Reusable Object-Oriented Software

El patrón Composite se aleja un poco de la línea tradicional de los patrones vistos hasta ahora, ya que rompe uno de los principios de la programación orientada a objetos: una clase, una responsabilidad. En realidad, los más puristas pueden decidir no hacerlo, pero el precio a pagar es demasiado alto para los ingenieros mortales: la simplicidad del modelo.

Cuando diseñamos debemos tener claro que la idea principal es alcanzar un equilibrio entre muchos factores como por ejemplo presupuesto, usabilidad y facilidad para que nuestro código sea reutilizable y pueda ser fácilmente mantenible en un futuro. Si el objetivo del anterior patrón, Flyweight, era el rendimiento, el sine qua non de este patrón es la facilidad de uso.

(más…)

Patrones Estructurales (V): Patrón Flyweight


Objetivo:

«Compartir una parte común del estado de un objeto para hacer más eficiente la gestión de un número elevado de objetos de grano más fino.»

Design Patterns: Elements of Reusable Object-Oriented Software

El patrón Flyweight u «objeto ligero», a diferencia de algunos de los patrones vistos hasta el momento, no goza de un uso masivo entre la comunidad de ingenieros de software. El motivo no radica en su falta de utilidad o de interés, sino que se centra principalmente en el concepto de rendimiento. A grandes rasgos, se basa en dividir un objeto en dos partes: una parte «común» a un conjunto grande de los objetos de la clase (parte intrínseca), y una parte «privada» que será accesible y modificable únicamente por un objeto en concreto (parte extrínseca).

Un ejemplo simple de Flyweight podría ser el gestor de ventanas del sistema operativo. Un tema de ventanas poseerá atributos como color de fondo, fuente tipográfica, grosor del borde de la ventana, estilo de los botones… Muchos de estos atributos serán comunes a todas las ventanas, por lo que podríamos almacenar toda esta información en un elemento compartido y hacer una llamada a un método para que, haciendo uso de estos atributos comunes y de los parámetros recibidos por el método, se realice una operación que no requiera una instancia exclusiva para ello.

Por ejemplo, realizando una llamada a un método como RenderizarVentana(int x, int y, int ancho, int alto), nuestro objeto Flyweight utilizaría los valores almacenados comunes a todas las ventanas para dibujar una ventana en la posición (x, y) con unas dimensiones (ancho, alto). La instancia de la ventana será única, limitándose a devolver un objeto con las características indicadas. La alternativa simple, como podremos imaginar, sería instanciar un objeto por cada ventana presente en el sistema que almacenara todos estos datos de forma individual más, opcionalmente, valores específicos para la posición y las dimensiones de la ventana. Como siempre ocurre con los patrones de diseño, simplificar una parte del software implicará aumentar la complejidad de otra. En este caso, un diseño más simple se corresponderá con un aumento de consumo de memoria. El límite, nuevamente, se encontrará en el punto de equilibrio que el diseñador estime conveniente.

 

(más…)

Patrones Estructurales (IV): Patrón Bridge


Objetivo:

«Desacoplar una abstracción de su implementación de modo que los dos puedan ser modificados de forma independiente.»

Design Patterns: Elements of Reusable Object-Oriented Software

El patrón Bridge o Puente es normalmente uno de los patrones que más cuesta entender, especialmente si nos ceñimos únicamente a su descripción. La idea tras este patrón, sin embargo, es sencilla: dado que cualquier cambio que se realice sobre una abstracción afectará a todas las clases que la implementan, Bridge propone añadir un nuevo nivel de abstracción entre ambos elementos que permitan que puedan desarrollarse cada uno por su lado.

Si le echamos un ojo al diagrama, es posible que de base no nos aclare demasiado. Nos centraremos en el elemento central: una clase abstracta Abstracción que contiene una referencia a una interfaz Implementor y un método operacion() que no hace más que invocar el método operacionOriginal() de dicha interfaz. Lo que hace esta clase Abstracción es, por tanto, encapsular a la interfaz Implementor exponiendo sus métodos.

(más…)

Patrones Estructurales (III): Patrón Decorator


Objetivo:

«Añadir responsabilidades a un objeto de forma dinámica. Los decoradores proporcionan una alternativa flexible a la herencia para extender funcionalidad.»

Design Patterns: Elements of Reusable Object-Oriented Software

El siguiente de los patrones estructurales que veremos sera el patrón Decorator o decorador. Su filosofía consiste en añadir responsabilidades de forma dinámica con el principal objetivo de evitar la conocida como «explosión de clases», es decir, la generación de un número elevado de subclases a partir de una superclase común.

Como podemos observar en el gráfico superior, la clase Decorator hereda de la misma clase que el componente que se quiere decorar. Así, cada decorador es capaz de encapsular una instancia de cualquier otro objeto que herede del componente común, bien un componente concreto u otro decorador. Este comportamiento recuerda al que vimos previamente en el patrón Adapter, con la diferencia de que la clase Decorator, a diferencia de la clase Adapter, no transforma una interfaz, sino que añade cierta funcionalidad.

(más…)

Patrones Estructurales (II): Patrón Facade


Objetivo:

«Proporcionar una interfaz unificada a otro conjunto de interfaces de un subsistema. Façade define una interfaz de más alto nivel que hace que el subsistema más fácil de usar.»

Design Patterns: Elements of Reusable Object-Oriented Software

Cuando vimos el patrón Adapter dijimos que el patrón Facade (fachada) estaba muy relacionado con él. Si bien ambos patrones se basan en el mismo principio (encapsular la interfaz de otros elementos), es el motivo y el uso que se le va a dar lo que las diferencia:

  • El patrón Adapterconvierte una interfaz en otra, haciendo que la clase cliente pueda utilizar los métodos de una clase para cuya interfaz no estaba originalmente preparado.
  • El patrón Facade, sin embargo, no realiza ninguna transformación, sino que se limita a simplificar y centralizar un conjunto de invocaciones en un único punto, a la vez que desacopla al cliente del subsistema (siendo la clase Facade la que quedaría acoplada). Es importante tener en cuenta que el patrón Facade no realiza operaciones de transformación, ya que las clases del subsistema, pese a ser envueltas con este elemento, pueden seguir siendo accesibles de forma normal en caso de que fuese necesario, al contrario de lo que ocurre con el patrón Adapter. Un Facade es una forma de simplificar las cosas: es decisión del diseñador si las clases del subsistema son accedidas de forma directa o a través de la fachada.

Resumiendo, Adapter transforma mientras que Facade simplifica y desacopla.

(más…)

Patrones Estructurales (I): Patrón Adapter (Wrapper)


Objetivo:

«Convertir la interfaz de una clase en otra interfaz que el cliente espera. Adapter consigue que trabajen juntas clases que de otro modo no podrían.»

Design Patterns: Elements of Reusable Object-Oriented Software

El patrón Adapter nos abre el camino hacia el segundo grupo de patrones propuestos por el Gang of Four: los patrones estructurales. Si bien los patrones de creación definían la forma en la que los objetos son instanciados, los patrones estructurales se basan en la forma en la que un conjunto de clases se relacionan entre sí para proporcionar una funcionalidad compleja, proporcionando una estructura para conseguir lograr ese objetivo.

La filosofía de Adapter, al igual que vimos con Prototype, es tan simple como autoexplicativa: establecer una capa intermedia que permita comunicarse a dos clases que de otro modo no podrían hacerlo, realizando una adaptación de la interfaz de la clase que proporciona el servicio a la que la solicita.

(más…)

Patrones de creación (IV): Patrón Singleton


Objetivo:

«Asegurarse de que una clase tiene una única instancia, proporcionando acceso global a ella.»

Design Patterns: Elements of Reusable Object-Oriented Software

Hay clases que deben instanciarse una única vez. El acceso a un sistema de archivos, a la cola de impresión o al gestor de ventanas del sistema operativo debería realizarse por un único objeto, siendo labor de la propia clase el controlar que la instancia sea única. Por norma general, esta clase será accesible de forma global, y el proceso de instanciado no suele requerir parámetros.

Como podemos observar en el diagrama, nuestra clase Singleton constará al menos con dos métodos:

  • Un método Instance() de carácter estático (método de clase) que se encargará de instanciar la clase.
  • Un constructor privado que evitará que se creen nuevos objetos mediante new(), haciendo que el método Instance() sea el único que puede generar la instancia.

(más…)

Patrones de creación (III): Patrón Prototype


Objetivo:

«Especificar el tipo de objetos que se crearán utilizando una instancia prototipada y crear nuevos objetos realizando copias de ese prototipo.»

Design Patterns: Elements of Reusable Object-Oriented Software

El concepto de este patrón es simple: en lugar de crear un objeto, se clona, es decir, se realiza una copia exacta de otro objeto dado, denominado prototipo.

Entran en juego tres elementos:

  • Cliente: clase que solicita al prototipo que se clone.
  • IPrototipo: interfaz o clase abstracta que define la operación de clonado.
  • PrototipoConcreto: implementa IPrototipo y su método Clone() para proceder al clonado del objeto.

El proceso de clonado comienza instanciando una clase de forma habitual. Una vez que disponemos de una instancia funcional, el resto de instancias se generarán creando copias de la primera.

La forma de aplicar este patrón es simple:

  • Se define una interfaz que expondrá el método utilizado para realizar el clonado del objeto.
  • Las clases que realicen el clonado utilizarán este método para esta operación.

(más…)

Patrones de creación (II): Patrón Builder (Constructor)


Objetivo:

«Separar la construcción de un objeto complejo de su representación, de modo que el mismo proceso de construcción pueda crear representaciones diferentes

Design Patterns: Elements of Reusable Object-Oriented Software

Patrón Builder

Hablando en plata, el patrón Builder es un patrón creacional cuyo objetivo es instanciar objetos complejos que generalmente están compuestos por varios elementos y que admiten diversas configuraciones. Cuando hablamos de «construcción» nos referimos al proceso, mientras que cuando hablamos de «representación» nos estaremos refiriendo a los datos que componen el objeto. Se encargará, por tanto, de encapsular todo el proceso de generación de modo que únicamente necesite los detalles necesarios para «personalizar» el objeto, devolviendo como resultado una instancia del objeto complejo que deseamos construir. Es un patrón fuertemente ligado a otro, el patrón estructural Composite, del que hablaremos en posteriores artículos.

(más…)

Patrones de creación (I): Factory Patterns


Habíamos quedado en que los patrones creacionales o de creación eran aquellos en los que se delegaba la instanciación de un objeto en otro en lugar de recurrir a un simple new(). La pregunta que nos hacemos es: ¿por qué hacer esto? ¿Qué interés práctico puede existir en crear una clase cuya función sea instanciar otras clases pudiendo dejarle el trabajo a la clase original?

Bien, esta forma de trabajar puede ser útil en algunos escenarios, pero el principal suele involucrar el no saber qué objeto vamos a instanciar hasta el momento de la ejecución. Valiéndonos del polimorfismo podremos utilizar una interfaz para alojar una referencia a un objeto que será instanciado por un tercero en lugar de dejar que sea el propio constructor del objeto el que proporcione la instancia. Hablando en plata, pasaremos de esto:


	MotorDiesel motor = new MotorDiesel();

A esto otro:


	IMotor iMotor = MotorFactory.CreateInstance(tipoMotor);

(más…)

Introducción a la inyección de dependencias mediante Unity


English version here

Tras una pequeña introducción a la inversión de control y a la inyección de dependencias, veremos cómo se comportan los contenedores DI en una aplicación práctica. Para ello hablaremos de Unity, desarrollado por Microsoft y perteneciente al paquete Enterprise Library.

Unity es, por tanto, un Framework de inyección de dependencias o DI Container. Puede ser descargado desde Codeplex o utilizando NuGet dentro de Visual Studio, método este último que utilizaremos en nuestro ejemplo.

Comenzaremos creando un nuevo proyecto de consola al que llamaremos, por ejemplo, UnityExample.

A continuación haremos uso de NuGet para añadir nuestra referencia a Unity. Será tan sencillo como hacer click derecho sobre las referencias del proyecto y seleccionar la opción Manage NuGet Packages…

(más…)

Inversión de Control e Inyección de Dependencias


English version here

Los conceptos de Inversión de Control e Inyección de Dependencias no son nuevos, sino que se remontan hasta finales de la década de los 80. Sin embargo, estos conceptos han comenzado a popularizarse debido a la estrecha relación que mantienen con la aparición de Frameworks como Spring en Java o Unity en .NET.

Inversión de Control

El concepto de Inversión de Control fue acuñado originalmente por Martin Fowler, diseñador del patrón MVVM (Model View View-Model). Fowler definió el concepto de forma informal denominándolo como el Principio de Hollywood, en el que, tras una audición, se le decía al actor la famosa frase de No nos llames, nosotros te llamaremos.

El principio establece una diferenciación entre el concepto de biblioteca y framework, definiendo el primero como un simple conjunto de clases, métodos y funciones que son invocadas por el flujo del programa y que posteriormente devuelven el control a éste (control normal) y el segundo como un diseño más abstracto y elaborado que se encargará, en algún momento, de invocar el código que el programador se encargue de codificar (inversión de control).

El ejemplo expuesto por Fowler no puede ser más sencillo: un control normal sería un simple programa secuencial de consola en el que el programa va solicitando datos al usuario y realizando operaciones (cálculos, visualización por pantalla) al recibir las respuestas. Un programa que aplica una inversión de control, sin embargo, se podría representar como una ventana compuesta por cajas de texto, etiquetas y botones. El Framework, en este caso, expondría un bucle de espera que detectaría la emisión de eventos, como la pulsación de un botón, momento en el cual se ejecutaría el código de usuario. El Framework invocará nuestro código en lugar de realizar la operación contraria.

(más…)

Simular teclado y ratón en aplicaciones de terceros


English version here.

La simulación de una pulsación de una combinación de teclas o de una pulsación del ratón en una aplicación propia es relativamente sencillo: basta con hacer uso del método SendKeys para que nuestra aplicación reciba datos desde teclado y la invocación explícita del método adecuado que esté asociado al evento del ratón para simular un click del ratón.

Sin embargo, si deseamos crear un programa cuya misión consista en realizar estas operaciones en un programa de terceros, deberemos hacer uso de código no administrado.

Código administrado y no administrado.

El código administrado es aquel que se ejecuta bajo el control del CLR (Common Language Runtime), es decir, aquel código escrito en .NET que es compilado a un código intermedio MSIL o CIL (dependiendo de la versión del Framework) y que en tiempo de ejecución es transformado en código nativo. Este es el proceso natural de la programación .NET, con el que supongo que todos o casi todos estamos familiarizados.

El código no administrado, en cambio, es aquel código ajeno a este ciclo de vida, tal como el incluido en componentes COM/COM+, C++, ActiveX o la propia API de Windows (que es donde centraremos el objetivo de este artículo).

Windows expone su API a través de un conjunto de bibliotecas de enlace dinámico (dll) tales como user32.dll (permite manejar ventanas y sus eventos), shell32.dll (procesos), winspool.drv (impresión)… Para hacer uso del teclado y el ratón en aplicaciones de terceros nos centraremos en la biblioteca user32.dll, que como podemos imaginar, se tratará como código no administrado.

(más…)