I've ellipsed out the code that isn't relavent to the question. Here is the output:
Called SetTagName. Looking for pipt for Test. Returned 76820 as pipoint. Called pipt_location for point 76820. Location 0 is 22. Location 1 is 235. Location 2 is 0. Location 3 is 1. Location 4 is 0. GetLocations(long, long) suceeded. arLocs = 0 arLocs = 0 arLocs = 0 arLocs = 0 arLocs = 0 Location1 of tag Test is 0
I've tried a couple of variations on the line setting the array values to be passed back to Java.
env->SetLongArrayRegion(buf, i, 1, arLocs[i]); (won't compile) env->SetLongArrayRegion(buf, i, 1, &arLocs[i]); (won't compile)
you're assigning the array returned from the native function to a local variable. Java is pass-by-value, so that new value disappears when GetLocations returns.
Have GetLocations return null on error, and the array from the native method on success. Better yet, remove a layer and have FindAttributes call the native method directly, and deal with any exceptions. Also, have the native methods throw Java exceptions rather than returning null -- it's more idiomatic and would simplify your code a lot.
Let me know if I'm off track on this. I've re-written the Java portion of my code to follow the above example. I am still not getting the array returned from the native function though. And I don't know much about having the native code (c++ in this case) throw a Java Exception. I did try to reason it out from the chapter on exceptions in the book ("The Java Native Interface Programmers Guide and Specification", Sheng Liang, ADDISON-WESLEY).
So, now I'm back to my orginal problem, I can't get the native code to return the array. I'm guessing this may have to do with where the memory for the array is allocated.
One of the other native functions in the interface returns a string with no probems. And a string is nothing but an array of characters:
(I know I need to go through this code and add provisions for throwing Java Exceptions.) But, as you see, the memory for the character array is originally allocated in the native code. But I believe the statement "return env->NewStringUTF(szEDesc);" caused the jvm to allocate memory for the string.
In the case of the array of longs, the statement "jlongArray buf = env->NewLongArray(5);" should be allocating the memory in the jvm. In the end I'm still confussed and I don't have my data.
As far as helping you figure out this problem: put a simple print loop in the Java method GetLocations(), right after you call the native method, to print each element of the array. You should find that you're getting the values into that variable. But the point is that assigning to that method parameter changes nothing outside of the GetLocations() routine. You need to be saying
JNI version is 65540 Called SetTagName. Looking for pipt for Test. Returned 76820 as pipoint. Called pipt_location for point 76820. Location 0 is 22. Location 1 is 235. Location 2 is 0. Location 3 is 1. Location 4 is 0. [i]arLocs = 1009317314582 arLocs = 0 arLocs = 0 arLocs = 0 arLocs = 0 GetLocations(long, long) suceeded. Called pipt_exdesc for point 76820. Called pipt_instrumenttag for point 76820. Called pipt_pointtypex for point 76820. PointType = 11 Location1 of tag Test is 1009317314582
The bold portion is output from the native code usint printf, the italics portion is output from the GetLocations function in Java.
The values output by the native code are correct. Those output by the java code are wrong. However, you will notice that Location1 (which is arLoc) does return correctly. So I think all of the code within Java is correct. But I can't pass the correct values back to Java from the native code.
I altered the return statment in the pipt_location function to:
based on an example I found in the book. This appears to have loaded only the first value of the array. Note that both 'buf' and 'arLocs' are arrays. arLocs is a c array of long while buf is of type jlongArray, created by the statement: "jlongArray buf = env->NewLongArray(5);"
David M Fairchild
posted 14 years ago
Got It !!!
The problem seem to be in how Java was interpreting the c type long. I had a statment:
env->SetLongArrayRegion(buf, i, 1, (jlong*)&arVal[i]);
Which compiled but transferred garbage back to Java. So I added a variable: