2

I have a function with this signature from the header file

SIMAPI_DECL DWORD WINAPI SimReadDwordBuffer (DWORD* pBuffer, 
                                             DWORD dwDwordsToRead, 
                                             DWORD* pdwDwordsRead, 
                                             DWORD dwBlockDwords, 
                                             DWORD dwNoWait);

With the following native call defined

protected native int  SimReadDwordBuffer (int[] pBuffer, 
                                          int dwDwordsToRead, 
                                          int pdwDwordsRead, 
                                          int dwBlockDwords, 
                                          int dwNoWait);

I use javah.exe to create the jni header and it looks like this

protected native int  SimReadDwordBuffer (int[] pBuffer, 
                                          int dwDwordsToRead, 
                                          int pdwDwordsRead, 
                                          int dwBlockDwords, 
                                          int dwNoWait);

And the implementation is this

JNIEXPORT jint JNICALL Java_com_sig_ccm_CcmBase_SimReadDwordBuffer
  (JNIEnv *env, jobject obj, jintArray pBuffer, jint dwWordsToRead, 
                             jint pdwWordsRead, 
                             jint dwBlockWords, jint dwNoWait){
jint *body = env->GetIntArrayElements(pBuffer, 0);
//DWORD foo = 0;
jint value = SimReadDwordBuffer((unsigned long int *)body,
                         dwWordsToRead,
                                     //&foo, 
                         (unsigned long int *)&pdwWordsRead,
                         dwBlockWords,
                         dwNoWait );
//cout << foo;
env->ReleaseIntArrayElements(pBuffer, body, 0);
return value;
}

The problem is no matter what I have tried I cannot get the value pdwWordsRead copied to the parameter I passed from java to jni. If I use a local variable I can write out the value so the c++ function is passing it back. Any suggestions would be appreciated.

Sting
  • 363
  • 6
  • 18
  • 2
    why are you casting `&pdwWordsRead`? – Red Alert Jun 05 '14 at 19:13
  • If you needed to use `GetIntArrayElements` for `pBuffer`, why would you think you wouldn't need it for `pdwWordsRead`? – PaulMcKenzie Jun 05 '14 at 19:19
  • 1
    Red Alert, If I don't I get the following error: ..\src\com_sig_ccm_CcmBase.cpp:104:38: error: invalid conversion from 'jint* {aka long int*}' to 'DWORD* {aka long unsigned int*}' [-fpermissive] dwNoWait ); – Sting Jun 05 '14 at 19:27
  • @PaulMcKenzie I'd imagine it's because `pdwWordsRead` is a counter of words read, not an array. I am more worried about the the fact that he is casting the address of `pdwWordsRead`. I doubt that is what he wants to do. – Red Alert Jun 05 '14 at 19:28
  • Paul: All of the examples I have seen treat the passing of an array using the GetIntArrayElements and just pass the address for a single dword. [link](http://stackoverflow.com/questions/10381773/how-to-pass-pointers-from-java-to-c-in-jni) – Sting Jun 05 '14 at 19:31
  • @Sting So, you are randomly casting variables to suppress errors without knowing why? A small tip, you should never ever do that. What do you need the address of `pdwWordsRead` for anyways? – Red Alert Jun 05 '14 at 19:31
  • @Sting - The compiler error should never have been "casted away". You don't convert from one type to another by merely casting, and especially between two differing size ints (what is `sizeof(jint)` and `sizeof(DWORD)`? Are they the same?). Remove the cast, and get the compiler to compile the code wihtout it. – PaulMcKenzie Jun 05 '14 at 19:33
  • @RedAlert - My mistake. I thought that the item was also a jintarray. – PaulMcKenzie Jun 05 '14 at 19:34
  • It has to be cast this way to account for the issue between java and c++ that java doesn't support unsigned. Anyway, that part of the code works. When I get the value out of the the function and write it to std out I can see the value and it is correct. It just isn't being passed up to the java code. – Sting Jun 05 '14 at 20:11
  • A jint is 4 bytes, a DWORD is 4 bytes, an unsigned long is 4 bytes. – Sting Jun 05 '14 at 20:20

1 Answers1

0

Java passes primitives by value, not by reference. Also doing things like address of jint and passing them to functions for population isn't a good idea.

JNIEXPORT jint JNICALL Java_com_sig_ccm_CcmBase_SimReadDwordBuffer
  (JNIEnv *env, jobject obj, jintArray pBuffer, jint dwWordsToRead, 
                             jint pdwWordsRead, 
                             jint dwBlockWords, jint dwNoWait){
jint *body = env->GetIntArrayElements(pBuffer, 0);

// I would consider copying the jint[] to a dword[] here... 
// I would also look into jlong instead of jint because jint 
// is 32-bit signed, and dword is 32-bit unsigned.  Then do 
// something like dword == jlong & 0xFFFFFFFF 

DWORD foo = 0;
jint value = SimReadDwordBuffer((DWORD *) body, // Potentially Bad!
                         (DWORD) dwWordsToRead,
                         &foo, 
                         //(DWORD *) &pdwWordsRead, Bad!
                         dwBlockWords,
                         dwNoWait );
// You need to return an object or something else to get both values out!!! 
env->ReleaseIntArrayElements(pBuffer, body, 0);
return value;
}

Again, I have no idea what value is but if its a success indicator, check it and throw an exception if a failure occurred and return the foo variable instead.

Alex Barker
  • 4,316
  • 4
  • 28
  • 47