1

I have the following C function:

    int read(int dev, void* buffer, unsigned int count)

This is usually call in C like:

    read(data->dev, data->buffer, 32000);

data is a struct, with the following:

    typedef struct {
         ssize_t dev; 
         char buffer[32000]; 
    } DATA;

And I have convert this to java, with jna with the following:

    public class Data{//not neccesary to extends of Structure, because is only used to package both variables together
          public int dev;
          public byte[] buffer;//in the constructor of the class set to 32000 elements
    }

   int read(int playdev, Buffer buffer, int count);

   //clib is the class to connect with  de C library

   ByteBuffer bf = ByteBuffer.wrap(data.buffer);
   clib.read(data.dev, bf , READ_SIZE);

And it gives me a "java.lang.Error: Invalid memory access" when I do the "clib.read"

Any idea how to go through this error???

I have tried to make a: int vox_playstr_read(int playdev, Pointer buffer, int count);

with

    ByteBuffer bf = ByteBuffer.wrap(data.buffer);
    Pointer pbuf = Native.getDirectBufferPointer(bf);
    clib.read(data.dev, pbuf, READ_SIZE);

and it gives me the same result.

Please, any ideas to make it work?

Selvaya
  • 41
  • 1
  • 5
  • You can pass the `byte[]` directly, use an NIO buffer, or use JNA `Memory`. JNA supports all three as buffer-type arguments. – technomage Oct 29 '13 at 17:28
  • Please update your question with your *actual* code. You do not indicate how you've initialized `buf` or `data.buffer`; that could very well be where your error lies. – technomage Oct 29 '13 at 17:30
  • I have edited the answer. With "buf", I mean "bf", its the same, I create the buffer and build de pointer with it. I have tried with byte[] directly, but not with Memory, and I don't know how you say it can apply here. – Selvaya Oct 30 '13 at 09:54
  • `Native.getDirectBufferAddress()` does not work with an NIO buffer wrapping a primitive array. Use `bf = ByteBuffer.allocateDirect(size)` instead. At any rate you should be able to pass the `ByteBuffer` directly to the `read` function; you should also be able to pass `byte[]` directly to `read`. Add debugging to your C function to spit out the arguments it's receiving; if the arguments are incorrect, then you've likely got the calling convention or signature wrong. – technomage Oct 30 '13 at 19:57
  • in the answer below of Radical, I said I tried with bf = ByteBuffer.allocateDirect(size), with the same result. And I can't debug de C function, because it's in a *.dll and I don't have access to the real C code.... But it's suppoused to be tested and whatever, so I assumed it's ok, and the problem was in my side... – Selvaya Oct 31 '13 at 08:47
  • If your DLL is using the `stdcall` calling convention, or if the sizes of its arguments are different than what you convey (int, pointer, int), then you'll wind up with incorrect parameter values. You're also calling `read` from the C library, which is distinctly different from `vox_playstr_read`. – technomage Oct 31 '13 at 11:03
  • Sorry, I misplaced the function, I have edited the post now. – Selvaya Oct 31 '13 at 16:07
  • `msvcrt.dll` (Microsoft's C runtime library) does not export a `read` function (the one you are looking for is named `_read`). You may be picking up a different `read` than the one you're looking for. – technomage Oct 31 '13 at 20:27
  • its not the msvcrt.dll library the one I'm exporting with JNA. It's from another dll and I'm pretty sure the parameters are ok. But thank you for the point. – Selvaya Nov 04 '13 at 08:40

2 Answers2

1

Try creating the ByteBuffer with ByteBuffer.allocateDirect and then use byteBuffer.put(..) if you want to set any initial data. Also, reset the position of the buffer, buffer.position(0).

ByteBuffer bb = ByteBuffer.allocateDirect(values.length);
bb.put(values);
bb.position(0);

Read Edwin's reply here for the reason to use allocateDirect.

Community
  • 1
  • 1
radical
  • 4,364
  • 2
  • 25
  • 27
  • I tried it with ByteBuffer buf = ByteBuffer.allocateDirect(32000); buf.put(data.buffer); and the result was the same a "java.lang.Error: Invalid memory access" – Selvaya Oct 29 '13 at 14:33
  • .. and you reset the position to 0, with buf.position(0), and data.buffer.length == 32000 ? You could test with a simple function which gets such a pointer and tries to put few bytes there, which you can check on the java side, after that native function returns. – radical Oct 29 '13 at 16:03
  • With your modification the result is the same exception as before :( – Selvaya Oct 29 '13 at 17:10
  • I was reasearching this today and found this question. You must remember the difference in endiannes between the JVM and the underlying machine. I would use `ByteBuffer.order(ByteOrder.nativeOrder())` immediately after allocation. – Pedro Lamarão Sep 19 '16 at 15:22
1

technomage's comments to the original post are exactly right. Explicitly, on the Java side, declare your JNA interface method as you plan to use it:

int read(int playdev, byte[] buffer, int count);

clib.read(data.dev, data.buffer, READ_SIZE);

No need to use Buffer or ByteBuffer. Also, depending on whether the read function is exported __cdecl or __stdcall, your JNA interface should extends Library or extends StdCallLibrary respectively.