February 13th, 2009

stupid

JNI function names depend on the package name your Java code uses.


- You must do a System.loadLibrary( "mylib" ) [or System. load( "C:\\libs\\mylib.dll" ) for Windows] [or System.load( "lib/mylib.so" ) for Linux] before you can use any native methods of a class.

- All your DLLs and all the DLLs they indirectly invoke must live on the java.library.path. Only exception is System.load, which requires you to specify the full path to the .DLL.

- If you get the UnsatisfiedLinkError when you invoke a native method, check that the *.cpp method signatures exactly match those in the *.h file. You should see method names like this: Java_com_mindprod_mouse_Mouse_GetMousePosition that start with the word Java and contain the package, class and method name all strung together.


http://mindprod.com/jgloss/runerrormessages.html#UNSATISFIEDLINKERROR

Notice that last point. If you take Java code, and move it into a new package, suddenly the "Java_OldPackageName_ClassName_MethodName" stuff in your C code is all wrong. The DLL will load up just fine, but you'll get a weird "UnsatisfiedLinkError" when you try and call your native methods. Really brilliant, Sun.

Also, System.loadLibrary() is just one big pain in the ass. If you use it, you generally have to copy your .dll to C:\Windows\System32\ or c:\Program Files\Java\jreXXX\ somewhere. Why??

I recommend something a lot more like this instead:

String libName = "MyNativeLib";

String libNameOnPlatform = System.mapLibraryName(libName); // => "MyNativeLib.(dll|so)"

// Search all the obvious places to try and find it.
java.net.URL libUrl = ClassLoader.getSystemClassLoader().getResource(libNameOnPlatform);

String libFullPath = libUrl.getPath(); // => "/c:\blah\blah.xxx"; note the leading "/"

if(libFullPath.startsWith("/")) { libFullPath = libFullPath.substring(1); }

if (! libFullPath.equals("")) {
System.load(libFullPath);
} else {
throw new RuntimeException("Can't find native library - " + libNameOnPlatform);
}


getResource() will usually find the file if it's in the current directory, in any of the directories that your .class files are in, in one of the .jars that you're using, etc. (Though in the .jar case System.load() will probably whine about not being able to load c:\dir\myjar.jar:MyNativeLib.dll or something.) Or you can just do System.load("C:\\full\\path\\to\\MyNativeLib.dll").