Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JNI C++ DLL - 'UnsatisfiedLinkError: %1 is not a valid Win32 application'

I am trying to actually get JNI working before I dive in with my actual code, but after I compile a DLL from C++ and run my Java application I get:

Exception in thread "main" java.lang.UnsatisfiedLinkError: <snip>\workspace\JNI test\native\jnitest.dll: %1 is not a valid Win32 application
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary1(Unknown Source)
    at java.lang.ClassLoader.loadLibrary0(Unknown Source)
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at net.condorcraft110.jnitest.JNITest.main(JNITest.java:11)

Having Googled this for a bit, I know that this is usually caused by trying to load a 64 bit DLL with a 32 bit JVM. However, my JVM is 64 bit, as evidenced by sun.arch.data.model equalling 64.

My makefile:

CLASSPATH = ../bin

vpath %.class $(CLASSPATH)

all : jnitest.dll

jnitest.dll : jnitest.o
    g++ -m64 -Wl,--add-stdcall-alias -shared -o $@ $<

jnitest.o : jnitest.cpp jnitest.h
    g++ -m64 -I"C:\Program Files\Java\jdk1.7.0_51\include" -I"C:\Program Files\Java\jdk1.7.0_51\include\win32" -c $< -o $@

jnitest.h : net/condorcraft110/jnitest/JNITest.class
    javah -verbose -classpath $(CLASSPATH) -o jnitest.h net.condorcraft110.jnitest.JNITest

clean :
    rm jnitest.h jnitest.o jnitest.dll

JNITest.java:

package net.condorcraft110.jnitest;

public class JNITest
{
    private static native void test();

    public static void main(String[] args)
    {
        System.out.println("sun.arch.data.model = " + System.getProperty("sun.arch.data.model"));

        System.loadLibrary("jnitest");

        test();
    }
}

jnitest.h as generated by javah:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_condorcraft110_jnitest_JNITest */

#ifndef _Included_net_condorcraft110_jnitest_JNITest
#define _Included_net_condorcraft110_jnitest_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     net_condorcraft110_jnitest_JNITest
 * Method:    loadPlugins
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_net_condorcraft110_jnitest_JNITest_test
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

jnitest.cpp:

using namespace std;

#include <jni.h>
#include <iostream>
#include "jnitest.h"

extern "C" JNIEXPORT void JNICALL Java_net_condorcraft110_jnitest_JNITest_test(JNIEnv *env, jclass clazz)
{
    cout << "jni test successful" << endl;
}

Anyone know why this isn't working?

Edit: java.library.path definitely points to native, as set up in an Eclipse run configuration.
Edit 2: the DLL works if I compile it with VS2013, but I really don't want to tie my project to Visual Studio if I can help it.

like image 375
condorcraft110 II Avatar asked Feb 09 '15 19:02

condorcraft110 II


2 Answers

I was initially getting Can't find dependent libraries error, to resolve which I added the DLLs in the path. But this led me to the error %1 is not a valid Win32 application at java. To resolve it all, making a static build worked for me, which compiles with: g++ -static. It adds the dependent libraries in the build itself.

like image 63
Caesar Avatar answered Sep 20 '22 14:09

Caesar


For me, the problem was that my newly-added DLL relied on other DLLs I didn't know about. Windows helpfully went out and found a 32-bit version in my path, but was unable to load it, as my application is 64-bit.

I used Dependency Walker (there are 32 and 64-bit versions, as well as Itanium...) and Process Monitor to debug this. The long and short of it is make sure that every single DLL that your DLL pulls in is also 64-bit, and you'll be a lot happier.

One thing to watch out for is if Windows finds a 32-bit DLL of the right name it will try to load it, and in Process Monitor it will look like it's reading it successfully. Make sure to keep scrolling down!! You may find that the system discards this DLL and moves on to keep searching the path for a 64-bit version.

Update:
Two other things to be aware of:

1) Old Dependency Walker can look like there are mismatches for the DLLs it loads e.g. it might find a 32-bit match first, when you really wanted a 64-bit DLL, and tell you there are CPU type mismatches. Just get the new version, and this issue goes away. Thanks to https://stackoverflow.com/a/22384936/309502 for this information.

2) Order matters when you're loading DLLs. I didn't realize I was loading two of them in the wrong order and could not figure out why it wasn't working. Check that you load the prerequisites first. :-)

like image 39
kmort Avatar answered Sep 23 '22 14:09

kmort