Question

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.

Was it helpful?

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.

OTHER TIPS

Look at how the test library within JNA is built (native/Makefile). Following that example will indicate proper export signatures and calling conventions.

__declspec(dllexport) indicates that the function name should be exported.

__stdcall is what is used by most MS APIs; you normally have no reason to use it in your own code, as it only complicates linking with its mangling of names.

When actually compiling (and linking), you need to tell GCC that you're building a shared library. Simply naming the file "*.dll" isn't sufficient.

gcc -o mydll.dll -shared mydll.c 

You may need one or more -l<libname> options at the end depending on what native libraries you're accessing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top