2014-09-30 4 views
0

JNA에서 C++ .so를 사용하고 있습니다. Netbeans를 통해 실행할 때 C++ 출력은 Netbeans 콘솔에 직접 인쇄됩니다. 이 출력을 예를 들어 JFrame으로 리디렉션하고 싶습니다. 웹에서 찾은 다른 유사한 주제에서 제안한 것처럼 freopen()을 사용하여 stdout을 파일로 리디렉션했습니다. 그것은 잘 작동하지만이 솔루션에는 한 가지 문제가 있습니다. 데이터는 C++ 코드의 실행이 중지 된 후에 만 ​​(또는 적어도 이해할 수 있습니다 - 어쩌면 내가 틀 렸음) 원하는대로 JFrame을 읽은 다음 JFrame으로 리디렉션 할 수 있습니다. 그래서 실시간으로 내 Java 코드에서 액세스 할 수있는 C++ 출력을 리디렉션 할 수있는 방법이 있는지 묻고 싶습니다. 내 말은 C++ 코드를 실행하는 동안이 아니라 C++ 부분에서 작업이 끝난 후에가 아니라는 뜻입니다. 감사.리디렉션 공유 라이브러리 출력

+2

당신이에서 읽고있는 파이프로 리디렉션합니다. 세부 사항은 플랫폼에 따라 어느 정도 다릅니다. –

+1

작성된대로 파일을 읽을 수는 있지만 명명 된 파이프가 가장 적합 할 수 있습니다. –

+0

답변 해 주셔서 감사합니다. 내가 여기에서 찾은 한 가지 예를 사용하여 당신이 언급 한 것을 시도했다. 파일을 읽는 Java 파트에서 available() 메서드를 사용하고 C 파트에서 sleep()을 사용하여 작동하는지 확인합니다. 이 예제에서는 작동하지만 공유 라이브러리에서는 작동하지 않습니다. 당신이 파이프 솔루션으로 바꾼다는 것에 대해 아무 것도 제안 할 수 있습니까? 감사. – SpyrosR

답변

3

오 신 .. 파이프로 리디렉션하는 것은 .. 내가 생각할 수있는 최악의 아이디어 중 하나입니다보다에서도 최악의 그것을 읽고 다음 파일로 작성하고 ..

이 맞지 않는

이러한 옵션은 단지 "C"없습니다 "C++".. C++은 당신이 원하는 일을 더 나은 방법이있다 ..

에 사용되어야한다 "실시간"또는 IMO "라이브"데이터의 당신의 필요 조건 ...

당신이 할 수있는 일은 JNI 호출을 통해 원하는 곳으로 직접 쓰는 스트림을 직접 생성하는 것입니다. 먼저 std::streambuf에서 상속 받아야하며 std::ostream 사용자 지정 클래스를 만들었습니다.

std::cout의 사용자 지정 스트림으로 리디렉션합니다. 여기

은 내가 쓴 것입니다 :

내가했던 자바 측에서 그런
#include "jni.h" 

#include <tuple> 
#include <vector> 
#include <iostream> 
#include <cstring> 

#if defined _WIN32 || defined _WIN64 
#include <windows.h> 
#else 
#include <sys/types.h> 
#endif 

#if defined _WIN32 || defined _WIN64 
#define JAVA_EXPORT __declspec(dllexport) 
#else 
#define JAVA_EXPORT 
#endif 


std::vector<std::tuple<std::ostream*, std::ios*, std::streambuf*>> streams; 

extern "C" { 
    JAVA_EXPORT void Java_natives_Natives_RedirectOutput(JNIEnv* env, jclass cls, jobject component); 
    JAVA_EXPORT void Java_natives_Natives_ResetOutput(JNIEnv* env, jclass cls); 
} 

class redir : public std::streambuf 
{ 
    private: 
     JNIEnv* env; 
     jobject comp; 
     jmethodID mID; 

     int_type overflow(int_type c = traits_type::eof()); 

    public: 
     redir(JNIEnv* e, jobject comp, jmethodID m) : env(env), comp(comp), mID(mID) {} 
     ~redir() {} 

     redir(const redir& other) = delete; 
     redir& operator = (const redir& other) = delete; 
}; 

redir::int_type redir::overflow(redir::int_type c) 
{ 
    if (c != traits_type::eof()) 
    { 
     jstring str = env->NewStringUTF((char*)&c); 
     env->CallVoidMethod(comp, mID, str); 
    } 

    return c; 
} 

