2014-01-10 2 views
0

При попытке получить уведомление от приложения 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 

затем обратный вызов не работает на выходе

+0

Возможно, что существует дефицит stdcall; Мне пришлось добавить поддержку обратного вызова stdcall в libffi, чтобы JNA поддерживала его. – technomage

+0

спасибо за ответ, не могли бы вы немного объяснить, этот недостаток вы имеете в виду? поскольку я знаю, что в JNA уже существует поддержка stdcall, которая отлично работает для другого метода с другой подписью. , например, это работает плавно ЬурейаЯ пустоту (__stdcall * TRANS2QUIK_TRANSACTION_REPLY_CALLBACK) (длинный nTransactionResult, длинные nTransactionExtendedErrorCode, длинные nTransactionReplyCode, DWORD dwTransId, двойная dOrderNum, LPCSTR lpcstrTransactionReplyMessage); содержит те же типы аргументов, но только 6 аргументов вместо 11 в «плохом» случае. Может ли это быть пределом длины массива в libffi? .. –

+0

Я очень рад, что автор проекта отвечает на меня, приветствует Тимоти! BTW, я подумал больше и решил, что ошибаюсь в подозрительной длине массива. До тех пор, пока все аргументы переданы обратному вызову Java, функция пересылки работает нормально, ошибка в том, что касается части очистки, я считаю. –

ответ

2

Проблема связана с ошибкой в ​​libffi, где выравнивание стеки корректируются в зависимости от размера аргумента, который неправильное поведение для stdcall.

Смежные вопросы