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 :)
Mostrando entradas con la etiqueta netbeans. Mostrar todas las entradas
Mostrando entradas con la etiqueta netbeans. Mostrar todas las entradas

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.

viernes, 5 de junio de 2020

Cómo corregir el error taskdef class com.sun.tools.ws.ant.WsImport cannot be found using the classloader AntClassLoader[] de Neatbeans 8.2

Tengo un proyecto de Netbeans 8.2, el cual incluye un cliente o referecia a un webservice. Todo estába bien hasta que quise depurarlo en Centos 7, donde fue que me saltó este error al querer compilarlo:

taskdef class com.sun.tools.ws.ant.WsImport cannot be foundusing the classloader AntClassLoader[]

Como dije, en mi Windows estaba todo bien ¿que pasó?
Rebuscando en la web halle la solución luego de tres intensos minutos de pruebas, justo aquí.

Seguimos las instrucciones:
  1. ir a  Herramientas->Opciones->Java->Ant.
  2. Hacer clic en "Add JAR/ZIP..." bajo la sección Classpath
  3. Ir a "C:\Program Files\NetBeans x.y\enterprise\modules\ext\metro\"
  4. Seleccionar todos los archivos.
  5. Clic en Ok e intentar la importación/compilación de nuevo.
 


Mi instalación de Netbeans está en /home/pc/netbeans-8.2rc. los archivos que busco están en /home/pc/netbeans-8.2rc/enterprise/modules/ext/metro/
Se deben importar todos:



Luego, al compilar, me salió el error:

/nbproject/jaxws-build.xml:22: class com.sun.tools.ws.ant.WsImport2 doesn't support the "encoding" attribute.

El Netbeans indica que el error sucede en la línea 22 del archivo jaxws-build.xml, para ir allí hay que hacerle clic al enlace en la línea donde se muestra el error (en la ventana Output):



Lo que se debe hacer aquí es borrar la etiqueta encoding en todas las líneas donde salte el error. Ya con esto, el netbeans me permitió compilar mi proyecto.

jueves, 23 de abril de 2020

Los Filósofos Comiendo en Java con Netbeans

Una explicación de este problema está en este enlace. Se trata de un problema de concurrencia: en una mesa circular hay cinco filósofos con cinco platos y cinco cucharas al lado derecho de cada uno. Todos deben poder comer sin fastidiar al filósofo de al lado. A su vez, cada filósofo emplea un tiempo en dejar de comer y ponerse a pensar.
Aquí los filósofos son hijos y las cucharas son recursos compartidos. En mi caso, las cucharas son accesos exclusivos a archivos compartidos.
Para evitar problemas de deadlock (un hilo no libera un recurso que otro necesita, mientras que el segundo hilo mantiene un recurso que el primero necesita...) o starvation (todos los recursos compartidos están ocupados), incluí varias reglas y sincronismos, por ejemplo que los filósofos sólo podían coger las cucharas a su izquierda (identificadas por sus índices). La mesa circular se simula jugando con los índices, el filósofo al que se le asigna el índice cero recibe la última y la primera cuchara:

La clase Spoon recibe como parámetros el índice del filósofo al que ha sido asignada, el número total de filósofos y los nombres de los archivos. La clase Philosopher recibe como parámetros dos objetos Spoon, el lugar que ocupa en la mesa (es decir su índice en el array), y su nombre. Es en esta clase donde se realizan las funciones multihilo.

Los archivos aparecerán en la carpeta del proyecto:


Nunca aparecerán más de cuatro archivos file1x.tmp por la regla que añadí: si se ocupan todas las cucharas, el filósofo debe soltarlas:


El proyecto completo se puede descargar de aquí, corre en java 8.

domingo, 28 de enero de 2018

Abrir y pasarle parámetros a una ventana secundaria desde Java swing en Netbeans

Lo que se necesita en esta ocasión es que al presionar un botón de una ventana en Java Swing, se abra una ventana secundaria una sola vez sin importar cuántas veces se presione el botón, que al cerrar sólo la ventana secundaria la ventana pricipal continúe ejecutandose, y que ambas ventanas se cierren y el programa finalice al cerrar la ventana principal. Además tengo que pasarle parámetros desde la ventana principal a la ventana secundaria al abrirse ésta:


Hacerlo es bastante fácil, se deben crear dos ventanas, la principal frmMain y la secundaria frmOther, ambas del tipo JFrame:


En la ventana principal se declara a nivel de clase:

frmOther formOther;

Y en el listener del botón que abre la ventana secundaria se ingresa el siguiente código:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)                                        
{                                            
    if (formOther == null || !formOther.isVisible())
    {
        formOther = new frmOther("Nuevo ", "Título");
        formOther.setVisible(true);
    }
    else
        formOther.setExtendedState(JFrame.NORMAL);
}  


En este caso la ventana secundaria recibe dos parámetros tipo String, pero se puede hacer que reciba cualquier cantidad  y tipo de parámetros, para esto basta sobrecargar el constructor en la clase de la ventana secundaria (en este caso sólo voy a cambiar el título):

public frmOther(String param1, String param2)
{
    initComponents();
    this.setTitle(param1 + param2);
}


Por último, en la propiedad DefaultCloseOperation  de la ventana secundaria se escoge DISPOSE.



Y eso es todo!
El proyecto en Netbeans 8.0.2 se puede descargar de aquí.