Search code examples
javacdlljnaunsatisfiedlinkerror

JNA cannot find function


JNA and DLLs are completely new territory for me... I have a custom DLL that has a function with this declaration:

int myfunc (const char*);

The dll compiles fine under MinGW with the following command:

>gcc -shared -omydll.dll mydll.c -lgdi32

However, loading it with JNA fails because it can't find the function within the DLL.

public interface mydll extends StdCallLibrary {
  mydll INSTANCE = (mydll)Native.loadLibrary("mydll", mydll.class);
  int myfunc (String arg);
  }

I did some research and it seems that this particular error has something to do with the calling procedure of the DLL functions. I've seen the __stdcall and the __cdecl procedures. I also saw that many DLL functions put __declspec(dllexport) in front of their function declarations/implementations (i have no idea what this means or what it does). So, since JNA seems to like the __stdcall procedure better, now my function looks like this:

__declspec(dllexport) int __stdcall myfunc (const char*);

Which looks super-complicated, but does no better than anything else i've tried. Using a HashMap to add the underscore prefix and the @4 suffix didn't work either:

mydll INSTANCE = (mydll)Native.loadLibrary("mydll", mydll.class, new HashMap () {{
  add("myfunc", "_myfunc@4");
  }});

The JNA documentation has been absolutely no help. I honestly have no idea what i'm doing anymore.


Solution

  • Turns out that i was building my DLL just fine, and JNA was finding my DLL just fine as well; i made an error in determining how the compiler mangled my symbols. Functions i named like myfunc were exported as myfunc@8 or myfunc@32 depending on how many bytes they took as arguments. Here's the code i used in my JNA project:

    import java.util.*;
    import com.sun.jna.*;
    import com.sun.jna.win32.*;
    //
    public class Test
      {
      public interface mydll extends StdCallLibrary
        {
        mydll INSTANCE = Native.loadLibrary("mydll", mydll.class, new HashMap {{
          put("myfunc", "myfunc@8");
          //Other functions
          }});
        public int myfunc (long arg);
        //Other functions
        }
      //
      public static void main (String[] args)
        {
        System.out.println
          (mydll.INSTANCE.myfunc((long)0x23A3920F)); //Or whatever
        return 0;
        }
      }
    

    My c code:

    #include <windows.h>
    #include <stdio.h>
    
    __declspec(dllexport) int __stdcall myfunc (__int64);
    /* Other functions */
    
    __declspec(dllexport) int __stdcall myfunc (__int64 arg)
      {
      /* Whatever */
      return return_value;
      }
    

    GCC was happy with just the -shared switch and linking against the proper libraries, like in my original question. I highly recommend downloading this tool so you can find out exactly what your function names are.