Search code examples
javac++dlljava-native-interfaceunsatisfiedlinkerror

Unresolved link error using JNI to load C# into Java project


I am attempting to load a DLL in my Java project, to allow me to use some code from C#. I made a sample and attempted to implement it in my Java project, however I am stuck receiving the following error when I attempt to run my Java project (Designer) :

D:\RPMOpen\svnCobra\conversion\Designer>designer

D:\RPMOpen\svnCobra\conversion\Designer>java -jar Designer.jar "D:/RPMOpen/svnCobra"
Exception in thread "main" java.lang.UnsatisfiedLinkError: main/Designer.displayHeyLand()V
        at main.Designer.main(Designer.java:491)

What I find curious is that I was receiving an error with respect to loading my DLL in my Java project which I managed to fix, and in the following code from my Java project if I comment out the last line my Designer works fine now. This suggests to me that my .DLL is in fact loading properly, but really confuses me as to why I am receiving a UnsatisfiedLinkError.

Java project sample code:

static {
        System.load("D://RPMOpen/svnCobra/Java/Designer/HeyLand.dll");
        }

    public native void displayHeyLand();

    public static void main(String[] args)
    {
        if (args.length == 0)
        {
            throw new IllegalArgumentException("Conversion location required");
        }



    cobraLocation = args[0];
            INPUT = cobraLocation + "/conversion/src/vb/";
            OUTPUT = cobraLocation + "/conversion/aui/Designer/";
            //System.loadLibrary(cobraLocation + "/conversion/Designer/GetFRXWrapper.dll");
            //String s = getFromFRX();
            //System.out.println(s);

            Designer t = new Designer();
            t.displayHeyLand();

Original C# code attempting to be implemented:

using System;
using System.Windows.Forms;

public class CSharpHeyLand
{
    public CSharpHeyLand() { }

    public void displayHeyLand()
    {
        MessageBox.Show("Hey Java, this is C#!", "Sample");
    }
 }

Elements from my wrapper, comprising of a C++ source file and two header files:

 //Cpp file HeyLand.cpp *******************************************

#include <jni.h>
#include "Java\HeyWork.h"



// managed c++ header containing call to c#
#include "MCPP\HeyLand.h"

// JNI call to managed C++ Class

JNIEXPORT void JNICALL Java_Main_Designer_displayHeyLand  (JNIEnv *jn, jobject jobj) {

    // istantiate the MC++ class.
    HeyLandC* t = new HeyLandC();

    // actual call is made. 
    t->callCSharpHeyLand();
}

//Header file HeyWork.h *******************************************

#include <jni.h>
/* Header for class Test1 */

#ifndef _Included_Designer
#define _Included_Designer
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Designer
 * Method:    displayHeyLand
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_Main_Designer_displayHeyLand
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

//Header file HeyLand.h *******************************************

#using <mscorlib.dll>
#using "/CSharpHeyLand.netmodule"

using namespace System;

public __gc class HeyLandC
{
    public:
        // provide .NET interop and garbage collecting to the pointer
        CSharpHeyLand __gc *t;
        HeyLandC() {
            t = new CSharpHeyLand();
            // Assign the reference a new instance of the object
        }

     // This inline function is called from the C++ Code
        void callCSharpHeyLand() {
            t->displayHeyLand();
        }
};

Any help is greatly appreciated!


Solution

  • I encountered the same error several monthes ago. We tried to use a C# DLL from Java, here's what we did:

    1. Write a C# DLL.
    2. Develop a C++/CLI DLL as a wrapper of the C# DLL, export the functions required.
    3. In Java, load the C++/CLI DLL and call the functions through JNI.

    Loading the C++/CLI DLL is already OK, just like your case, when executing some code, we encounter the UnsatisfiedLinkError error, we traced it with the Process Monitor, it is because that the java exe doesn't find reference C# assemblies.

    Unlike the native C++ DLL, the referenced managed assembly is not load immediately when exe starts, it is loaded as needed, this happens when the JIT compiler converts MSIL code to native code at application run time when the code is reached at the first time. This explains when the error happens when it reaches that line of code.

    So to figure out this problem, you can use the process monitor to monitor the java.exe to see how it loading the DLLs. As I observed,the java exe will try find the C# DLL in:

    1. First in global assembly cache.(GAC). Only strong name assemblies are in GAC.
    2. The folder of java.exe.

    So if the reference assembly are not in the two places, you will encounter that error.