【问题标题】:Calling a C++ dll method from Java using JNA and avoiding Method Name Mangling使用 JNA 从 Java 调用 C++ dll 方法并避免方法名称修改
【发布时间】:2013-04-12 07:33:25
【问题描述】:

我一直在查看 StackOverflow 上有关如何解决方法名称错误的链接,但没有找到任何具有实时示例的解决方案。

场景-C++ Ex.dll 文件由客户端提供。我需要访问 Ex.dll 并通过 Java 调用相同的方法。

限制 - 无法修改 Ex.dll,我只能访问相同的。

面临的问题 - 当我通过 JNA 访问 Ex.dll 时出现以下异常

Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'getCPUSpeed': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:134)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:336)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:316)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.getCPUSpeed(Unknown Source)
at cpp.java.JnaTest.main(JnaTest.java:16)

google了很多,发现是因为方法名Mangling,但还是找不到任何好的解决方案示例代码。

这是我使用的代码-

import com.sun.jna.Native;
class JnaTest
{

public static void main(String args[])
{
    try 
    {
        JnaInterface jInterface = (JnaInterface) Native.loadLibrary("Ex", JnaInterface.class);

        System.out.println("Calling C++ DLL method");
        System.out.println("========================");
        System.out.println("getCPUSpeed() -- "+jInterface.getCPUSpeed());

    } catch (Exception e) {
        e.printStackTrace();
    }
}
}



package cpp.java;
import com.sun.jna.Library;
public interface JnaInterface extends Library{  
public int getCPUSpeed();
} 

更新 1:**************************************

下面提到的是我通过依赖walker浏览DBMM.dll时得到的实际功能-

DBMM DLL 函数-

??0cDbmmInterfaceCache@@QAE@ABV0@@Z

??0cDbmmInterfaceCache@@QAE@XZ

??0cDbmmInterfaceControl@@QAE@ABV0@@Z

??0cDbmmInterfaceControl@@QAE@XZ

??0cDbmmInterfaceEcon@@QAE@ABV0@@Z

??0cDbmmInterfaceEcon@@QAE@XZ

??0cDbmmInterfaceKnob@@QAE@XZ

??0cDbmmInterfaceOutput@@QAE@ABV0@@Z

??0cDbmmInterfaceOutput@@QAE@H@Z

??0cDbmmInterfacePoolLoan@@QAE@ABV0@@Z

??0cDbmmInterfacePoolLoan@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z

??0cDbmmMacroEcon@@QAE@ABV0@@Z

??0cDbmmMacroEcon@@QAE@ABVcDbmmInterfaceEcon@@_N@Z

??0cDbmmMtgBasisConstSpreadModel@@IAE@XZ

??0cDbmmMtgBasisConstSpreadModel@@QAE@ABV0@@Z

??0cDbmmMtgBasisConstSpreadModel@@QAE@PBD@Z

??0cDbmmMtgBasisModel@@QAE@ABV0@@Z

??0cDbmmMtgBasisModel@@QAE@XZ

??0cScaleFieldsSubSum@@QAE@NN@Z

??1cDbmmInterfaceCache@@QAE@XZ

??1cDbmmInterfaceControl@@QAE@XZ

??1cDbmmInterfaceEcon@@QAE@XZ

??1cDbmmInterfaceKnob@@QAE@XZ

??1cDbmmInterfaceOutput@@QAE@XZ

??1cDbmmInterfacePoolLoan@@QAE@XZ

??1cDbmmMacroEcon@@QAE@XZ

??1cDbmmMtgBasisConstSpreadModel@@UAE@XZ

??1cDbmmMtgBasisModel@@UAE@XZ

??1cScaleFieldsSubSum@@QAE@XZ

??4cDbmmInterface@@QAEAAV0@ABV0@@Z

??4cDbmmInterfaceCache@@QAEAAV0@ABV0@@Z

??4cDbmmInterfaceControl@@QAEAAV0@ABV0@@Z

??4cDbmmInterfaceEcon@@QAEAAV0@ABV0@@Z

??4cDbmmInterfaceKnob@@QAEAAV0@ABV0@@Z

??4cDbmmInterfaceOutput@@QAEAAV0@ABV0@@Z

??4cDbmmInterfacePoolLoan@@QAEAAV0@ABV0@@Z

??4cDbmmMacroEcon@@QAEAAV0@ABV0@@Z

??4cDbmmMtgBasisConstSpreadModel@@QAEAAV0@ABV0@@Z

??4cDbmmMtgBasisModel@@QAEAAV0@ABV0@@Z

??4cScaleFieldsSubSum@@QAEAAV0@ABV0@@Z

??_7cDbmmMtgBasisConstSpreadModel@@6B@

??_7cDbmmMtgBasisModel@@6B@

??_FcDbmmInterfaceOutput@@QAEXXZ

??_FcDbmmInterfacePoolLoan@@QAEXXZ

??_FcScaleFieldsSubSum@@QAEXXZ

?Add@cScaleFieldsSubSum@@QAEXNN@Z

?InitSubsum@cScaleFieldsSubSum@@QAEXNN@Z

?ReInit@cDbmmMacroEcon@@QAEX_N@Z


不知道如何通过 Java 调用这些函数。

如果有人可以为我提供 Java 端的解决方案,请提供示例代码:)

【问题讨论】:

  • 通过 Dependency Walker 验证时的方法名称是 _Java_sysInfo_getCPUSpeed@8 如何从 Java 端解决这个问题,即类 JnaTest 需要做哪些更改才能将方法名称映射为通过依赖walker显示。

标签: c++ jna


【解决方案1】:

您的函数使用 JNI 和 stdcall 约定进行修饰;它不是 C++ 损坏的。

看起来这个库是一个 JNI 库,给定了 Java_sysInfo_ 前缀。如果是这种情况,您只需要声明等效的 Java 端,例如

// default package
public class sysInfo {
    static { System.loadLibrary("Ex"); }
    public static native int getCPUSpeed();
}

我想你可能会发现这个映射是正确的并且你不需要 JNA。

编辑

给定一个具有任意 ctor 输入参数和方法 getCount() 的 C++ 类:

extern "C" int getCountForName(const char* name) {
    MyCPPClass mycpp(name);
    return mycpp.getCount();
}

Compile that into a shared library,并通过 JNA 加载。

【讨论】:

  • 您好 Technomage,感谢您的回复。上面提到的是我正在尝试寻找解决方案的示例。用我通过 Dependency walker 浏览 dll 时找到的实际方法更新了问题。
  • 那些 C++-mangled名称。如果它们是静态方法,您可以直接调用它们,但如果它们是成员方法,您需要编写一个暴露简单(外部“C”)函数的包装器,或者使用像JNAerator 这样的工具来生成更复杂的映射。
  • 感谢Technomage的回复,您能否提供一个示例代码或任何参考站点,说明如何编写公开简单(外部“C”)函数的包装器?因为我是 C++ java 集成的新手。同时我正在研究 JNAerator。
【解决方案2】:

如果您通过 Visual Studio 构建 DLL,如果您还没有这样做,您应该能够将其构建为发布版本而不是调试来修复函数名称。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多