I have a C function that expects a struct that contains a non-const String.
typedef struct _A {
char* str;
} A;
void myFunc(A* aptr) { ... }
I've tried for a long time to pass this thing via JNA but didn't manage so far.
public class A extends Structure {
public String str;
protected List getFieldOrder() { ...
}
doesn't work because String will be turned into a const char* instead of char* which I need.
public class A extends Structure {
public byte[] str;
protected List getFieldOrder() { ...
}
doesn't work because the byte array inside a struct gets turned into contiguous memory and not a pointer.
I know I can do it by using Memory
and copying the String over. But I can't imagine that this is the preferred way to do it.
I also tried something like
public class NonConstStringMember extends Structure {
public static class ByReference extends NonConstStringMember implements Structure.ByReference {}
public byte[] stringMember;
protected List getFieldOrder() { ...
}
public class A extends Structure {
public NonConstStringMember.ByReference str;
}
but it doesn't work either, maybe because of alignment issues.
What is the preferred way to do this with JNA?
Assuming you want this to point to an arbitrary buffer which you may write to, use Pointer
(and assign it a Memory
value if you're allocating the buffer).
You then use Pointer.getString(0)
or Pointer.setString(0, s)
to manipulate the buffer contents.
EDIT
Windows libraries usually have an ascii or unicode version of most functions. While in most cases you can define a single Structure
for use in both cases, sometimes you need to provide a little additional handling to ensure the correct types are used. Since the two modes are rarely, if ever, used simultaneously, JNA sets up options to default to one or the other (automatically mapping to the right function suffix, and automatically mapping String
to either native const char*
or const wchar_t*
depending on the mode).
Use setWideString()
if using unicode mode and setString()
otherwise, or make some accessors on your Structure
to handle that for you automatically. For example:
class MyStructure extends Structure {
private static final boolean ASCII = Boolean.getBoolean("w32.ascii");
public Pointer stringBuffer = new Memory(X);
void setStringBuffer(String s) {
stringBuffer.setString(0, s, ASCII);
}
String getStringBuffer() {
return stringBuffer.getString(0, ASCII);
}
}
EDIT
Please note that in most cases you should use a String
as the field type and rely on a TypeMapper
to use WString
behind the scenes where appropriate (e.g. User32
and W32APIOptions.DEFAULT_OPTIONS
).