Search code examples
javajna

JNA: java.lang.Error: Invalid memory access - TS3 Library


I'm using JNA to access some dll function from Java, this dll Native Function is declared as the following:

unsigned int ts3client_initClientLib(const struct ClientUIFunctions* functionPointers, const struct ClientUIFunctionsRare* functionRarePointers, int usedLogTypes, const char* logFileFolder, const char* resourcesFolder);

and so, I declared it inside library interface as the following:

int ts3client_initClientLib(Structure functionPointers, Structure functionRarePointers, int usedLogTypes, String logFileFolder, String resourcesFolder);

and then I call it the following way:

ts3client_initClientLib(null, null, 1, "log.log", "soundbackends");

but I'm getting the following Exception:

Exception in thread "main" java.lang.Error: Invalid memory access
    at com.sun.jna.Native.invokeInt(Native Method)
    at com.sun.jna.Function.invoke(Function.java:383)
    at com.sun.jna.Function.invoke(Function.java:315)
    at com.sun.jna.Library$Handler.invoke(Library.java:212)
    at com.sun.proxy.$Proxy0.ts3client_initClientLib(Unknown Source)
    at pl.edu.tirex.ts3musicbot.MusicBot.main(MusicBot.java:17)

Solution

  • Correct solution:

    Create event interface:

    import com.sun.jna;
    
    public interface ServerErrorEvent implements Callback
    {
        void invoke(long serverConnectionHandlerID, String errorMessage, int error, String returnCode, String extraMessage);
    }
    

    Create Client UI Functions Structure:

    import com.sun.jna.Structure;
    
    public class EventsStructure extends Structure
    {
        public ServerErrorEvent onServerErrorEvent;
    
        @SuppressWarnings("rawtypes")
        @Override
        protected List<String> getFieldOrder() 
        {
            List<String> fields = new ArrayList<String>();
            for (Field f : this.getClass().getDeclaredFields())
            {
                boolean has = false;
                for (Class<?> c : f.getType().getInterfaces())
                {
                    if (c.equals(DefaultEvent.class))
                    {
                        has = true;
                    }
                }
                if (has)
                {
                    fields.add(f.getName());
                }
            }
            return fields;
        }
    }
    

    Use following methods:

    EventsStructure eventStructure = new EventsStructure();
    eventStructure.onServerErrorEvent = new ServerErrorEvent() //implement server error event
    {
        @Override
        public void invoke(long serverConnectionHandlerID, String errorMessage, int error, String returnCode, String extraMessage)
        {
            System.out.println("server error");
        }
    };
    ts3client_initClientLib(eventStructure, null, 0, "logs", "soundbackends"); //invoke ts3client_initClientLib function from library