UncleBob
UncleBob

Reputation: 1391

JNA: How to pass a string as void* from Java to C

I have successfully received a void* from a C function into Java and cast it into the apropriate type depending on context, but now I have to do the whole thing the other way around, and I can't get it to work.

Specifically, the function I am trying to call demands a void*, behind which, in this case, hides a char*, behind which of course hides a char[]. The C-function doesn't manipulate the data, it just reads it.

So I've tried creating a Byte[] from a string and then passing a pointer to the first element of it, like so:

    //transform the string into a byte array
    byte[] byte_value = new_value.getBytes();
    //create a pointer to the first byte
    ByteByReference valueptr = new ByteByReference(byte_value[0]);
    //pass the pointer to the function that sets the value
    int result = lib.gp_widget_set_value(widget, valueptr.getPointer()); 

To my surprise, nothing crashes. To my dismay, the function doesn't seem to get the data at all. Can anybody see what I'm doing wrong?

The function gp_widget_set_value was generated by JNAerator based on libgphoto2. The generated function header including generated comment looks like this:

/**
 * Original signature : <code>int gp_widget_set_value(CameraWidget*, const void*)</code><br>
 * <i>native declaration : /usr/include/gphoto2/gphoto2-widget.h:840</i>
 */
int gp_widget_set_value(Gphoto2Library.CameraWidget widget, Pointer value);

The documentation of the actual C function from the Gphoto API docs:

int gp_widget_set_value ( CameraWidget * widget, const void * value )

Sets the value of the widget.

Parameters widget a CameraWidget value

Returns a gphoto2 error code.

Please pass (char*) for GP_WIDGET_MENU, GP_WIDGET_TEXT, GP_WIDGET_RADIO, (float) for GP_WIDGET_RANGE, (int) for GP_WIDGET_DATE, GP_WIDGET_TOGGLE, and (CameraWidgetCallback) for GP_WIDGET_BUTTON.

In case you are wondering, the last line refers to the widget type, and yes, I'm making very sure that that is correct.

Upvotes: 1

Views: 1282

Answers (2)

technomage
technomage

Reputation: 10069

You don't need anything complicated. JNA takes care of most common C idioms. JNAerator is giving you literally what's in the function declarations; it can't figure out the semantic difference between a C string, a char buffer, an array of char, or a pointer to a single char.

int gp_widget_set_value(Gphoto2Library.CameraWidget widget, String value);

Note that the memory passed to the native function in this case is temporary and will be disposed of when the function returns. If you need the memory to stick around (not a good idea), you'd need to use Memory and maintain a reference to it.

Upvotes: 1

Mike Nakis
Mike Nakis

Reputation: 61986

You could use the following to get the bytes in the proper encoding:

byte[] bytes = new_value.getBytes( StandardCharsets.UTF_8 ); //or .US_ASCII

But what you most probably need to do is to use JNA's byte[] Native.toByteArray(String s)

If for some reason that does not work, then this should do it:

Pointer m = new Memory( new_value.length() + 1 ); //assumes ASCII
m.setString( 0, new_value );
int result = lib.gp_widget_set_value( widget, m );

Upvotes: 1

Related Questions