2013-06-18 1 views
0

라디오 하드웨어와 상호 작용하는 데 사용하는 .DLL 및 온라인 API가 있습니다. JNA를 사용하여 Java를 통해 내 보낸 함수에 액세스합니다 (C/C++를 알지 못하기 때문에). 기본 메서드를 호출하고 일부 API 구조를 성공적으로 사용할 수 있지만 콜백 구조에 문제가 있습니다. 나는 TutorTutor 가이드 here을 따라 갔고 Mr. Wall의 권위있는 가이드 here도 시도했지만 구조체에 올바르게 설정된 콜백에 대한 자바 사이드 구문을 공식화하지 못했습니다.JNA를 사용하여 DLL의 내 보낸 함수를 통해 콜백의 C/C++ 구조에 액세스

BOOL __stdcall SetCallbacks(INT32 hDevice, 
          CONST G39DDC_CALLBACKS *Callbacks, DWORD_PTR UserData); 

이 기능은 C/C++ 구조 참조 :

나는이 보낸 된 함수 사용해야하는 API에 따라

typedef struct{ 
    G39DDC_IF_CALLBACK    IFCallback; 
    //more omitted 
} G39DDC_CALLBACKS; 

을 ...이 회원을 가지고 (이것은 내 보낸 함수가 아닙니다.) :

VOID __stdcall IFCallback(CONST SHORT *Buffer, UINT32 NumberOfSamples, 
          UINT32 CenterFrequency, WORD Amplitude, 
          UINT32 ADCSampleRate, DWORD_PTR UserData); 
//more omitted 

나는 G39DDCAPI.java를 가지고 있는데, DLL 라이브러리를로드하고 JNA의 도움을 받아 Java에서 함수를 내 보냈다. 그 일에 대한 간단한 호출은 잘 작동합니다.

위의 C/C++ 구조체를 다른 API 구조체의 형식으로 구현 한 G39DDC_CALLBACKS.java도 있습니다. 이 콜백 구조는 내가 구문 확실치 곳이다 :

import java.util.Arrays; 
import java.util.List; 
import java.nio.ShortBuffer; 
import com.sun.jna.Structure; 
import com.sun.jna.platform.win32.BaseTSD.DWORD_PTR; 
import com.sun.jna.win32.StdCallLibrary.StdCallCallback; 

public class G39DDC_CALLBACKS extends Structure { 
    public G39DDC_IF_CALLBACK    IFCallback; 
    //more omitted 

    protected List getFieldOrder() { 
     return Arrays.asList(new String[] { 
      "IFCallback","DDC1StreamCallback" //more omitted 
     }); 
    } 

    public static interface G39DDC_IF_CALLBACK extends StdCallCallback{ 
     public void invoke(ShortBuffer _Buffer,int NumberOfSamples, 
          int CenterFrequency, short Amplitude, 
          int ADCSampleRate, DWORD_PTR UserData); 
    } 
} 

편집

: 내가 Technomage 제안으로 내 인수가 더 타입 안전했다. 콜백을 호출하는 여러 시도와 함께 널 포인터 예외가 계속 발생합니다. 위의 콜백 구조에 관한 구문에 대해서는 잘 모르므로 아래에서 주 문제를 정확하게 지적 할 수 없습니다. 현재 관련 부분은 다음과 같습니다

int NumberOfSamples=65536;//This is usually 65536. 
ShortBuffer _Buffer = ShortBuffer.allocate(NumberOfSamples); 
int CenterFrequency=10000000;//Specifies center frequency (in Hz) of the useful band 
          //in received 50 MHz wide snapshot. 
short Amplitude=0;//The possible value is 0 to 32767. 
int ADCSampleRate=100;//Specifies sample rate of the ADC in Hz. 
DWORD_PTR UserData = null; 

G39DDC_CALLBACKS callbackStruct= new G39DDC_CALLBACKS(); 
lib.SetCallbacks(hDevice,callbackStruct,UserData); 
    //hDevice is a handle for the hardware device used-- works in other uses 
    //lib is a reference to the library in G39DDCAPI.java-- works in other uses 
    //The UserData is a big unknown-- I don't know what to do with this variable 
      //as a DWORD_PTR 
callbackStruct.IFCallback.invoke(_Buffer, NumberOfSamples, CenterFrequency, 
           Amplitude, ADCSampleRate, UserData); 

편집 NO 2 :

나는 하나의 콜백 다소 작업이,하지만 난 버퍼를 제어 할 필요가 없습니다. 좀 더 실망스럽게도,이 메소드를 호출하는 단일 호출은 일반적으로 여러 개의 출력 파일 (결과가 크게 달라짐)에서 사용자 정의 콜백을 여러 번 실행합니다. C/C++ 측에서 메모리를 확보 할 수 없기 때문에 또는 Java에 버퍼에 액세스하는 데 필요한 큐가 없기 때문에 Java 측에서 올바르게 메모리를 할당하지 않기 때문에 그 것인지 여부를 알 수 없습니다. 당신은 하나, StdCallCallback을 확장 할 필요가

//before this, main method sets library, starts DDCs, initializes some variables... 

