Extract and Load Dll from Jar

Extract and load DLL from JAR

You need to put dll in your library path (recommended ) before you try to load it. so that you will have to extract it from jar and copy it into lib path .

private void loadLib(String path, String name) {
name = System.mapLibraryName(name); // extends name with .dll, .so or .dylib
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = getClass().getResourceAsStream("/" + path + name);
File fileOut = new File("your lib path");
outputStream = new FileOutputStream(fileOut);
IOUtils.copy(inputStream, outputStream);

System.load(fileOut.toString());//loading goes here
} catch (Exception e) {
//handle
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
//log
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
//log
}
}
}

}

Note: ACWrapper is the class holding the static method

How to get JNA to extract several DLL files from a jar file?

JNA show error "UnsatisfiedLinkError" when dll couldn't be loaded. If your DLL needs another custom DLLs not present in the system path it will fail, as JNA doesn't extract this dll automatically.

JNA as a Java library doesn't know the dependencies of the system library, so it can't extract from the jar. The solution is to specify all the dependencies in the JNA Java interfaces.

You can see an example here Load multiple dependent libraries with JNA


What is happening behind the scenes of the Operating System

At the end, the libraries are loaded by the operating system as requested by the main executable. In this case the main executable is java.exe or (jvm.dll). If the system can't find a library in the path it fails and java generates an exception.

Another related and solved question is Registering multiple .dll libraries into a single java class using JNA

Java - Loading dlls by a relative path and hide them inside a jar

I don't believe you can load the DLL directly from the JAR. You have to take the intermediary step of copying the DLL out of the JAR. The following code should do it:

public static void loadJarDll(String name) throws IOException {
InputStream in = MyClass.class.getResourceAsStream(name);
byte[] buffer = new byte[1024];
int read = -1;
File temp = File.createTempFile(name, "");
FileOutputStream fos = new FileOutputStream(temp);

while((read = in.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
fos.close();
in.close();

System.load(temp.getAbsolutePath());
}

How to make a JAR file that includes DLL files?

Just package it anywhere in the jar. One thing you have to keep in mind though - before you can use the DLLs you need to actually extract these from the JAR and dump these on the hard disk somewhere otherwise you won't be able to load these

So basically - I did JNI project for the client where I will use such jar packaged within the war. However - before running any native methods I would get the DLL as a resource and write it to the disc into temp directory. Then I would run regular initialization code where my DLL is set to the same location I just wrote DLL to

Oh, and just in case: there's nothing special about packaging dll or any other file into jar. It's just like packaging stuff into zip

Here's some code I just digged out

public class Foo {
private static final String LIB_BIN = "/lib-bin/";
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private final static String ACWRAPPER = "acwrapper";
private final static String AAMAPI = "aamapi51";
private final static String LIBEAU = "libeay32";

static {
logger.info("Loading DLL");
try {
System.loadLibrary(ACWRAPPER);
logger.info("DLL is loaded from memory");
} catch (UnsatisfiedLinkError e) {
loadFromJar();
}
}

/**
* When packaged into JAR extracts DLLs, places these into
*/
private static void loadFromJar() {
// we need to put both DLLs to temp dir
String path = "AC_" + new Date().getTime();
loadLib(path, ACWRAPPER);
loadLib(path, AAMAPI);
loadLib(path, LIBEAU);
}

/**
* Puts library to temp dir and loads to memory
*/
private static void loadLib(String path, String name) {
name = name + ".dll";
try {
// have to use a stream
InputStream in = ACWrapper.class.getResourceAsStream(LIB_BIN + name);
// always write to different location
File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
logger.info("Writing dll to: " + fileOut.getAbsolutePath());
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
System.load(fileOut.toString());
} catch (Exception e) {
throw new ACCoreException("Failed to load required DLL", e);
}
}
// blah-blah - more stuff
}

How to copy files out of the currently running jar

Since your dlls are bundeled inside your jar file you could just try to acasses them as resources using ClassLoader#getResourceAsStream and write them as binary files any where you want on the hard drive.

Here is some sample code:

InputStream ddlStream = <SomeClassInsideTheSameJar>.class
.getClassLoader().getResourceAsStream("some/pack/age/somelib.dll");

try (FileOutputStream fos = new FileOutputStream("somelib.dll");){
byte[] buf = new byte[2048];
int r;
while(-1 != (r = ddlStream.read(buf))) {
fos.write(buf, 0, r);
}
}

The code above will extract the dll located in the package some.pack.age to the current working directory.

Java problem loading native lib inside jar

First off some good advices:

  • remove all unnecessary jar files from your project (they might cause problems similar to yours)
  • do not mix different versions of LWJGL jar files (might cause problems similar to yours)
  • do not mix different versions of LWJGL native .dll files (might cause problems similar to yours)
  • use only really needed native .dll files (sometime unnecessary ones may cause errors like yours)

Now here is your code updated by me for automatic detection of all native files in internal natives folder without need of manually defining them + rest is basically yours - tested myself, all works as it should.

//INITIALIZATION OF NATIVE LIBS PACKED INSIDE THE COMPILLED JAR
static {
try {
String internalNativesFolder = "natives";

//EXTRACT NATIVE LIB(S) FROM JAR
File tmpDir = new File(App.FILE_APPPATH.getAbsolutePath() + App.LOMKA_R + internalNativesFolder);
if (tmpDir.exists()) {
FileUtils.deleteDirectory(tmpDir);
}
tmpDir.mkdir();

//GETS ALL FILES IN INTERNAL NATIVES FOLDER
URI uri = App.class.getResource(App.LOMKA_R + internalNativesFolder).toURI();
Path myPath;
if (uri.getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
myPath = fileSystem.getPath(App.LOMKA_R + internalNativesFolder);
} else {
myPath = Paths.get(uri);
}
Stream<Path> walk = Files.walk(myPath, 1);
List<String> libNames = new ArrayList<>();
for (Iterator<Path> it = walk.iterator(); it.hasNext();) {
String fN = it.next().getFileName().toString();
if (!fN.equals(internalNativesFolder)) {
libNames.add(fN);
}
}

//COPIES THOSE FILES TO TEMPORARY LOCAL DIRECTORY
for (String libName : libNames) {
URL url = Class.class.getResource(App.LOMKA_R + internalNativesFolder + App.LOMKA_R + libName);
File nativeLibTmpFile = new File(tmpDir, libName);
try (InputStream in = url.openStream()) {
Files.copy(in, nativeLibTmpFile.toPath());
}
}

//ADD PATH TO EXTRACTED LIBS FOLDER TO JAVA
System.setProperty("java.library.path", tmpDir.getAbsolutePath());
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);

//LOAD LIB DLL FILE(S)
libNames.forEach(libName -> {
System.load(new File(tmpDir, libName).getAbsolutePath());
});

} catch (IOException | SecurityException | IllegalArgumentException | NoSuchFieldException | IllegalAccessException | URISyntaxException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
}
}

Where to put my .dll to be accessed in my jar

Just package it anywhere in the jar. One thing you have to keep in mind though - before you can use the DLLs you need to actually extract these from the JAR and dump these on the hard disk somewhere otherwise you won't be able to load these

How to make a JAR file that includes DLL files?



Related Topics



Leave a reply



Submit