2011-06-02 32 views
6

Hem Windows hem de Linux'ta çalışacak bir java projesi üzerinde çalışıyorum ve her iki işletim sisteminde de kullanılabilen üçüncü taraf bir paylaşılan kitaplık kullanıyorum aynı yöntemlerin imzası. Ancak dll'nin çağrı kuralı, paylaşılan nesne cdecl iken stdcall'tır.JDN'de .dll ve .so aynı geri çağırma imzasıyla nasıl kullanılır?

Geri arama kodunu, iki arabirimi ve iki sınıfı, her arama kuralı için bir arabirimi çoğaltmaktan kaçınmak istiyorum. Geri arama işlevi için tek bir kod yazmak istiyorum. Mümkün mü?

Linux'a erişmek için aşağıdaki koddaki tek değişiklik, arabirimdir. Geriçağırım işlevi kodu kendisi aynıdır. Herhangi bir emziği takdir edeceğim.

//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 
    } 
} 

sayesinde

Fernando

cevap

0

Ben JNAWrapper etrafında başka bir sarmalayıcı olurdu:

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

Bu

ben dll geri arama için yazdığı kodudur. Örneğin, dll için JNA sarmalayıcısı IExternLibWindows ve Linux için bir tane IExternLibLinux olarak adlandırılırsa, başka bir sarıcı yazabilirim - IExternLib. Sonra ,

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

technomage tepkisi çok çok daha KISS uyumludur kodun çoğalmasını önler ve önlenebilir “if” (somefunc2'yi uygulamanız gerektiğinde ne yapacaksınız?) – Cerber

3

Sen StdCallLibrary/StdCallCallback ile ikisini ilan edebilir, ancak davranış tüm platformlarda tanımlanabilir olmayabilir. Bu seçenek, alternatif çağrı kurallarını desteklemeyen platformlarda yok sayılır (şu anda win32 dışındaki her şeydir), ancak mutlaka tüm platformlarda test edilmemiştir.

stdcall kitaplığını yalnızca pencereler için tanımlayan tercih edilen tanım budur.

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); 
} 

sadece (gerçi ben bu test öneriyoruz) linux ve pencereler, yeterli olabilir daha sonra tek bir arayüz hedefliyorsanız:

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

Merhaba, bunun nasıl yapılacağını örnek verebilir misiniz? – Fernando

+0

Yukarıdaki değişikliklere dikkat edin, yani pencereler dışında StdCallLibrary'ı kullanmayın. – technomage