使用JNA从Java调用c++ dll方法并避免方法名称混淆

Calling a C++ dll method from Java using JNA and avoiding Method Name Mangling

本文关键字:方法 使用 Java 调用 c++ dll JNA      更新时间:2023-10-16

我一直在通过StackOverflow关于如何解决方法名称混淆的链接,但没有找到任何解决方案与实时示例。

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

限制-不能修改exe .dll,我只能访问相同的。

面临的问题-当我通过JNA访问exe .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)

谷歌了很多,发现这是由于方法名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:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

下面提到的是我通过依赖项漫游器浏览DBMM.dll时得到的实际函数-

DBMM DLL函数-

? ?0 cdbmminterfacecache@@qae@abv0@@z

? ?0 cdbmminterfacecache@@qae@xz

? ?0 cdbmminterfacecontrol@@qae@abv0@@z

? ?0 cdbmminterfacecontrol@@qae@xz

? ?0 cdbmminterfaceecon@@qae@abv0@@z

? ?0 cdbmminterfaceecon@@qae@xz

? ?0 cdbmminterfaceknob@@qae@xz

? ?0 cdbmminterfaceoutput@@qae@abv0@@z

? ?0 cdbmminterfaceoutput@@qae@h@z

? ?0 cdbmminterfacepoolloan@@qae@abv0@@z

? ? 0 cdbmminterfacepoolloan@@qae@v ? basic_string@DU美元? char_traits@D@std@@V美元?美元allocator@D@2@@std@@@Z

? ?0 cdbmmmacroecon@@qae@abv0@@z

? ?0 cdbmmmacroecon@@qae@abvcdbmminterfaceecon@@_n@z

? ?0 cdbmmmtgbasisconstspreadmodel@@iae@xz

? ?0 cdbmmmtgbasisconstspreadmodel@@qae@abv0@@z

? ?0 cdbmmmtgbasisconstspreadmodel@@qae@pbd@z

? ?0 cdbmmmtgbasismodel@@qae@abv0@@z

? ?0 cdbmmmtgbasismodel@@qae@xz

? ?0 cscalefieldssubsum@@qae@nn@z

? ?1 cdbmminterfacecache@@qae@xz

? ?1 cdbmminterfacecontrol@@qae@xz

? ?1 cdbmminterfaceecon@@qae@xz

? ?1 cdbmminterfaceknob@@qae@xz

? ?1 cdbmminterfaceoutput@@qae@xz

? ?1 cdbmminterfacepoolloan@@qae@xz

? ?1 cdbmmmacroecon@@qae@xz

? ?1 cdbmmmtgbasisconstspreadmodel@@uae@xz

? ?1 cdbmmmtgbasismodel@@uae@xz

? ?1 cscalefieldssubsum@@qae@xz

? ?4 cdbmminterface@@qaeaav0@abv0@@z

? ?4 cdbmminterfacecache@@qaeaav0@abv0@@z

? ?4 cdbmminterfacecontrol@@qaeaav0@abv0@@z

? ?4 cdbmminterfaceecon@@qaeaav0@abv0@@z

? ?4 cdbmminterfaceknob@@qaeaav0@abv0@@z

? ?4 cdbmminterfaceoutput@@qaeaav0@abv0@@z

? ?4 cdbmminterfacepoolloan@@qaeaav0@abv0@@z

? ?4 cdbmmmacroecon@@qaeaav0@abv0@@z

? ?4 cdbmmmtgbasisconstspreadmodel@@qaeaav0@abv0@@z

? ?4 cdbmmmtgbasismodel@@qaeaav0@abv0@@z

? ?4 cscalefieldssubsum@@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端解决方案,请与示例代码:)

你的函数是用JNI和stdcall约定装饰的;它不受c++的影响。

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

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

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

编辑

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

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

编译成一个共享库,并通过JNA加载

如果你通过Visual studio构建DLL,如果你还没有这样做,你应该能够将它作为一个发布版本来构建,而不是调试来修复函数名。