При попытке получить уведомление от приложения C++ через обратный вызов JNA, я постоянно вижу сбои JVM. Native.setProtected не помогает. Оригинальное объявление обратного вызоваJNA: __stdcall ESP коррупция
typedef void (__stdcall *TRANS2QUIK_ORDER_STATUS_CALLBACK) (long nMode, DWORD dwTransID, double dNumber, LPCSTR ClassCode, LPCSTR SecCode, double dPrice, long nBalance, double dValue, long nIsSell, long nStatus, long nOrderDescriptor);
^^^ это то, что не работает
Я пытался как StdCallLibrary.StdCallCallback, который должен работать и просто обратный вызов, они оба потерпели неудачу. Но после того, как я написал C++-оболочку, где я просто вызываю обратный вызов JNA как cdecl изнутри исходного обратного вызова stdcall C++, все стало работать гладко.
typedef void (*WRAPPED_ORDER_STATUS_CALLBACK) (double dNumber, double dPrice, long nBalance, double dValue, long nIsSell, long nStatus, long nOrderDescriptor);
QUIKWRAP_API TRANS2QUIK_ORDER_STATUS_CALLBACK __stdcall wrapCallback(WRAPPED_ORDER_STATUS_CALLBACK);
^^^^^^ это то, что работает плавно без проблем
Вопрос может ли это быть ЮНА ошибка специально для этой функции подписи? Потому что у меня есть еще один обратный вызов stdcall в моем коде с другой подписью, и он работает отлично.
Я создал изолированную TestCase для этого вопроса см ниже: ява
import java.util.HashMap;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.win32.StdCallLibrary;
public class JNATest {
interface TestCallback extends StdCallLibrary.StdCallCallback {
void testCallback(NativeLong nMode, WinDef.DWORD dwTransID, double dNumber, LPCSTR ClassCode, LPCSTR SecCode, double dPrice, NativeLong nBalance, double dValue, NativeLong nIsSell, NativeLong nStatus, NativeLong nOrderDescriptor);
}
interface JNADLL extends StdCallLibrary{
void testCallback(TestCallback cb);
}
public static class LPCSTR extends PointerType {
public LPCSTR(Pointer address) {
super(address);
}
public LPCSTR() {
super();
}
@Override
public String toString() {
return getPointer().getString(0);
}
};
/**
* @param args
*/
public static void main(String[] args) {
System.setProperty("jna.encoding", "Cp1251");
HashMap<String, Object> nameMapping = new HashMap<String, Object>();
nameMapping.put(Library.OPTION_FUNCTION_MAPPER, StdCallLibrary.FUNCTION_MAPPER);
nameMapping.put(Library.OPTION_CALLING_CONVENTION, StdCallLibrary.STDCALL_CONVENTION);
JNADLL JNADll = (JNADLL) Native.loadLibrary("QuikWrap", JNADLL.class, nameMapping);
TestCallback cb = new TestCallback() {
@Override
public void testCallback(NativeLong nMode, DWORD dwTransID,
double dNumber, JNATest.LPCSTR ClassCode, JNATest.LPCSTR SecCode,
double dPrice, NativeLong nBalance, double dValue,
NativeLong nIsSell, NativeLong nStatus, NativeLong nOrderDescriptor) {
System.out.println("testCallback \n" +
" nMode: " + nMode + "\n" +
" dwTransID: " + dwTransID + "\n" +
" number: " + dNumber + "\n" +
" ClassCode: " + ClassCode + "\n" +
" SecCode: " + SecCode + "\n" +
" price: " + dPrice + "\n" +
" balance: " + nBalance + "\n" +
" value: " + dValue + "\n" +
" isSell: " + nIsSell + "\n" +
" status: " + nStatus + "\n" +
" orderDescriptor: " + nOrderDescriptor + "\n");
}
};
JNADll.testCallback(cb);
}
}
с заголовок QuikWrap.h
#ifdef QUIKWRAP_EXPORTS
#define QUIKWRAP_API extern "C"__declspec(dllexport)
#else
#define QUIKWRAP_API __declspec(dllimport)
#endif
typedef void (__stdcall *TRANS2QUIK_ORDER_STATUS_CALLBACK) (long nMode, DWORD dwTransID, double dNumber, LPCSTR ClassCode, LPCSTR SecCode, double dPrice, long nBalance, double dValue, long nIsSell, long nStatus, long nOrderDescriptor);
QUIKWRAP_API void __stdcall testCallback(TRANS2QUIK_ORDER_STATUS_CALLBACK cb);
с источником QuikWrap.cpp
#include "stdafx.h"
#include "QuikWrap.h"
#include "stdio.h"
QUIKWRAP_API void __stdcall testCallback(TRANS2QUIK_ORDER_STATUS_CALLBACK cb){
cb(1, 2, 3, "Hi", "Bye", 4.0, 5, 6, 7, 8, 9);
cb(0, 2, 3, "Hi", "Bye", 4.0, 5, 6, 7, 8, 9);
return;
}
onl у выхода из обратного вызова я получил это
testCallback
nMode: 1
dwTransID: 2
number: 3.0
ClassCode: Hi
SecCode: Bye
price: 4.0
balance: 5
value: 6.0
isSell: 7
status: 8
orderDescriptor: 9
затем обратный вызов не работает на выходе
Возможно, что существует дефицит stdcall; Мне пришлось добавить поддержку обратного вызова stdcall в libffi, чтобы JNA поддерживала его. – technomage
спасибо за ответ, не могли бы вы немного объяснить, этот недостаток вы имеете в виду? поскольку я знаю, что в JNA уже существует поддержка stdcall, которая отлично работает для другого метода с другой подписью. , например, это работает плавно ЬурейаЯ пустоту (__stdcall * TRANS2QUIK_TRANSACTION_REPLY_CALLBACK) (длинный nTransactionResult, длинные nTransactionExtendedErrorCode, длинные nTransactionReplyCode, DWORD dwTransId, двойная dOrderNum, LPCSTR lpcstrTransactionReplyMessage); содержит те же типы аргументов, но только 6 аргументов вместо 11 в «плохом» случае. Может ли это быть пределом длины массива в libffi? .. –
Я очень рад, что автор проекта отвечает на меня, приветствует Тимоти! BTW, я подумал больше и решил, что ошибаюсь в подозрительной длине массива. До тех пор, пока все аргументы переданы обратному вызову Java, функция пересылки работает нормально, ошибка в том, что касается части очистки, я считаю. –