将函数指针的 C 结构体转换为 JNA 代码

Posted

技术标签:

【中文标题】将函数指针的 C 结构体转换为 JNA 代码【英文标题】:Translate C struct of function pointers to JNA code 【发布时间】:2017-09-18 04:50:25 【问题描述】:
// original c code

struct callback 
    void (*recv_msg_)(const char * msg, int type, unsigned int len);
    void (*connected_)(void *cs);
    void (*disconnected_)(void *cs);
;

void recv_msg(const char *msg, int type, unsigned int len)

    // some code
    //......


void connected(void *s)

    // some code
    //......


void disconnected(void *s)

    // some code
    //......


struct callback cb;
cb.recv_msg_ = recv_msg;
cb.connected_ = connected;
cb.disconnected = disconnected;

init("127.0.0.1", 5672, &cb);
// C code end
////////////////////////////////////////////////////////////////////////

// THE JNA code

interface RecvMsg extends Callback 
    void invoke(String msg, int type, int con_len);


interface CbConnected extends Callback 
    void invoke(Pointer ctx);


interface CbDisconnected extends Callback 
    void invoke(Pointer ctx);


class RecvMsgImpl implements RecvMsg 
    @Override
    public void invoke(String msg, int type, int len) 
        System.out.println("recv msg: " + msg);
    


class CbConnectedImpl implements CbConnected 
    @Override
    public void invoke(Pointer ctx) 
        System.out.println("connected.");
    


class CbDisconnectedImpl implements CbDisconnected 
    @Override
    public void invoke(Pointer ctx) 
        System.out.println("diconnected.");
    


public class MyCallBack extends Structure 
    public RecvMsg recv_msg_;
    public CbConnected cb_connected_;
    public CbDisconnected cb_disconnected_;

    @Override
    protected List getFieldOrder() 
        return Arrays.asList(new String[] "recv_msg_", "cb_connected_", "cb_disconnected_");
    


MyCallBack cb = new MyCallBack();
cb.recv_msg_ = new RecvMsgImpl();
cb.cb_connected_ = new CbConnectedImpl();
cb.cb_disconnected_ = new CbDisconnectedImpl();

Xxx xxx = (Xxx) Native.loadLibrary("***", Xxx.class);
xxx.init("127.0.0.1", 5672, cb);

// Java code end
////////////////////////////////////////////////////////////////////

我运行java代码,得到如下异常:

Exception in thread "main" java.lang.IllegalArgumentException: Structure field "cb_connected_" was declared as interface DLLTest.CbConnected, which is not supported within a Structure
    at com.sun.jna.Structure.writeField(Structure.java:808)
    at com.sun.jna.Structure.write(Structure.java:718)
    at com.sun.jna.Structure.autoWrite(Structure.java:1923)
    at com.sun.jna.Function.convertArgument(Function.java:505)
    at com.sun.jna.Function.invoke(Function.java:297)
    at com.sun.jna.Library$Handler.invoke(Library.java:212)
    at com.sun.proxy.$Proxy1.init(Unknown Source)
    at DLLTest.Tester.main(Tester.java:55)

请告诉我如何使用 JNA 将其翻译成 java。

【问题讨论】:

发布你到目前为止所做的事情 java代码是我到目前为止所做的。我得到了异常,但我无法解决它。 【参考方案1】:

这是我对 jna 库的测试。

我认为你必须找到与我的不同之处。

我自己编写了代码,因为您没有向我展示完整的源代码。

我的开发环境是一个带有 msys2 的 mingw64 和一个带有 java(1.8) 的 eclipse(oxygen)

这里有更多细节。

Gcc 版本

Using built-in specs.
COLLECT_GCC=C:\DEV\COMP\msys32\mingw64\bin\gcc.exe
COLLECT_LTO_WRAPPER=C:/DEV/COMP/msys32/mingw64/bin/../lib/gcc/x86_64-w64-
mingw32/6.3.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: .....skip
Thread model: posix
gcc version 6.3.0 (Rev1, Built by MSYS2 project)

Java 信息​​

java.class.version::52.0
sun.management.compiler::HotSpot 64-Bit Tiered Compilers
sun.arch.data.model::64
sun.desktop::windows
sun.cpu.isalist::amd64

首先,你的 JnaTest 类的完整代码。

package ***;

import java.util.Arrays;
import java.util.List;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;

public class JnaTest 
    public interface JnaInf extends Library 
        public void init(String val, int port, MyCallBack cb);
    

    public static void main(String[] args) 
        MyCallBack cb = new MyCallBack();
        cb.recv_msg_ = new RecvMsgImpl();
        cb.cb_connected_ = new CbConnectedImpl();
        cb.cb_disconnected_ = new CbDisconnectedImpl();

        System.load("C:\\DEV\\COMP\\msys32\\home\\***\\jna_inf.dll");


        JnaInf xxx = (JnaInf) Native.loadLibrary("jna_inf", JnaInf.class);
        xxx.init("127.0.0.1", 5672, cb);
    

    interface RecvMsg extends Callback 
        void invoke(String msg, int type, int con_len);
    

    interface CbConnected extends Callback 
        void invoke(Pointer ctx);
    

    interface CbDisconnected extends Callback 
        void invoke(Pointer ctx);
    

    static class RecvMsgImpl implements RecvMsg 
        @Override
        public void invoke(String msg, int type, int len) 
            System.out.println("recv msg: " + msg);
            System.out.println("type: " + type);
            System.out.println("len: " + len);
        
    

    static class CbConnectedImpl implements CbConnected 
        @Override
        public void invoke(Pointer ctx) 
            System.out.println("connected.");
        
    

    static class CbDisconnectedImpl implements CbDisconnected 
        @Override
        public void invoke(Pointer ctx) 
            System.out.println("diconnected.");
        
    

    public static class MyCallBack extends Structure 
        public RecvMsg recv_msg_;
        public CbConnected cb_connected_;
        public CbDisconnected cb_disconnected_;

        @Override
        protected List getFieldOrder() 
            return Arrays.asList(new String[]  "recv_msg_", "cb_connected_", "cb_disconnected_" );
        
    

那么,c源代码名jna_info.c如下,

struct callback 
    void (*recv_msg_)(const char * msg, int type, unsigned int len);
    void (*connected_)(void *cs);
    void (*disconnected_)(void *cs);
;

void recv_msg(const char *msg, int type, unsigned int len)

    // some code
    //......


void connected(void *s)

    // some code
    //......
    return;


void disconnected(void *s)

    // some code
    //......
    return;


void init(const char *msg, int type, struct callback *mycallback)

    mycallback->recv_msg_("123", 22, 3);
    mycallback->connected_("123");
    return;

编译c源代码

gcc -c jna_inf.c
gcc -shared -o jna_inf.dll jna_inf.o

输出看起来像我所期待的......

我真诚地希望这对你有所帮助。

【讨论】:

以上是关于将函数指针的 C 结构体转换为 JNA 代码的主要内容,如果未能解决你的问题,请参考以下文章

使用 JNA 将本机 C 函数映射到 Java 接口时的指针问题

C 语言结构体 ( 结构体作为函数参数 | 结构体指针作为函数参数 )

JNA 结构和指针映射

c语言函数返回字符串时必须要用指针吗?如果返回结构体呢?函数在返回那些类型值时必须要用指针?

C++入门基础教程:C语言的指针与结构体到底怎么用?

C++入门基础教程:C语言的指针与结构体到底怎么用?