Ejecución de Código C en JAVA
Basado en la publicación Beginning JNI with NetBeans

Objetivo: Realizar un ejemplo simple de un programa en JAVA que invoca un método nativo de un archivo DLL construido en C.

Herramientas:


Pasos:
  1. Instalación de compiladores C/C++ (Cygwin).
  2. Creación y configuración del proyecto java
  3. Creación de archivo de cabecera.
  4. Configuración de C/C++ en NetBeans.
  5. Construyendo y ejecutando la aplicación en conjunto.

Instalación de Cygwin
.
El primer paso es descargar el Cygwin con el paquete "devel", luego de esto
ejecute el Cygwin Bash Shell, y verifique que estén instaladas las siguientes herramientas:

Herramienta
Comando en Cygwin Bash Shell
Cygwin 1.5.x
cygcheck -c cygwin
Cygwin gcc-core (C compiler) 3.4.x
gcc --version
Cygwin gcc-c++ (C++ compiler) 3.4.x
g++ --version
Cygwin gdb (GNU Debugger) 6.5.50
gdb --version
Cygwin make 3.80
make --version


 
Ahora se agrega en la variable de entorno patch, e
l directorio de instalación de Cygwin, siguiendo los siguientes pasos:

De click en Inicio, ubique el icono Mi PC  y de click derecho sobre él, seguidamente seleccione propiedades. Aparecerá la ventana de propiedades del sistema seleccione la pestaña Opciones Avanzadas, luego de click en variables de entorno, busque la variable path y adicione al final de la linea y despúes de ; la ruta de la carpeta bin de Cygwin, como se muestra en la siguiente gráfica.

 

Creación y configuración del proyecto JAVA.
Seleccione File/New Project. En Choose Project, seleccione Categories:java  seguido de Java Application, luego de click en el botón next. 
  

Seguido de esto aparecerá la ventana New Java Application. En el campo project name escriba HelloWorldNative, seleccione un folder para el proyecto.


Luego de click derecho en el nodo del projecto edite la clase main como sigue:


Úbiquese en el nodo principal del proyecto, de click derecho y seleccione Clean and Build 


la clase deberá compilar sin errores.

Creación del archivo de cabecera.
Diríjase a la consola y úbiquese en el directorio del proyecto. escriba:

<JAVA_HOME>\bin\javah.exe -o HelloWorldNative.h -jni -classpath <PROJECTS_ROOT>\HelloWorldNative\build\classes helloworld.Main
 
reemplazando <JAVA_HOME> por la respectiva ruta donde se encuentra instalado el JDK, y reemplazando <PROJECTS_ROOT>, por la ruta respectiva del proyecto. A modo de ejemplo observe la siguiente gráfica.
 

Después de la ejecución del anterior comando el archivo HelloWorldNative. h es generado. Este es requerido para la declaración del metodo nativo.

Creación y configuración del proyeto DLL en C/C++
Seleccione File/New Proyect. En Choose Project, seleccione Categories:C/C++  seguido de C/C++ Dynamic Library, luego de click en el botón next. Observese la siquiente gráfica.

Seguidamente aparecerá la ventana NewC/C++ Dynamic Library, escriba en el campo Project Name HelloWorldC. En project Location escriba la ruta de localización del proyecto java realizado anteriormete.


De click derecho en el nodo del proyecto HelloWorldC, seleccione propiedades, expanda el nodo Build y agregue los directorios include e include/win32 del JDK en el campo Include Directorires, para los sub nodos C Compiler y C++ Compiler. Agrege el siguiente comando en Command Line /Additional Options: -mno-cygwin -Wl,--add-stdcall-alias -shared -m32.

La opción -mno-cygwin option, habilita la no dependencia de las librerias de Cygwin para la construccion de los dlls, es decir la dlls podrán funcionar en maquinas que no tengan instalado Cygwin,
-Wl,--add-stdcall-alias, pasa la opcion  --add-stdcall- a el enlazador (linker) ; Sin esto se producirá una falla en tiempo de compilación de tipo UnsatisfiedLinkError.
El -shared option, le dice al compilador que genere una dll, y no un archivo ejecutable.
-m32, le indica al compilador que compile a 32bit.

Observe las siguinte gráfica a modo de ejemplo.
 

De click sobre el sub menu Linker, escriba en General/Output la ruta dist/DLL/libHelloWorldC.dl.

Agregando archivo de cabecera al proyecto DLL en C/C++.
Copie el archivo de HelloWorldNative.h ubicado en el fólder de localización de projectos a el projecto en C. para el ejemplo seria copiar C:\JNIDemo\HelloWorldNative.h al fólder  C:\JNIDemo\HelloWorldC\HelloWorldNative.h.

Expanda el projecto HelloWorldC y de click derecho  en ResourceFiles, seleccione Add Existing Item y agregue el archivo C:\JNIDemo\HelloWorldNative.h.

Implementado el archivo HelloWorldNative.c.
De click derecho sobre el nodo principal del proyecto HelloWorldC, úbiquese en el subnodo Source Files de click derecho sobre este y seleccione New Empty C File, en el campo File Name escriba HelloWorldNative, se creará un archivo llamado HelloWorldNative.c, editelo con las siguientes lineas:

#include <jni.h>
#include <stdio.h>
#include "HelloWorldNative.h"

JNIEXPORT void JNICALL Java_helloworldnative_Main_nativePrint (JNIEnv *env, jobject obj){
   
    printf("\nHello World from C\n");

}

Luego de click derecho en sobre el nodo principal del proyecto y seleccione Build, el proyecto debe  compilar sin errores.

A modo de ejemplo se muestran las siguientes gráficas.


El resultado de la anterior ejecución es el archivo  C:\JNIDemo\HelloWorldC\dist\DLL\libHelloWorldC.dll.

Construyendo y ejecutando la aplicación en conjunto.

Abra el Main.java y el siguinte bloque de inicializacion static que asegura la carga de la dll construida en el anterior paso.

static {
        System.load("C:\\JNIDemo\\HelloWorldC\\dist\\DLL\\libHelloWorldC.dll");
   }

Finalmente construya el proyecto y ejecútelo, dando click derecho sobre el nodo HelloWorldNative, selecione Build, de click derecho sobre la clase main y seleccione Run "Main.java". La ejecución mostrará Hello World from C. Observe a manera de guia la siguiente gráfica.


NOTAS

DLL


Dynamic Link Librarary, son archivos con código ejecutable generalmente construidos en C. que se cargan bajo demanda del programa por parte del sistema operativo. Especificamente esta denominación hace referencia a los sistemas operativos Windows, aunque el concepto existe en practicamente totos los sistemas operativos, por ejemplo para linux y open solaris la denominación es OS ():

#ifdef y #ifndef
son  directivas condicionales especializadas para comprobar si un macro-identificador está definido o no.

extern
Modificador utilizado para declarar un método que se implementa externamente.

Usage: javah [options] <classes>

where [options] include:

        -help                 Print this help message and exit
        -classpath <path>     Path from which to load classes
        -bootclasspath <path> Path from which to load bootstrap classes
        -d <dir>              Output directory
        -o <file>             Output file (only one of -d or -o may be used)
        -jni                  Generate JNI-style header file (default)
        -version              Print version information
        -verbose              Enable verbose output
        -force                Always write output files

<classes> are specified with their fully qualified names (for
instance, java.lang.Object).