//API call to start IF 
System.out.print("Starting IF...    "+lib.StartIF(hDevice, Period)+"\n") 
G39DDC_CALLBACKS callbackStructure = new G39DDC_CALLBACKS(); 
callbackStructure.IFCallback = new G39DDC_IF_CALLBACK(){ 

    @Override 
    public void invoke(Pointer _Buffer, int NumberOfSamples, int CenterFrequency, 
      short Amplitude, int ADCSampleRate, DWORD_PTR UserData ) { 

    //notification 
     System.out.println("Invoked IFCallback!!"); 

     try { 
    //ready file and writers 
      File filePath = new File("https://stackoverflow.com/users/user/G39DDC_Scans/"); 
      if (!filePath.exists()){ 
       System.out.println("Making new directory..."); 
       filePath.mkdir(); 
      } 

      String filename="Scan_"+System.currentTimeMillis(); 
      File fille= new File("https://stackoverflow.com/users/user/G39DDC_Scans/"+filename+".txt"); 
      if (!fille.exists()) { 
       System.out.println("Making new file..."); 
       fille.createNewFile(); 
      } 

      FileWriter fw = new FileWriter(fille.getAbsoluteFile()); 
    //callback body 
      short[] deBuff=new short[NumberOfSamples]; 
      int offset=0; 
      int arraySize=NumberOfSamples; 

      deBuff=_Buffer.getShortArray(offset,arraySize); 
      for (int i=0; i<NumberOfSamples; i++){ 
       String str=deBuff[i]+","; 
       fw.write(str); 
      } 
       fw.close(); 
     } catch (IOException e1) { 
      System.out.println("IOException: "+e1); 
     } 
    } 
}; 

lib.SetCallbacks(hDevice, callbackStructure,UserData); 
System.out.println("Main, before callback invocation"); 

callbackStructure.IFCallback.invoke(s_Pointer, NumberOfSamples, CenterFrequency, Amplitude, ADCSampleRate, UserData); 
System.out.println("Main, after callback invocation"); 

//suddenly having trouble stopping DDCs or powering off device; assume it has to do with dll using the functions above 
    //System.out.println("StopIF: " + lib.StopIF(hDevice));//API function returns boolean value 
    //System.out.println("StopDDC2: " + lib.StopDDC2(hDevice, Channel)); 
    //System.out.println("StopDDC1: " + lib.StopDDC1(hDevice, Channel)); 
    //System.out.println("test_finishDevice: " + test_finishDevice(hDevice, lib)); 

System.out.println("Program Exit"); 

//END MAIN METHOD 

답변

0

네이티브 코드가 자바 코드를 호출 할 때, 그렇지 않으면 당신은 가능성이 충돌 것, :. 같은 관련 코드가 보인다.

_PTR이있는 Windows 유형이있는 모든 곳에서는 PointerType을 사용해야합니다. JNA의 플랫폼 패키지에는 DWORD_PTR 및 친구들에 대한 정의가 포함되어 있습니다.

마지막으로 G39DDC_IF_CALLBACK에 원시 배열 인수를 사용할 수 없습니다. Pointer 또는 NIO 버퍼를 사용해야합니다. 원하는 길이의 어레이를 제공함으로써 short[]을 추출하기 위해 Pointer.getShortArray()을 사용할 수있다.

예, 당신이 그렇지 않으면 당신은 단지 자바 나에 대한 불만의 원인이됩니다 NULL 포인터를 전달하는, 네이티브 함수에 전달하기 전에 콜백 구조에서 콜백 필드를 초기화해야 EDIT 네이티브 쪽 또는 둘 다.

는 선언 된 콜백 함수 인터페이스의 익명의 인스턴스를 사용하여 콜백을 생성하는 데 걸리는 무엇을 : 나는 대답은 내가 가진 하나의 오해를 정정 알고

myStruct.callbackField = new MyCallback() { 
    public void invoke(int arg) { 
     // do your stuff here 
    } 
}; 
+0

을; StdCallCallback은 백그라운드 Windows OS와의 상호 작용에만 사용되었습니다. 나는 제안이 결국 나의 질문에 답할 것이라고 생각하지만 새로운 코드를 시도하기 전에 NIO 버퍼를 읽어야한다. 지금 당장 고마워. 그리고 내가 일하는 것을 얻 자마자 나는 그 대답을 받아 들일 것인가로 점검 할 것이다. –

+0

위에서 본 것처럼 여러 가지 유형을 변경했습니다. 내 접근 방식이 완전히 잘못되었다는 것을 알고 있습니다. 콜백 구조는 사용자 정의 콜백에 대한 액세스를 제공 할 예정입니다. 즉, 라인을 따라 어딘가에 Java 측에서 메소드 본문을 제공 할 장소가 필요합니다. 제 문제 중 일부는 컴파일러가 불평하지 않고이 작업을 수행 할 수 있습니다. –

+0

귀하의 의견을 사용하여, 나는 자바 문법이 작동하는 문법을 가지고 있다는 것을 나타내는 일반적인 println 문을 실행할 수있게되었다. 나는 여전히 버퍼 관리에 몇 가지 문제를 겪고있다. 나중에 업데이트 할 수있게되면 나중에 업데이트를 게시 할 것입니다. –