B4J Question BASS library, Java Native Access, and Structure problem

rdkartono

Member
Licensed User
Longtime User
I wrapped BASS library using Java Native Access(JNA) in Eclipse for sometime ago, and every methods I wanted, worked correctly.
Callbacks that I needed, also worked correctly.

Now I want to implement BASS_StreamCreateFileUser function, declared in C like below :
B4X:
HSTREAM BASS_StreamCreateFileUser(DWORD system, DWORD flags, BASS_FILEPROCS *procs, void *user);

In JNA, I wrapped become :
B4X:
int BASS_StreamCreateFileUser(int system, int flags, Object resultstruct, Object buffer1);

This function require a structure, with 4 callbacks inside, declared in C like below :
B4X:
void CALLBACK FileCloseProc(
    void *user
);
QWORD CALLBACK FileLenProc(
    void *user
);
DWORD CALLBACK FileReadProc(
    void *buffer,
    DWORD length,
    void *user
);
BOOL CALLBACK FileSeekProc(
    QWORD offset,
    void *user
);

typedef struct {
    FILECLOSEPROC *close;
    FILELENPROC *length;
    FILEREADPROC *read;
    FILESEEKPROC *seek;
} BASS_FILEPROCS;
And I wrapped in JNA as below :
B4X:
public interface FILECLOSEPROC extends Callback{
           void invoke(Object user);
       }
       
       public interface FILELENPROC extends Callback{
           long invoke(Object user);
       }
       
       public interface FILEREADPROC extends Callback{
           int invoke(ByteBuffer buffer, int length, Object user);
       }
       
       public interface FILESEEKPROC extends Callback{
           boolean invoke(long offset, Object user);
       }

public class BASS_FILEPROCS1 implements Structure.ByReference {
           
           public FILECLOSEPROC filecloseproc;
           public FILELENPROC filelenproc;
           public FILEREADPROC filereadproc;
           public FILESEEKPROC fileseekproc;
           
           BASS_FILEPROCS1(){
               filecloseproc = new FILECLOSEPROC(){

                   @Override
                   public void invoke(Object user) {
                       // TODO Auto-generated method stub
                       System.out.println("FILECLOSEPROC is called");
                   }
                   
               };
               filelenproc = new FILELENPROC(){

                   @Override
                   public long invoke(Object user) {
                       // TODO Auto-generated method stub
                       System.out.println("FILELENPROC is called");
                       return 0;
                   }
                   
               };
               filereadproc = new FILEREADPROC(){

                   @Override
                   public int invoke(ByteBuffer buffer, int length, Object user) {
                       // TODO Auto-generated method stub
                       System.out.println("FILEREADPROC is called");
                       return 0;
                   }
                   
               };
               fileseekproc = new FILESEEKPROC(){

                   @Override
                   public boolean invoke(long offset, Object user) {
                       // TODO Auto-generated method stub
                       System.out.println("FILESEEKPROC is called");
                       return false;
                   }
                   
               };
           };
       }

Instancing a new variable in Java library as below :
B4X:
Bass.BASS_FILEPROCS1 myfileproc = new Bass.BASS_FILEPROCS1();

And using it in my function as below :
B4X:
public int bass_openstreamMP3(int flags) {
       Buffer1.clear();
       if (current_handle!=0) bass_stopcurrentplayback();
       bass.BASS_SetDevice(BASS_ID);   
       try{
           current_handle = bass.BASS_StreamCreateFileUser(BASS_CONSTANT.STREAMFILE_BUFFER, flags,myfileproc, null);
           System.out.println("MP3 Stream handle="+current_handle);
                   
       } catch(Exception ex){
           System.out.println(ex.getMessage());
       }
       
       if (current_handle!=0) raise_streamstart(BASS_ID); else raise_streamstop(BASS_ID);
       return current_handle;
   }

Library compiled, and used in B4J, and it will return
Unsupported argument type jbass.JBass$Bass$BASS_FILEPROCS1 at parameter 2 of function BASS_StreamCreateFileUser


I have spent 5 working days trying to figure out this Structure , tried every combinations i know, yet no luck.
Anybody have idea on how making this BASS_FILEPROCS1 structure in JNA ?
 

rdkartono

Member
Licensed User
Longtime User

they are using JNI, while I am implementing in JNA , which is much simpler and easy to understand, well... at least for me... Other functions can be done correctly, just this Structure with 4 callback thing is hard.

