wiiznokes3
wiiznokes3

Reputation: 511

SEHException (0x80004005) when using JNI to run C# code

I have a project written in Kotlin, and I want to use a library written in C#. So I used the JNI to make a "proxy" in C++ witch make the link between C# and the JVM. I was able to load the library in Kotlin but I have this error when I call a function:

Fatal error. System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception.
   at <Module>.Java_Authenticator_authenticate(JNIEnv_*, _jobject*, _jstring*, _jstring*)
:run (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 1.965 secs.

This is my Java class witch use the library:

public class Authenticator {

    static  {
        System.loadLibrary("CppProxy");
    }
    public native boolean authenticate(String username, String password);

    public void runLib() {
        System.out.println("run");
        boolean valid = authenticate("admin", "admin");
        if(valid) {
            System.out.println("Valid");
        }
        else {
            System.out.println("No valid");
        }
    }
}

This is the Authenticator.h file in C++ project, generated automatically with the command javac -h:

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

#ifndef _Included_Authenticator
#define _Included_Authenticator
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Authenticator
 * Method:    authenticate
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_Authenticator_authenticate
  (JNIEnv *, jobject, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif

This is my CppProxy.cpp file:

#include "pch.h"
#include "CppProxy.h"
#include <string.h>
#include "Authenticator.h"

String^ toString(const char* chars) {
    int len = (int)strlen(chars);
    array<unsigned char>^ a = gcnew array<unsigned char>(len);
    int i = 0;
    while (i < len) {
        a[i] = chars[i];
        i++;
    }
    return System::Text::Encoding::UTF8->GetString(a);
}

bool authenticate(const char* username, const char* password) {
    return LibreHardwareMonitorWrapper::SharpAuthenticator::SharpAuthenticated(toString(username), toString(password));
}

JNIEXPORT jboolean JNICALL Java_Authenticator_authenticate
(JNIEnv* env, jobject c, jstring username, jstring password) {

    jboolean isCopyUsername;
    const char* c_username = env->GetStringUTFChars(username, &isCopyUsername);

    jboolean isCopyPassword;
    const char* c_password = env->GetStringUTFChars(password, &isCopyPassword);

    jboolean result = authenticate(c_username, c_password);

    // cleaning
    env->ReleaseStringUTFChars(username, c_username);
    env->ReleaseStringUTFChars(username, c_password);

    return result;
}

And this is my C# code:

namespace LibreHardwareMonitorWrapper
{
    public static class SharpAuthenticator
    {
        public static bool SharpAuthenticated(String username, String password)
        {
            return username == "admin" && password == "admin";
        }
    }
}

I'm using the oracle JDK 17 and the C# project is currently using .NET6.

Cpp project target x64 platform and C# project Any CPU.

The Cpp project is build in a folder call "lib" witch is inside java.library.path.

CppProxy has for reference LibreHardwareMonitorWrapper.

I tried to run .\gradlew run and expected to see Valid but I have an error in my external function at execution.

Upvotes: 1

Views: 165

Answers (1)

Lacoudasse
Lacoudasse

Reputation: 29

Finally found what was the problem. I could not find the CLR option in properties of C# project, whereas it's crucial for running C# code in C++.

So I think .net6 is not yet compatible with this option, I tried with .net framework 4.x and it works.

Also, you should know that it is necessary to put the assemblies of C# project in the /bin of JDK.

Upvotes: 1

Related Questions