Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning jintArray from JNI

I'm trying to return a jintArray from C++ to Java, but the application seems to hang in the JNI call. I have stripped the problem down to the creation and population of the jintArray, although I'm not receiving any errors. Any help is appreciated.

Test project to make sure everything works:

include "stdafx.h"
include "windows.h"
include <vector>
include <iostream>
include <jni.h>

using namespace std;

std::vector<jint> childWindows;

BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {
    childWindows.push_back((jint) hwnd);
    return TRUE;
}

jint* getChildWindows(HWND hWnd) {
    childWindows.clear();
    ::EnumChildWindows(hWnd, EnumChildProc, NULL);

    int len = static_cast<int>(childWindows.size());

    jint values[100];
    std::copy(childWindows.begin(), childWindows.end(), values);


    for (std::vector<jint>::const_iterator i = childWindows.begin(); i != childWindows.end(); ++i) {
        std::cout << (HWND)*i << ' ';
    }
    //env->SetIntArrayRegion(childeren, 0, len, values);
    return values;
}


int _tmain(int argc, _TCHAR* argv[])
{
    getChildWindows((HWND)1377258);

    std::cout << " | Windows count: " << childWindows.size() << " ";
    return 0;
}

Output:

000D0550 000B04F2 001C047A 0002055E 00020558 00010564 0007054E 00050570 00060512 000C04E0 | Windows count: 10

Java code:

    System.out.println("Get child windows");
    System.out.println("Main handle: " + getHandle());
    final int[] handles = getChildWindows();
    System.out.println("Done getting childs");

Java output:

Starting test child windows

Get child windows

Main handle: 525978

JNI code:

JNIEXPORT jintArray JNICALL Java_main_getChildWindows(JNIEnv *env, jclass c) {
    childWindows.clear();
    ::EnumChildWindows(hWnd, EnumChildProc, NULL);

    int len = static_cast<int>(childWindows.size());
    jintArray childeren = env->NewIntArray(len);

    jint values[100];
    std::copy(childWindows.begin(), childWindows.end(), values);

    env->SetIntArrayRegion(childeren, (jsize)0, (jsize)len, values);
    //env->ReleaseIntArrayElements(childeren, values, 0);
    return childeren;
}
like image 684
MicroHat11 Avatar asked Aug 12 '15 23:08

MicroHat11


People also ask

How to return String array in JNI?

Look at NewObjectArray into the JNI doc. Basically you can return from the JNI function an Array Of String (Java) an then transform it in a List or a whatever kind of Collection type.

How JNI works?

The JNI framework lets a native method use Java objects in the same way that Java code uses these objects. A native method can create Java objects and then inspect and use these objects to perform its tasks. A native method can also inspect and use objects created by Java application code.

What is JNI Bridge?

Introduction to Java Native Interface: Establishing a bridge between Java and C/C++ JNI (Java Native Interface) is a foreign function interface that allows code running on JVM to call (or be called by) native applications. Using JNI, one can call methods written in C/C++ or even access assembly language.


1 Answers

You're not checking for errors after your JNI calls. This can lead to a situation where you code crashes not at the spot where you had the error but at the next spot where you call into the JVM. You won't get "errors" in any friendly sense when this happens - Your chance to get those was by checking return values and querying the JVM for pending exceptions. (See below.)

In your case, for example, if

jintArray childeren = env->NewIntArray(len)

generates an exception (in Java in the JVM), your code will continue past that line in the native code, but the JVM will still be holding that exception. The next time that you call into the JVM, which happens to be the line that you identified where you set the array values, the code will crash. You need to clear the exception explicitly.

In any case, you should be checking return values and checking for exceptions. (See the JNI docs for ExceptionOccurred and ExceptionClear.) I'd bet that for some reason you failed to get an array allocated. Exactly why that would happen isn't clear to me from your code, but this will give you a concrete place to start, i.e. if you have an exception or you have a null reference that will give you information about what went wrong. It will also potentially shift your search to the spot where the problem occurs.

Good luck!

like image 135
Brick Avatar answered Oct 20 '22 02:10

Brick