🗒️
notes
  • Journal
  • URLs
  • Java Card
    • SCP02
    • Rapid Notes
    • _FIXVALS_
    • Mifare
    • Chain Of Trust
  • Encoding
    • CBEFF
    • Bytes
  • Snippets
    • JNI_OnLoad
  • float to byte[]
  • Protobuf
  • C/C++
    • Containers
    • Basics
    • JNI
    • gcov
    • Castings
  • chess
    • Untitled
  • Compression
    • Untitled
  • Snippets
    • Untitled
  • Build Systems
    • Maven
    • Windows
  • Gradle
  • CMake
  • Java
    • Untitled
    • Certificates
  • Android
    • Mifare
  • Python
    • ctypes
  • WebSub
    • References
  • Spring Boot
    • Form-based Authentication
    • Basic Access Authentication
    • JWT Authentication
  • QR Code
    • Denso QR Code
  • Philosophical Inquiry
    • First
  • XML
    • xmlstarlet
Powered by GitBook
On this page

Was this helpful?

  1. Snippets

JNI_OnLoad

The impossible C++ dream:

   jint ret = 1;

   for (auto& cls : classes) {
        ret = 1;
        jclass clazz2 = env->FindClass(cls.c_str());
        if (clazz2) {
            ret = env->RegisterNatives(clazz2,
                        method_table2,
                        sizeof(method_table2) / sizeof(method_table2[0]));
            env->DeleteLocalRef(clazz2);
        } else {
            break;
        }
   }

   return ret == 0 ? JNI_VERSION_1_6 : JNI_ERR;

Pushing kittens:

    std::string line;
    std::vector<std::string> classes;
    std::ifstream jconfig("jconfig.cfg");
    if (jconfig.is_open()) {
        while (std::getline(jconfig, line)) {
            classes.push_back(line); 
        }
    }

Lone wolf:

JavaVM* javaVM;
//env->GetJavaVM(&vm);

JNI methods:

// maps to a static method of a java class
static jlong myf1(JNIEnv* env, jclass clazz, jlong n)
{
    // implement;
    return 0;
}

// maps to a runtime method of a java object
static jint inc(JNIEnv* env, jobject thiz, jint n)
{
    return n + 1;
}

static JNINativeMethod dx_MyLib_table[] = {
    {(char*)"f1", (char*)"(J)J", (void*)myf1},
    {(char*)"plusOne", (char*)"(I)I", (void*)inc}      
};

static void add_JNI(JNIEnv *env ,const char* cls, JNINativeMethod* table, int n)
{
    jint ret = 1;

    jclass clazz = env->FindClass(cls);

    if (clazz) {
        ret = env->RegisterNatives(clazz, table, n);
        env->DeleteLocalRef(clazz);
    } 
 
    if (ret != 0) {
        throw "add_JNI failed";
    }
}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env;

    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    } else {
        try {

            add_JNI(env,
                    "dx/MyLib",
                    &dx_MyLib_table[0],
                    sizeof(dx_MyLib_table) / sizeof(dx_MyLib_table[0]));

        } catch (...) {
            return JNI_ERR;
        }
    }

    return JNI_VERSION_1_6;
}

Power of C++ lambda:

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    static bool flag = false;
    if (flag) {
        return JNI_VERSION_1_6;
    }
    flag = true;

    JNIEnv* env;

    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    } else {
        auto add_JNI = [&env](const char* cls, JNINativeMethod* table, int n) {
            jint ret = 1;
            jclass clazz = env->FindClass(cls);
            if (clazz) {
                ret = env->RegisterNatives(clazz, table, n);
                env->DeleteLocalRef(clazz);
            }
            if (ret != 0) {
                throw "add_JNI failed";
            }
        };

        try {
            add_JNI("org/dx/TestApp", &testapp[0], 
                sizeof(testapp) / sizeof(testapp[0]));
        } catch (...) {
            return JNI_ERR;
        }
    }

    return JNI_VERSION_1_6;
}

The nice thing with JNI_OnLoad is that the function declaration is now more clearer. I mean, you can opt to keep those directives it will work fine, but you can also no longer need them. So the function declaration/definition now becomes:

//extern "C" JNIEXPORT jbyteArray JNICALL
jbyteArray 
appPerson(JNIEnv *env,
          jobject thiz,
          jlong context,
          jstring sur_name,
          jstring given_name,
          jstring date_of_birth,
          jstring place_of_birth,
          jstring extras,
          jstring pin,
          jbyteArray photo)
{
    ...
}

Visual Studio 2019 copy dll on Post-Build Event:

copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" C:\Users\63927\src\onload\

Notice carefully, there is a \ slash in certain places there and the output extension (dll or exe) has to be explicitly written.

Microsoft's top 3 sins:

  • Allowing spaces and case insensitivity in file names

  • The use backward slash \ in path separator

  • Their newline endings in text files

I think these sins are unforgivable because firstly, Microsoft first worked on Unix systems in the earliest days so Bill Gates knew this. The strive for user-friendliness is no question and their Visual Studio IDE being light years ahead of the competition is a testament to Microsoft's dedication to user-friendliness in their designs. I guess it's a hit & run case. They did excellent in MSOffice but epic fail in other aspect such as Visual Basic.

Can't blame them it seems there is a primal tension between systems and user-friendliness. People likes to have spaces in names, we also do not care much with regards to case sensitivity. The Unix takes the opposite draconian way.

The best JNI_OnLoad

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    static bool runonce = false;
    if (runonce) {
        return JNI_VERSION_1_6;
    }
    runonce = true;

    JNIEnv* env;

    if (vm->GetEnv(
        reinterpret_cast<void**>(&env), 
        JNI_VERSION_1_6
    ) != JNI_OK) {
        return JNI_ERR;
    }
    
    // Create re-usable local function for mapping JNIs to method tables
    auto map_JNI = [&env](const char* cls, JNINativeMethod* table, int n) {
        jint ret = 1;
        jclass clazz = env->FindClass(cls);
        if (clazz) {
            ret = env->RegisterNatives(clazz, table, n);
            env->DeleteLocalRef(clazz);
        }
        if (ret != 0) {
            throw "add_JNI failed";
        }
    };

    // Map org.idpass.IDPassAPI Java native methods to C method table
    try {
#ifdef _APP_JNI_
        map_JNI("org/myapp/App", &APP_JNI[0], APP_JNI_TLEN);
#endif
    } catch (...) {
        return JNI_ERR;
    }

    return JNI_VERSION_1_6;
}

The JNI_OnLoad allows for a well-organized and flexible mechanism to map native methods in Java to a C method table. The only minimum requirements are:

  • Java native method name and signature must match as in the C method table row

  • Pass the full package class name into the map_JNI function above

PreviousBytesNextfloat to byte[]

Last updated 4 years ago

Was this helpful?