我有一个供应商提供的.DLL和一个在线API,我用来与一个无线电硬件进行交互;我正在使用JNA通过Java访问导出的函数(因为我不知道C / C ++)。我可以调用基本方法并成功使用一些API结构,但是我遇到了回调结构的问题。我遵循了TutorTutor指南here并尝试了Wall先生的权威指南here,但我无法为结构中正确设置的回调制定Java端语法。
我需要使用导出的功能:
BOOL __stdcall SetCallbacks(INT32 hDevice,
CONST G39DDC_CALLBACKS *Callbacks, DWORD_PTR UserData);
此功能引用 C / C ++结构:
typedef struct{
G39DDC_IF_CALLBACK IFCallback;
//more omitted
} G39DDC_CALLBACKS;
...根据API有这些成员(注意这不是导出的函数):
VOID __stdcall IFCallback(CONST SHORT *Buffer, UINT32 NumberOfSamples,
UINT32 CenterFrequency, WORD Amplitude,
UINT32 ADCSampleRate, DWORD_PTR UserData);
//more omitted
我有一个G39DDCAPI.java,我在JNA的帮助下加载了DLL库并用Java重现了API导出的函数。对此工作的简单调用很好。
我还有一个G39DDC_CALLBACKS.java,我已经以适用于其他API结构的格式实现了上述C / C ++结构。这个回调结构是我不确定语法的地方:
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:
我有一个回调工作,但我无法控制缓冲区。更令人沮丧的是,调用该方法的单个调用将导致多次运行自定义回调,通常具有多个输出文件(结果在运行之间变化很大)。我不知道是不是因为我没有在Java端正确分配内存,因为我无法释放C / C ++端的内存,或者因为我没有告诉Java访问缓冲区等的提示相关代码如下:
//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("/users/user/G39DDC_Scans/");
if (!filePath.exists()){
System.out.println("Making new directory...");
filePath.mkdir();
}
String filename="Scan_"+System.currentTimeMillis();
File fille= new File("/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 :(得分:0)
您需要扩展StdCallCallback
,否则当本机代码尝试调用Java代码时,您可能会崩溃。
如果您看到带有_PTR
的Windows类型的任何地方,则应使用PointerType
- 带有JNA的平台包中包含DWORD_PTR
和朋友的定义。
最后,您的G39DDC_IF_CALLBACK
中不能有原始数组参数。您需要使用Pointer
或NIO缓冲区;然后可以使用Pointer.getShortArray()
通过提供所需的数组长度来提取short[]
。
修改强>
是的,你需要在回调结构中初始化你的回调字段,然后再将它传递给你的本机函数,否则你只是传递一个NULL指针,这会引起对Java或本机或两者的抱怨。
这是使用声明的回调函数接口的匿名实例创建回调所需的:
myStruct.callbackField = new MyCallback() {
public void invoke(int arg) {
// do your stuff here
}
};