JNA实战笔记汇总(⼆)——JNA和CC++的数据类型映射
(dll函数回调、结构体、指针)
⽬录
JNA技术难点
有过跨平台、跨语⾔开发的程序员都知道,跨平台、预研调⽤的难点,就是不同语⾔之间数据类型不⼀致造成的问题。绝⼤部分跨平台调⽤的失败都是这个问题造成的。关于这⼀点,不论何种语⾔、何种技术⽅案都⽆法解决这个问题。JNA也不列外。
上⾯说到接⼝中使⽤的函数必须与链接库中的函数原型保持⼀致,这是JNA甚⾄所有跨平台调⽤的难点,因为C/C++的类型与Java的类型是不⼀样的,你必须转换成java对应类型让它们保持⼀致,这就是类型映射(Type Mappings),JNA官⽅给出的默认类型映射表如下:
其中类型映射的难点在于结构体、指针和函数回调。
1、函数回调
c++代码长这样:
// 实时监视接⼝
VIXHZ_EXPORT long _VixHz_StartRealPlay(
long lLoginID,
long lChannelNO,
int type,
HWND hWnd,
CallbackFuncRealDataEx func,
unsigned long dwUserParm);
/
/ 回调函数
typedef bool (CALLBACK * CallbackFuncRealDataEx)(
unsigned long lRealHandle,
unsigned long dwDataType,
unsigned char *pBuffer,
unsigned long dwBufSize,
int width,
int height,
int ra,
unsigned long dwUser);
转java,在CLibrary接⼝中函数回调函数声明为RealDataCallbackListener接⼝:
/
**
* ⽤于⽤户请求实时视频
*
* @param lLoginID 登录ID
* @param lChannelNO 通道号
* @param type 码流类型,1-主码流,2-辅码流
* @param hWnd 窗⼝句柄传空指针即可
* @param realDataResult 实时数据回调函数
* @param dwUserParm ⽤户数据参数
* @return 请求成功返回此次会话session,错误返回错误码(<=0) {@link NetworkErrorEnum}
*/
NativeLong VixHz_StartRealPlay(NativeLong lLoginID, NativeLong lChannelNO, Integer type, Pointer hWnd, RealDataCallbackListener realDataResult, String d RealDataCallbackListener接⼝:
package com.focus.vision.device.sdk.callback;
import com.sun.jna.Callback;
import com.sun.jna.NativeLong  ;
import com.sun.jna.Pointer;
import org.springframework.stereotype.Component;
/**
* 回调函数声明接⼝
*/
@Component
public interface RealDataCallbackListener extends Callback {
/**
* 获取实时视频数据回调
*
* @param lRealHandle 播放句柄
* @param dwDataType ⽆实际意义
* @param pBuffer 实时数据
* @param dwBufSize
* @param dwUser ⽤户数据
* @return
*/
boolean getRealData(NativeLong lRealHandle, NativeLong dwDataType, Pointer pBuffer, NativeLong dwBufSize, String dwUser);
}
再在需要调⽤CLibrary.INSTANCE⽅法的类中,声明getVixHz_StartRealPlay:
/**
* ⽤户请求实时视频回调函数
*
* @param lLoginID 登录ID
* @param lChannelNO 通道号
java jna
* @param type 码流类型,1-主码流,2-辅码流
* @param hWnd 窗⼝句柄传空指针即可
* @param realDataResult 实时数据回调函数
* @param dwUserParm ⽤户数据参数
* @return
*/
public static boolean getVixHz_StartRealPlay(NativeLong lLoginID, NativeLong lChannelNO, Integer type, Pointer hWnd, RealDataCallbackListener realDataRe        NativeLong startRealPlay = CLibrary.INSTANCE.VixHz_StartRealPlay(lLoginID, lChannelNO, type, hWnd, realDataResult, dwUserParm);
if (startRealPlay.intValue() > 0) {
return true;
}
return false;
}
测试实时预览,函数回调是否能够调⽤成功:
ackage com.focus.vision.device.sdk;
import com.focus.vision.device.sdk.callback.RealDataCallbackListener;
import com.focus.vision.device.sdk.callback.TalkDataCallbackListener;
import com.focus.vision.ums.AlarmCallbackEnum;
import com.focus.vision.ums.PTZConfigTypeEnum;
import com.focus.vision.ums.PTZParamConfigTypeEnum;
import com.focus.vision.ums.RecordTypeEnum;
import com.focus.vision.device.sdk.structure.QueryStructure;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.st.context.SpringBootTest;
import org.springframework.stereotype.Component;
import st.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@Component
public class DeviceSdkTests {
private static Logger logger = Logger(DeviceSdkTests.class);
@Test
public void testDeviceSdk() {
// 初始化SDK
boolean initSDKResult = CLibrary.INSTANCE.VixHz_InitSDK();
if (initSDKResult) {
logger.info("SDK初始化成功...");
// ⽤户根据⾃⼰的需要设置SDK消息回调
CLibrary.INSTANCE.VixHz_SetMessageCallback(AlarmCallbackEnum.CALLBACK_Key(), null, "0");
// 测试登录设备,返回登录句柄
NativeLong loginResult = testLoginDevice();
if (loginResult.intValue() == -1) {
return;
}
// 测试打开和关闭实时预览
testRealPlay(loginResult);
// ⽤户登出设备
CLibrary.INSTANCE.VixHz_Logout(loginResult);
}
// 退出释放SDK资源
CLibrary.INSTANCE.VixHz_UnInitSDK();
}
/**
* 测试登录设备,返回登录句柄
*
* @return
*/
private NativeLong testLoginDevice() {
NativeLong loginResult = CLibrary.INSTANCE.VixHz_LoginDevice("172.18.30.16", 80, "admin", "123456", "{}");
if (loginResult.intValue() <= 90000) {
<("设备注册失败...loginResult= {}", loginResult);
return new NativeLong(-1);
}
logger.info("设备注册成功...loginResult = {}", loginResult);
return loginResult;
}
/**
* 测试打开和关闭实时预览
*/
private void testRealPlay(NativeLong loginResult) {
boolean startRealPlay = getVixHz_StartRealPlay(loginResult, new NativeLong(0), 1, Pointer.NULL, new RealDataCallbackListener() {
@Override
public boolean getRealData(NativeLong lRealHandle, NativeLong dwDataType, Pointer pBuffer, NativeLong dwBufSize, String dwUser) {                return true;
}
}, "");
if (!startRealPlay) {
<("实时预览失败...startRealPlay = {}", startRealPlay);
return;
}
logger.info("实时预览成功...startRealPlay = {}", startRealPlay);
// 关闭实时预览
NativeLong stopRealPlayResult = CLibrary.INSTANCE.VixHz_StopRealPlay(loginResult, new NativeLong(100));
if (stopRealPlayResult.intValue() <= 0) {
<("关闭实时预览失败...stopRealPlayResult = {}", stopRealPlayResult);
}
logger.info("关闭实时预览成功...stopRealPlayResult = {}", stopRealPlayResult);
}
运⾏结果:
OK,函数回调成功啦~~
2、结构体
c++代码:
// c++接⼝不完整,作为⼀个java模仿着写了个结构体,如有问题,请不吝赐教struct Vix_QueryInfoParam
{
void *bebpic;
void *begtime;
void *endtime;
int recordtype;
int source;
void *channelno;
int protocolType;
};
java代码,编写结构体:
package com.focus.vision.device.sdk.structure;
import com.focus.vision.ums.RecordTypeEnum;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
/**
* 查询信息结构体
*/
public class QueryStructure extends Structure {
/**
* 是否为图⽚查询,0-否
*/
public Pointer bebpic;
/**
* 开始时间
*/
public Pointer begtime;
/**
* 结束时间
*/
public Pointer endtime;
/**
* 录像类型  {@link RecordTypeEnum}
*/
public Integer recordtype;
/**
* 录像源(只能为2,表设备录像)
*/
public Integer source;
/**
* 通道号
*/
public Pointer channelno;
/**
* 协议类型(只能为1,表cfi协议)
*/
public Integer protocolType;
/
**
* 内部类实现指针类型接⼝
*/

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。