如何通过本机函数的值返回?

时间:2019-05-14 12:02:05

标签: java jnr

我使用Visual Studio 2017编译了以下C ++方法:

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;
}

在Java代码中,它由Java Native Runtime使用具有以下签名的接口方法进行映射:

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();
    }
}

有效。

上面的C ++方法会导致内存泄漏,因此我想更改它以按值返回结果:

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;
}

我使用相同的Java JNR映射:

Info GetInfo(Pointer infoProvider);

但是它不起作用-访问冲突。调用本机方法,但具有一些悬空指针值。

如何在JNR中按值返回?

1 个答案:

答案 0 :(得分:5)

JNI围绕旧的纯K&R C构建,以与所有可用的编译器兼容。从函数返回结构是在C89中引入的,后来与C ++标准一起被完全实现。如今,仍然有可能在许多Java友好的环境(如小型设备或SIM卡)中找到这种旧的C编译器。因此,我认为JNI不会升级到C89甚至C99。

对于您的情况,我建议编写一个额外的C代码来处理库函数的调用。该代码可以通过两种方式实现:

  1. 对于Info* __stdcall GetInfo(InfoProvider* infoProvider),您应该编写自由功能,例如:
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;
}
  1. 对于Info __stdcall GetInfo(InfoProvider* infoProvider),您应该编写包装器:
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;
}