I have the following C++ method compiled using Visual Studio 2017:
extern "C" __declspec( dllexport )
Info* __stdcall GetInfo(InfoProvider* infoProvider)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info info = new Info();
Info->data1 = infoProvider->data1;
Info->data2 = infoProvider->data2;
return info;
}
In Java code, it is mapped by Java Native Runtime using interface method with following signature:
Info GetInfo(Pointer infoProvider);
final class Info extends Struct {
public final Signed32 data1;
public final Signed32 data2;
public R2VInfo(final Runtime runtime) {
super(runtime);
data1 = new Signed32();
data2 = new Signed32();
}
}
It works.
The above C++ method causes memory leak, so I would like to change it to return result by value:
extern "C" __declspec( dllexport )
Info __stdcall GetInfo(InfoProvider* infoProvider)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info info{};
Info.data1 = infoProvider->data1;
Info.data2 = infoProvider->data2;
return info;
}
I use the same Java JNR mapping:
Info GetInfo(Pointer infoProvider);
But it does not work - Access Violation. Native method is invoked, but with some dandling pointer value.
How to return by value in JNR?
JNI build around old pure K&R C to be compatible with all available compilers. Returning a structure from a function was introduced in C89 and was fully implemented significantly later with C++ standard together. Today it is still possible to find such old C compiler in many java-friendly environments like small devices or sim-cards. So I don't think that JNI would be upgraded to C89 or even C99.
For your case, I would recommend to write an additional C-code that handles calling of a library function. The code could be implemented in two ways:
Info* __stdcall GetInfo(InfoProvider* infoProvider)
you should write free-function like:extern "C" __declspec( dllexport )
void __stdcall FreeInfo(Info* info)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
delete info;
}
Info __stdcall GetInfo(InfoProvider* infoProvider)
you should write a wrapper:extern "C" __declspec( dllexport )
void __stdcall GetInfo(InfoProvider* infoProvider, Info* info)
{
static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");
Info infoProvider = GetInfo(infoProvider);
info->data1 = infoProvider.data1;
info->data2 = infoProvider.data2;
}