2

I have a C function (compiled into a DLL) that takes a WinDef.RECT object and prints out the four co-ordinates:

DllExport void Test(RECT rect)
{
    printf("Rect: %i, %i, %i, %i", rect.top, rect.left, rect.bottom, rect.right);
}

On the Java (JNA) side, I'm attempting to pass it a WinDef.RECT as follows:

WinDef.RECT rect = new WinDef.RECT();
rect.bottom=0;
rect.left=0;
rect.right=0;
rect.top=0;
jna.INSTANCE.Test(rect);

However, I just get nonsense numbers out (which aren't consistent and vary every time), eg:

Rect: -857788769, 11343200, 8044544, 8044544

I'm assuming that I'm not defining the RECT correctly on the JNA side (the C++ function is fine called from other native functions in the same dll), but beyond that I'm a bit stuck!

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • 1
    I noticed that I'm getting the same problem when I use a 32bit JRE with the 32bit version of the DLL while everything works as expected with the 64bit versions. – regulus Apr 25 '15 at 05:13
  • @regulus Thanks for the observation - would you suggest this is a JNA bug in this case? (Unfortunately my use case restricts me to a 32 bit stack.) – Michael Berry Apr 25 '15 at 09:27
  • Note that w32 APIs use the [`stdcall`](http://stackoverflow.com/questions/297654/what-is-stdcall) calling convention on 32-bit, but not on 64-bit. Make sure that if your native library uses `stdcall`, that your JNA mapping implements `StdCallLibrary`. – technomage Apr 26 '15 at 11:52

1 Answers1

0

I had a useful answer over on the JNA mailing list:

Your native signature is asking for struct and your JNA mapping defaults to struct* semantics. Change your native sig or use Structure.ByValue; struct* is preferred unless you explicitly need otherwise.

In my case I need the native library to remain unchanged, so the solution was declaring a subclass of WinDef.RECT and tagging it with Structure.ByValue:

public static class RectByValue extends WinDef.RECT implements Structure.ByValue {}

This could then be used in place of WinDef.RECT, and all appears to work without an issue.

Note that while this fix worked ok for me, other(s) have reported otherwise - as in the comment below, switching types to LPRECT is another potential fix.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • 1
    In my case using ByValue didn't help, but after I read your answer I tried changing my methods signature to LPRECT which solved the problem. I still feel like there is a JNA bug here. – regulus Apr 25 '15 at 19:22
  • @regulus Hmm, that is interesting - I just tried recompiling / running on a 64 bit stack and I actually get the same result as the 32 bit stack (doesn't work how I first tried, but using `ByValue` fixed it.) I'm weary now of rolling out this code if it doesn't seem to work reliably on all systems! (I'll update my answer with your comment regardless in case others run into that same issue.) – Michael Berry Apr 25 '15 at 19:27
  • Note that you need to change both the mapped function signature *and* actually pass in an object tagged with the `Structure.ByValue` type. The function signature is what determines how the data gets passed to the native code, and obviously if you get it wrong you can crash the VM or at best get bogus data. – technomage Apr 26 '15 at 11:23