2011-06-02 7 views
6

Estoy trabajando en un proyecto de Java para ejecutar en Windows y Linux, y estoy usando una biblioteca compartida de terceros disponible para ambos sistemas operativos con la misma firma de métodos Pero, la convención de llamadas del dll es stdcall mientras que el objeto compartido es cdecl.Cómo usar JNA en .dll y .so con la misma firma de devolución de llamada

Me gustaría evitar duplicar el código de devolución de llamada, dos interfaces y dos clases, una interfaz para cada convención de llamadas. Me gustaría escribir un código único para la función de devolución de llamada. ¿Es eso posible?

El único cambio en el siguiente código para acceder a .so en Linux es la interfaz. El código de la función de devolución de llamada es el mismo. Apreciaré cualquier sugerencia.

import com.sun.jna.Callback; 
interface IExternLibCallback extends Callback {..} 

Este es el código que escribí para la devolución de llamada en DLL:

//Interface to stdcall (Windows) 
package test1; 
import com.sun.jna.win32.StdCallLibrary; 
interface IExternLibCallback extends StdCallLibrary.StdCallCallback { 

     void callback (JEventDataStructure context_data); 
} 

//Class that implements the interface 
package test1; 
class ExternLibCallback implements IExternLibCallback { 

    ... Other class codes go here .... 

    @ Override 
    public void callback (JEventDataStructure contextData) { 

    ... Code of callback function 
    } 
} 

Gracias,

Fernando

Respuesta

0

Me gustaría tener otra envoltura alrededor de la JNAWrapper. Entonces, por ejemplo, si el contenedor JNA para el dll se llama IExternLibWindows y el de Linux se llama IExternLibLinux, escribiría otro contenedor - IExternLib. entonces,

public interface IExternLibWindows extends StdCallLibrary{ 
    public IExternLibWindows Instance ; 
... 
    void stdcall_somefunc(...); 
... 
} 

public interface IExternLibLinux extends StdCallLibrary{ 
    public IExternLibLinux Instance ; 
... 
    void cdecl_somefunc(...); 
... 
} 

public class IExternLib(){ 

    public void somefunc(...){ 
     if(System.getProperty("os.name").startsWith("Windows")) 
      IExternLibWindows.stdcall_somefunc(...); 
     else if(System.getProperty("os.name").startsWith("Linux")) 
      IExternLibLinux.cdecl_somefunc(...); 

    } 
} 
+0

de technomage es mucho más compatible BESO ya que previene multiplicaciones de código y 'if' evitables (¿qué harás cuando necesites implementar' somefunc2') – Cerber

3

Se puede declarar a ambos con StdCallLibrary/StdCallCallback, pero el comportamiento no puede ser definido en todas las plataformas. La opción se ignora en plataformas que no admiten una convención de llamadas alternativa (que es todo menos win32 en este momento), pero no ha sido necesariamente probada en todas las plataformas.

Esta es la definición preferida, que define la biblioteca stdcall solo para Windows.

interface MyLibrary extends Library { 
    interface MyCallback extends Callback { 
     public void invoke(); 
    } 
    void callbackFunction(MyCallback cb); 
    MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary("mylib", Platform.isWindows() ? MyWin32Library.class : MyLibrary.class); 
} 
interface MyWin32Library extends MyLibrary, StdCallLibrary { 
    interface MyStdCallCallback extends MyCallback, StdCallCallback {} 
    void callbackFunction(MyStdCallCallback cb); 
} 

si sólo está apuntando Linux y Windows, a continuación, una única interfaz puede bastar (recomiendo probar esto, sin embargo): respuesta

interface MyLibrary extends StdCallLibrary { 
    interface MyCallback extends StdCallCallback { 
     public void invoke(); 
    } 
    void callbackFunction(MyCallback cb); 
    MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary("mylib", MyLibrary.class); 
} 
+0

Hola, podrías dar un ejemplo de cómo hacerlo? – Fernando

+0

Tenga en cuenta los cambios anteriores, es decir, no use StdCallLibrary excepto en Windows. – technomage

Cuestiones relacionadas