使用 JNA 从 Java 调用 C++ dll 方法并避免方法名称修改
Posted
技术标签:
【中文标题】使用 JNA 从 Java 调用 C++ dll 方法并避免方法名称修改【英文标题】:Calling a C++ dll method from Java using JNA and avoiding Method Name Mangling 【发布时间】:2013-04-12 07:33:25 【问题描述】:我一直在查看 *** 上有关如何解决方法名称错误的链接,但没有找到任何具有实时示例的解决方案。
场景-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显示。 【参考方案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,如果您还没有这样做,您应该能够将其构建为发布版本而不是调试来修复函数名称。
【讨论】:
以上是关于使用 JNA 从 Java 调用 C++ dll 方法并避免方法名称修改的主要内容,如果未能解决你的问题,请参考以下文章