class rdstream : public std::ostream 
{ 
    public: 
     rdstream(JNIEnv* env, jobject comp, jmethodID mID) : std::ostream(0), sbuf(env, comp, mID) {init(&sbuf);} 

    private: 
     redir sbuf; 
}; 



void Java_natives_Natives_RedirectOutput(JNIEnv* env, jclass cls, jobject component) 
{ 
    if (streams.empty()) 
    { 
     jclass txtcls = env->FindClass("Ljavax/swing/JTextArea;"); 

     if (txtcls) 
     { 
      jmethodID app = env->GetMethodID(txtcls, "append", "(Ljava/lang/String;)V"); 

      rdstream* ctrd = new rdstream(env, component, app); 
      rdstream* crrd = new rdstream(env, component, app); 
      streams.push_back(std::make_tuple(ctrd, &std::cout, std::cout.rdbuf())); 
      streams.push_back(std::make_tuple(crrd, &std::cerr, std::cerr.rdbuf())); 
      std::cout.rdbuf(ctrd->rdbuf()); 
      std::cerr.rdbuf(crrd->rdbuf()); 

      std::cout<<"TESTING OUTPUT REDIRECTION\n"; 
     } 
    } 
} 

void Java_natives_Natives_ResetOutput(JNIEnv* env, jclass cls) 
{ 
    for (std::vector<std::tuple<std::ostream*, std::ios*, std::streambuf*>>::iterator it = streams.begin(); it != streams.end(); ++it) 
    { 
     std::get<1>(*it)->rdbuf(std::get<2>(*it)); 
     delete std::get<0>(*it); 
    } 

    streams.clear(); 

    std::cout<<"TESTING OUTPUT RESET\n"<<std::flush; 
} 

void __attribute__((constructor)) load() 
{ 
    //Onload.. 
} 

void __attribute__((destructor)) unload() 
{ 
    //OnUnload.. 
    if (!streams.empty()) 
    { 
     Java_natives_Natives_ResetOutput(NULL, NULL); 
    } 
} 

:

package natives; 

import java.awt.Component; 

/** 
* 
* @author Brandon 
*/ 
public class Natives { 
    static { 
     System.loadLibrary("Redirector"); 
    } 

    public native static void RedirectOutput(Component comp); 
    public native static void ResetOutput(); 
} 

및 테스트 클래스 : 이제

package windowhandle; 

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import javax.swing.JFrame; 
import javax.swing.JTextArea; 

/** 
* 
* @author Brandon 
*/ 
public class WindowHandle { 

    public static void main(String[] args) { 
     JFrame f = new JFrame("Test"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setVisible(true); 

     JTextArea t = new JTextArea(); 
     t.setPreferredSize(new Dimension(500, 100)); 
     f.setLayout(new BorderLayout(0, 0)); 
     f.getContentPane().add(t, BorderLayout.CENTER); 
     f.pack(); 

     natives.Natives.RedirectOutput(t);   
     natives.Natives.ResetOutput(); 
    } 
} 

는 C++ 코드가 될 수 있습니다 원하는 방식으로 사용자 정의 할 수 있습니다. Java 측에서 원하는 구성 요소를 추가 한 다음 C++에서 텍스트 영역을 찾고 구체적으로 추가하는 대신 해당 메서드를 호출 할 수있는 메서드를 만들 수 있습니다. 이렇게하면 모든 프로젝트에 사용할 수 있습니다. 텍스트 영역뿐만 아니라 모든 구성 요소에 적용됩니다.

파일 (std::fstream)에도 사용할 수 있습니다.

어쨌든 .. 결과는 다음과 같습니다 ..

당신이 그것을 리디렉션하는 경우 : enter image description here

당신이 그것을 재설정하면 : enter image description here

+1

추 ..당신은 또한 BOOST iostreams로 이것을 할 수 있습니다 .. 아마도 boost가 있지만 meh .. 아마 이미 위를 썼습니다. 그래서 지금은 boost에 대해 잊어 버릴지도 모릅니다. – Brandon

+1

코드가 업데이트되었습니다. 이제 더 최적화되고 빨라졌습니다. 전보다. 리디렉션 된 스트림은 Java 항목에 직접 씁니다. – Brandon

+0

안녕하세요! 매우 상세한 답변/설명에 정말 감사드립니다. 지금 이틀 동안 이것을 찾고 있기 때문에 나는 아주 좋은 대답/설명을 찾을 수 없었다! 나는 JNA와 함께 그렇게하려고 노력할 것입니다. 그렇지 않으면 JNA와 협력 할 것입니다. 다시 한번 대단히 감사합니다! :) – SpyrosR