如何通过JNA从xpcapi.dll的void方法返回指针参数?
解决JNA调用xPCGetParamName获取输出字符串的问题
嘿,我之前也踩过JNA处理C函数输出字符串的坑!你现在的问题核心是把输出用的char*错误声明成了String——在JNA里,String对应的是C的const char*,是用来给C函数传入字符串的,而这里blockName和paramName是C函数要往里面写数据的输出参数,自然没法拿到返回值。下面给你两种可行的解决方法:
方法一:用JNA的Pointer/Memory(推荐)
这种方式更灵活,适合不确定字符串长度或者需要动态分配内存的场景:
- 修正JNA接口的方法声明
把原来的String换成Pointer,因为我们需要传递一个可写入的内存指针给C函数:
public interface XpcApi extends Library { XpcApi INSTANCE = Native.load("xpcapi", XpcApi.class); void xPCGetParamName(int port, int paramIdx, Pointer blockName, Pointer paramName); }
- 分配内存并调用函数
先给两个输出字符串分配足够的内存空间(要记得留足\0终止符的位置,比如假设最大长度是256字节):
// 分配256字节内存,足够容纳大部分字符串(包含null终止符) Pointer blockNameMem = new Memory(256); Pointer paramNameMem = new Memory(256); // 调用DLL方法 XpcApi.INSTANCE.xPCGetParamName(port, paramIdx, blockNameMem, paramNameMem);
- 从内存中读取字符串
调用完成后,从内存指针里读取字符串即可:
// 默认使用系统编码,也可以指定编码比如"UTF-8" String blockName = blockNameMem.getString(0); String paramName = paramNameMem.getString(0);
方法二:用char[]数组
如果已经知道输出字符串的最大长度,用char[]也是个不错的选择:
- 修正JNA接口的方法声明
把输出参数换成char[]:
public interface XpcApi extends Library { XpcApi INSTANCE = Native.load("xpcapi", XpcApi.class); void xPCGetParamName(int port, int paramIdx, char[] blockName, char[] paramName); }
- 初始化数组并调用函数
创建对应长度的char数组(比如256长度),然后传入调用:
char[] blockNameArr = new char[256]; char[] paramNameArr = new char[256]; XpcApi.INSTANCE.xPCGetParamName(port, paramIdx, blockNameArr, paramNameArr);
- 将数组转成有效字符串
C函数会在字符串末尾加\0终止符,所以我们需要截断到这个位置:
// 找到第一个null终止符的位置 int blockEnd = 0; while (blockEnd < blockNameArr.length && blockNameArr[blockEnd] != '\0') { blockEnd++; } String blockName = new String(blockNameArr, 0, blockEnd); // 同样处理paramName int paramEnd = 0; while (paramEnd < paramNameArr.length && paramNameArr[paramEnd] != '\0') { paramEnd++; } String paramName = new String(paramNameArr, 0, paramEnd);
关键提醒
- 一定要确保分配的内存空间足够大,不然C函数写入时会导致内存溢出错误;
- 如果文档里有说明
blockName和paramName的最大长度,一定要按那个长度分配,不要随便猜; - 不要用
String作为输出参数,JNA会把它映射成只读的const char*,C函数往里面写会触发内存错误。
内容的提问来源于stack exchange,提问作者dzi
相关产品推荐
相关产品推荐

