将 Java 中的 C++ DLL 与 JNA 结合使用

Use C++ DLL from Java with JNA

我尝试使用来自 C++ 的 DLL 和 JNA 来与来自 Java 程序的 Fanuc 数字控制进行通信,但总是出现此错误: 线程异常 "main" java.lang.Error: 无效内存访问

我尝试使用的具体C++方法是这个https://www.inventcom.net/fanuc-focas-library/handle/cnc_allclibhndl3

FWLIBAPI short WINAPI cnc_allclibhndl3(const char *ipaddr, unsigned short port, long timeout, unsigned short *FlibHndl);

并且在 Java 的声明中我使用了这个:

short cnc_allclibhndl3(String ipaddr, short port, NativeLong timeout, short FlibHndl);

我尝试了不同的类型映射,但总是得到同样的错误。

你能告诉我这个声明是否正确吗?

这是我最后一个节目:

import com.sun.jna.Library;
import com.sun.jna.Native;

public class JnaFanuc {

    public interface Fwlib32 extends Library {
        short cnc_allclibhndl3(String ipaddr, short port, long timeout, short FlibHndl);
    }

    public static void main(String[] args) {
        short p = 0;
        int handle = 0;
        short ret;

        Fwlib32 fwl = (Fwlib32) Native.load("Fwlib32", Fwlib32.class);

        ret = fwl.cnc_allclibhndl3("192.168.1.100", (short)8193, 10, p);

        System.out.println("cnc_allclibhndl3 Ret: " + ret);
        System.out.println("hndl: " + handle);
    }
}

在 Daniel Widdis 回复后编辑。

您好,我尝试了您的解决方案,这是我第一次工作。应用程序以 "ret = -16" 响应,这意味着 "EW_SOCKET (-16) Socket error"。这是正常的,因为另一侧没有任何 CNC。 当我用真实 IP 连接真实 CNC 时出现问题,然后出现与第一次相同的错误。

这是我的实际代码:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.ShortByReference;

public class TestJNA {

    public interface Fwlib32 extends Library {
        Fwlib32 INSTANCE = (Fwlib32) Native.load("Fwlib32", Fwlib32.class);
        short cnc_allclibhndl3(String ipaddr, short port, long timeout, ShortByReference FlibHndl);
}

    public static void main(String[] args) {
        ShortByReference handle = new ShortByReference((short)0);

        short ret = 0;

        Fwlib32 fwl = Fwlib32.INSTANCE;
        ret = fwl.cnc_allclibhndl3("192.168.1.100", (short) 8193, 4, handle);

        System.out.println("cnc_allclibhndl3 Ret: " + ret);
        System.out.println("hndl: " + handle.getValue());
    }
}

这是错误:

Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:422)
at com.sun.jna.Function.invoke(Function.java:361)
at com.sun.jna.Library$Handler.invoke(Library.java:265)
at com.sun.proxy.$Proxy0.cnc_allclibhndl3(Unknown Source)
at testjna.TestJNA.main(TestJNA.java:38)

cnc_allclibhndl3() 函数的最后一个参数是指向 short:

的指针
unsigned short *FlibHndl

所以正确的映射应该是 ShortByReference。这将初始化指向内存中其他地方的 short 的指针。目前您正在传递一个空 (0) 指针并要求本机方法访问该内存!

此外,您需要将 C long 变量映射到 Java 中的 NativeLong 而不是 long。 Java long 始终为 64 位,但 C long 根据 OS 和位数而变化。在 Windows 中,它实际上总是 32 位的,所以如果您的代码是 Windows-only,您甚至可以使用 int,但在 general/cross-platform 中,您应该使用 NativeLong 用于该映射。

此外,约定是 Native.load() 调用作为静态 INSTANCE 变量出现在接口中,而不是像您所做的那样将其定义为内联。

试试这个:

public class JnaFanuc {

    public interface Fwlib32 extends Library {
        Fwlib32 INSTANCE = (Fwlib32) Native.load("Fwlib32", Fwlib32.class);

        short cnc_allclibhndl3(String ipaddr, short port, NativeLong timeout, short FlibHndl);
    }

    public static void main(String[] args) {
        ShortByReference handle = new ShortByReference();
        short ret;
        String ip = "192.168.1.100";
        short port = (short) 8193;
        NativeLong timeout = new NativeLong(10);
        Fwlib32 fwl = Fwlib32.INSTANCE;

        ret = fwl.cnc_allclibhndl3(ip, port, timeout, handle);

        System.out.println("cnc_allclibhndl3 Ret: " + ret);
        System.out.println("hndl: " + handle.getValue());
    }
}