Hace falta toda una vida para aprender a vivir. Séneca
Mucho he tenido que buscar, probar y desesperar para descubrir el mejor modo de hacer que Java sea capaz de llamar a funciones de C# y recuperar un string.
La opción más conocida es JNI (Java Native Interface), que permite llamar a una DLL de VC++.
Si tenemos en cuenta que un programa de VC++ puede comunicarse con una DLL de C#... bueno, parece que ya está todo: creamos nuestra DLL de C#, nuestra DLL de VC++ y hacemos la llamada desde Java mediante JNI.
Pues no.
Resulta que hay un bug imperdonable en las llamadas de JNI, un error en el código fuente, exáctamente en el fichero javacalls.cpp, que hace que falle todo si la DLL de VC++ intenta inicializar una clase de C#.
Así que, para utilizar JNI solo queda una solución: modificar javacalls.cpp y recompilar.
No obstante, hay otra manera de obtener un resultado, y mucho más sencilla que con JNI:
Podemos crear un EXE de consola con VC++, que haga lo que tenga que hacer con sus referencias a C#, y desde Java llamar a este ejecutable con el siguiente código:
Process p = Runtime.getRuntime().exec("EjecutableVC.exe");
Si esta aplicación de consola escribe en la salida estándar (stdout), para leer los resultados de nuestras operaciones solo necesitaremos el siguiente código:
InputStream is = p.getInputStream();
StringBuffer sb = new StringBuffer();
byte[] b = new byte[4096];
for (int n; (n = is.read(b)) != -1; ) {
sb.append(new String(b, 0, n));
}
String s = sb.toString();
is.close();
Alguno se preguntará cómo llamar a una función u otra del ejecutable.
Muy sencillo: pasando parámetros al ejecutable. Dependiendo del parámetro, el EXE ejecutará unas acciones u otras.
Lo único importante es que el EXE de VC++ escriba a la salida estándar.
Eso sí, no hay que olvidar destruir el proceso del EXE con:
p.destroy();
Fin del problema. Y, además, mejora el rendimiento con respecto a JNI.
¿Qué más se puede pedir?