Re: Redirecting IO from C++ native library
Josef Svitak wrote:
Chris Uppal wrote:
I doubt if that -- or anything else -- will work.
Right. I think I've come around to that view...
If you have access to the same C/C++ compiler
as the DLL you want to capture from, then there
may be some possibilities.
Look at this example. I am using Windows and
Mingw C compiler.
First we emulate the current DLL you have.
Nat1.java:
public class Nat1 {
public native void hello();
static {
System.loadLibrary("Nat1");
}
}
Nat1.c:
#include <stdio.h>
#include <jni.h>
#include "Nat1.h"
JNIEXPORT void JNICALL Java_Nat1_hello(JNIEnv *cntx, jobject me)
{
printf("Hello world\n");
}
A true classic.
Now to capture the output from this DLL we create a new DLL.
Nat2.java:
public class Nat2 {
public native void init();
public native String done();
static {
System.loadLibrary("Nat2");
}
}
Nat2.c:
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <jni.h>
#include "Nat1.h"
#define MAXBUF 20480
static int oldstdout;
static int pipehandles[2];
static char buf[MAXBUF];
JNIEXPORT void JNICALL Java_Nat2_init(JNIEnv *cntx, jobject me)
{
oldstdout = _dup(_fileno(stdout));
_pipe(pipehandles,MAXBUF,_O_BINARY);
_dup2(pipehandles[1],_fileno(stdout));
}
JNIEXPORT jstring JNICALL Java_Nat2_done(JNIEnv *cntx, jobject me)
{
int n;
fflush(stdout);
_dup2(oldstdout,_fileno(stdout));
n = _read(pipehandles[0],buf,sizeof(buf));
buf[n] = '\0';
return (*cntx)->NewStringUTF(cntx,buf);
}
Now we just need a test program.
TestProgram.java:
public class TestProgram {
public static void main(String[] args) throws Exception {
Nat2 n2 = new Nat2();
n2.init();
Nat1 n1 = new Nat1();
n1.hello();
n1.hello();
n1.hello();
System.out.println("#" + n2.done() + "#");
}
}
Building and running:
javac -classpath . Nat1.java
javah -classpath . -jni Nat1
gcc -c -I\sunjava\jdk1.5.0\include -I\sunjava\jdk1.5.0\include\win32
Nat1.c -o Nat1.obj
gcc -s -shared -Wl,--export-all,--kill-at Nat1.obj -o Nat1.dll
javac -classpath . Nat2.java
javah -classpath . -jni Nat2
gcc -c -I\sunjava\jdk1.5.0\include -I\sunjava\jdk1.5.0\include\win32
Nat2.c -o Nat2.obj
gcc -s -shared -Wl,--export-all,--kill-at Nat2.obj -o Nat2.dll
javac -classpath . TestProgram.java
path=.;%PATH%
java -classpath . TestProgram
And the output:
#Hello world
Hello world
Hello world
#
The method should work with C++ IO as well (cout instead of stdout).
This technique requires:
- DLL's being dynamicly linked against the C/C++ RTL
- DLL's being compiled with the same compiler
So it may not be possible for you.
But on the other hand it may be possible !
Arne