If I am correct, java is passing all object by Value, meanwhile above function will pass address of the structure (pointer). While I tried using JNA's Structure.ByReference, it doesn't work as intended.
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Just had a look at my old JoyPad program that uses JNA.
I use a structure that is by reference, this is the code
B4X:
 public static class ResultStruct extends Structure implements
   Structure.ByReference {
  public int dwSize;
  public int dwFlags;
  public int dwXpos;
  public int dwYpos;
  public int dwZpos;
  public int dwRpos;
  public int dwUpos;
  public int dwVpos;
  public int dwButtons;
  public int dwButtonNumber;
  public int dwPOV;
  public int dwReserved1;
  public int dwReserved2;
 }
 
Upvote 0

rdkartono

Member
Licensed User
Longtime User
I do have other functions that implements Structure.ByReference as your example, which only contains int or string, and they can work OK. This structure I mentioned, contains 4 Callback, that is the problem.
Other functions which only use 1 callback, I already can implement correctly.
Only function "StreamCreateFileUser" which use that structure, I can't implement.
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Did you extend Structure?
 
Upvote 0

rdkartono

Member
Licensed User
Longtime User
If I extends Structure and implements Structure.ByReference as below :
B4X:
public class BASS_FILEPROCS2 extends Structure implements Structure.ByReference{
            public FILECLOSEPROC filecloseproc;
            public FILELENPROC filelenproc;
            public FILEREADPROC filereadproc;
            public FILESEEKPROC fileseekproc;
            
            //BASS_FILEPROCS2(Pointer pp){
            //    super();
            //    useMemory(pp);
            //    read();
            //}
            
            public BASS_FILEPROCS2(){
                super();
                //ensureAllocated();
                //setAlignType(Structure.ALIGN_NONE);
                filecloseproc = new FILECLOSEPROC(){

                    @Override
                    public void invoke(Object user) {
                        // TODO Auto-generated method stub
                        System.out.println("FILECLOSEPROC is called");
                    }
                    
                };
                filelenproc = new FILELENPROC(){

                    @Override
                    public long invoke(Object user) {
                        // TODO Auto-generated method stub
                        System.out.println("FILELENPROC is called");
                        return 0;
                    }
                    
                };
                filereadproc = new FILEREADPROC(){

                    @Override
                    public int invoke(ByteBuffer buffer, int length, Object user) {
                        // TODO Auto-generated method stub
                        System.out.println("FILEREADPROC is called");
                        return 0;
                    }
                    
                };
                fileseekproc = new FILESEEKPROC(){

                    @Override
                    public boolean invoke(long offset, Object user) {
                        // TODO Auto-generated method stub
                        System.out.println("FILESEEKPROC is called");
                        return false;
                    }
                    
                };
            };
            @BA.Hide public void autoWrite(){}
            @BA.Hide public void autoRead(){}
            protected List<String> getFieldOrder() {
                // TODO Auto-generated method stub
                return Arrays.asList("filecloseproc","filelenproc","filereadproc","fileseekproc");
            }
            
        }

At execution in B4J, I will get Invalid Memory Access :
B4X:
Program started.
BASS version=2040c01
BASS_FX version=2040b01
DeviceID used = 1
DeviceName = Speakers (Realtek High Definition Audio)
Device Driver = {0.0.0.00000000}.{23ba0844-b9d4-48c3-8f40-5133400f9f24}
Device enabled
Device initialized
java.lang.Error: Invalid memory access
    at com.sun.jna.Native.invokeInt(Native Method)
    at com.sun.jna.Function.invoke(Function.java:390)
    at com.sun.jna.Function.invoke(Function.java:323)
    at com.sun.jna.Library$Handler.invoke(Library.java:236)
    at com.sun.proxy.$Proxy0.BASS_StreamCreateFileUser(Unknown Source)
    at jbass.JBass.bass_openstreamMP3(JBass.java:1357)
    at b4j.example.main._try_open_mp3_stream(main.java:147)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:613)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:228)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:159)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:90)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:93)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:77)
    at b4j.example.main.main(main.java:29)
java.lang.RuntimeException: java.lang.Error: Invalid memory access
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:119)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:93)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:77)
    at b4j.example.main.main(main.java:29)
Caused by: java.lang.Error: Invalid memory access
    at com.sun.jna.Native.invokeInt(Native Method)
    at com.sun.jna.Function.invoke(Function.java:390)
    at com.sun.jna.Function.invoke(Function.java:323)
    at com.sun.jna.Library$Handler.invoke(Library.java:236)
    at com.sun.proxy.$Proxy0.BASS_StreamCreateFileUser(Unknown Source)
    at jbass.JBass.bass_openstreamMP3(JBass.java:1357)
    at b4j.example.main._try_open_mp3_stream(main.java:147)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:613)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:228)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:159)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:90)
    ... 3 more
Program terminated (StartMessageLoop was not called).

and I am pretty sure by instancing BASS_FILEPROCS2 , Callbacks inside also instanced. I tested , they are not null...
 
Upvote 0
Top