简体   繁体   中英

How to return data in a Java String from a call to a C function via JNI in Android NDK

I need to call into a C function using the Android NDK and must return an altered value via a Java String which is passed as a char* parameter to the C function. The problem is that Java strings are passed by value so the changes my C function makes to the string do not reach the calling Java function.

My Java source is as follows, I get sensible output from the values in arg1_j and result_j but as stated, arg3_j is not updated by my C function :

import Cptr.Cptr;
...
String arg1_j = new String(new byte[65]);
long arg2_j = 1000;
String arg3_j = new String(new byte[65]);

arg1_j = "1234567890123456789012345678901234567890123456789012345678901234";

Integer result_j = Cptr.test_cptr(arg1_j, arg2_j, arg3_j);

final EditText eText = (EditText) findViewById(R.id.editText1);

eText.setText(arg1_j);
//eText.setText(result_j.toString());
//eText.setText(arg3_j);
...

My C header file, cptr.h is as follows :

#ifndef CPTR_H_
#define CPTR_H_

#include <stdint.h>
#include <stdbool.h>

int32_t test_cptr(char *, uint32_t, char *);

#endif // ndef CPTR_H_

My C source file cptr.c is as follows :

#include "cptr.h"

// The function sets arg3 data and returns arg2 - 1
int32_t test_cptr(char* arg1, uint32_t arg2, char* arg3)
{
    arg3[0] = 'h';
    arg3[1] = 'e';
    arg3[1] = 'l';
    arg3[3] = 'l';
    arg3[4] = 'o';
    arg3[5] = '\0';

    return arg2 - 1;
}

My Cptr.i file is :

/* File : Cptr.i */
%module Cptr
%{
/* Includes the header in the wrapper code */
#include "cptr.h"
%}

%include "stdint.i"

// Enable the JNI class to load the required native library.
%pragma(java) jniclasscode=%{
static {
try {
java.lang.System.loadLibrary("Cptr"); 
} catch (UnsatisfiedLinkError e) {
java.lang.System.err.println("native code library failed to load.\n" + e);
java.lang.System.exit(1); 
} 
}
%}
/* Parse the header file to generate wrappers */
%include "cptr.h"

I have tried to use the typemap example in the SWIG examples code (...Examples/Java/typemap/example.i) as follows but without luck. The following example in the same source also didn't work for me, in both cases arg3 was passed as a String and not updated by my C function :

/* default behaviour is that of input arg, Java cannot return a value in a 
  * string argument, so any changes made by f1(char*) will not be seen in the Java
  * string passed to the f1 function. 
 */
void f1(char *s);

%include various.i

/* use the BYTE argout typemap to get around this. Changes in the string by 
 * f2 can be seen in Java. */
 void f2(char *BYTE);

I have also tried carrays.i from various posts on this forum but I am new to Java and Android have not got anything to work. The more explicit you can be in your replies the better from my POV.

Many thanks,

也许您可以使c方法返回修改后的参数,然后以以下形式在Java中调用它:

value = function(value);

Well, I am mistaken ! Very sorry for the noise but the first method from the ..Examples/Java/typemap/example.i that comes with SWIG did in fact work for me. I don't know what I did wrong before but the same cptr.c and cptr.h files as above now work fine with the following changes :

Java source :

import Cptr.Cptr;
...
byte[] arg1_j = "1234567890123456789012345678901234567890123456789012345678901234\0".getBytes();

int arg2_j = 1000;

byte[] arg3_j = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\0".getBytes();

Integer result = Cptr.test_cptr(arg1_j, arg2_j, arg3_j);

// convert byte array to hex string using no external libraries
StringBuffer sb = new StringBuffer();
for (byte b : arg3_j) { sb.append(Integer.toHexString( (int) (b & 0xff) )); }

final EditText eText = (EditText) findViewById(R.id.editText1);

eText.setText(sb.toString());

My new Cptr.i file is :

/* File : Cptr.i */
%module Cptr
%{
/* Includes the header in the wrapper code */
#include "cptr.h"
%}

%include "stdint.i"
%include various.i

// Enable the JNI class to load the required native library.
%pragma(java) jniclasscode=%{
static {
try {
java.lang.System.loadLibrary("Cptr");
} catch (UnsatisfiedLinkError e) {
java.lang.System.err.println("native code library failed to load.\n" + e);
java.lang.System.exit(1);
}
}
%}
int32_t test_cptr(char* BYTE, uint32_t, char *BYTE);

Hopefully this will help someone else

Thanks for your attention,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM