LoadLibrary(Ex)失败,GetLastError返回127 (找不到指定的程序)

调试一个简单的Win32 DLL时,发现当DLLMain中调用API获取注册表键值时,LoadLibrary会返回NULL,错误代码为127。去除API调用后问题解决。进一步排查发现是由于调用了不支持的RegGetValue函数导致。
调试程序时遇到一个很怪对问题:一个很简单的win32 dll,就一个DllMain,里面就几行代码在Process Attach时调用API函数获取注册表的指定键值 ,很简单。但偏偏出了问题。问题还很怪异:另外一个程序LoadLibrary加载这个dll时返回NULL,GetLastError返回127(“ 找不到指定的程序”)。呵呵,这个错误就是怪异之处,非常难理解(其实我到现在也没有理解什么叫“指定到程序”)。去掉DllMain里面到那几行代码,只留下空函数,再编译就OK,加上那几行API就无法LoadLibrary。

按理说,就算API调用失败,也不应该影响dll本身的加载吧??dll加载失败一般发生再DllMain返回FALSE,或dll本身结构出现错误。这两点在我的这个程序里面应该都不存在:我的DllMain明明返回了TRUE(其实dll根本就没有加载,DllMain也没有执行),这个dll是VS2005刚刚编译出来的,其结构不大可能被破坏。

后来使用来排除法确定是调用了 RegGetValue到缘故。

仔细查看MSDN,这个函数“ Requires WindowsVista or WindowsXP Professional x64 Edition”而我用的是32位版本的Windows XP Pro,是个问题。不过很难理解。就算我调用了一个不被支持的API函数,顶多在这个函数被执行是给我throw一下(或返回FALSE之类的),可我遇到的情况是在这个函数被执行之前就出了问题,好像由于使用了这个函数,导致编译器在编译dll时做了什么事情似的!!实在无法理解了。还有LoadLibrary失败后的LastError信息更是误导!
package com.NetSDKDemo; import com.demo.impl.Websocket; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import static com.NetSDKDemo.ClientDemo.hCNetSDK; /** * 视频取流预览,下载,抓图mok * * @create 2022-03-30-9:48 */ public class VideoDemo { static fPlayEScallback fPlayescallback; // 裸码流回调函数 static FileOutputStream outputStream; static IntByReference m_lPort = new IntByReference(-1); /** * 获取实时裸码流回调数据 * * @param userID 登录句柄 * @param iChannelNo 通道号参数 */ public static int getESRealStreamData(int userID, int iChannelNo) { if (userID == -1) { System.out.println("请先注册"); return -1; } HCNetSDK.NET_DVR_PREVIEWINFO previewInfo = new HCNetSDK.NET_DVR_PREVIEWINFO(); previewInfo.read(); previewInfo.hPlayWnd = null; // 窗口句柄,从回调取流不显示一般设置为空 previewInfo.lChannel = iChannelNo; // 通道号 previewInfo.dwStreamType = 0; // 0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推 previewInfo.dwLinkMode = 1; // 连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4- RTP/RTSP,5- RTP/HTTP,6- HRUDP(可靠传输) ,7- RTSP/HTTPS,8- NPQ previewInfo.bBlocked = 1; // 0- 非阻塞取流,1- 阻塞取流 previewInfo.byProtoType = 0; // 应用层取流协议:0- 私有协议,1- RTSP协议 previewInfo.write(); // 开启预览 int Handle = hCNetSDK.NET_DVR_RealPlay_V40(userID, previewInfo, null, null); if (Handle == -1) { int iErr = hCNetSDK.NET_DVR_GetLastError(); System.err.println("取流失败" + iErr); return -1; } System.out.println("取流成功"); // 设置裸码流回调函数 if (fPlayescallback == null) { System.out.println("111"); fPlayescallback = new fPlayEScallback(); } if (!hCNetSDK.NET_DVR_SetESRealPlayCallBack(Handle, fPlayescallback, null)) { System.err.println("设置裸码流回调失败,错误码:" + hCNetSDK.NET_DVR_GetLastError()); } /* Boolean bStopSaveVideo = hCNetSDK.NET_DVR_StopSaveRealData(lPlay); if (bStopSaveVideo == false) { int iErr = hCNetSDK.NET_DVR_GetLastError(); System.out.println("NET_DVR_StopSaveRealData failed" + iErr); return; } System.out.println("NET_DVR_StopSaveRealData suss"); if (lPlay>=0) { if (hCNetSDK.NET_DVR_StopRealPlay(lPlay)) { System.out.println("停止预览成功"); return; } }*/ return Handle; } static class fPlayEScallback implements HCNetSDK.FPlayESCallBack { private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private boolean start = false; @Override public void invoke(int lPreviewHandle, HCNetSDK.NET_DVR_PACKET_INFO_EX pstruPackInfo, Pointer pUser) { System.out.println("111"); pstruPackInfo.read(); // 保存I帧和P帧数据 // 从第一帧 I 帧开始解析 if (pstruPackInfo.dwPacketType == 1) { start = true; } if (!start) { return; } if (pstruPackInfo.dwPacketType == 1 || pstruPackInfo.dwPacketType == 3) { // 如果是 I 帧,则将上一帧 I 帧到当前 I 帧的数据发送给 Websocket 解析 if (pstruPackInfo.dwPacketType == 1) { byte[] byteArray = outputStream.toByteArray(); outputStream.reset(); if (byteArray.length > 0) { // 通过websocket发送 long start = System.currentTimeMillis(); Websocket.sendBuffer(byteArray); System.out.println("cost: "+(System.currentTimeMillis() - start)); } } // System.out.println("dwPacketType:" + pstruPackInfo.dwPacketType // + ":wWidth:" + pstruPackInfo.wWidth // + ":wHeight:" + pstruPackInfo.wHeight // + ":包长度:" + pstruPackInfo.dwPacketSize // + ":帧号:" + pstruPackInfo.dwFrameNum); ByteBuffer buffers = pstruPackInfo.pPacketBuffer.getByteBuffer(0, pstruPackInfo.dwPacketSize); byte[] bytes = new byte[pstruPackInfo.dwPacketSize]; buffers.rewind(); buffers.get(bytes); try { outputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } } } } } package com.NetSDKDemo; import Common.osSelect; import com.sun.jna.Native; import com.sun.jna.Pointer; /** * @create 2020-12-24-17:55 */ public class ClientDemo { static HCNetSDK hCNetSDK = null; static int lUserID = -1;// 用户句柄 static int lPlayHandle = -1; // 预览句柄 static FExceptionCallBack_Imp fExceptionCallBack; static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack { public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) { System.out.println("异常事件类型:" + dwType); } } /** * 动态库加载 * * @return */ private static boolean createSDKInstance() { if (hCNetSDK == null) { synchronized (HCNetSDK.class) { String strDllPath = ""; try { if (osSelect.isWindows()) // win系统加载库路径 strDllPath = System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll"; else if (osSelect.isLinux()) // Linux系统加载库路径 strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so"; hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class); } catch (Exception ex) { System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage()); return false; } } } return true; } public static void start() { if (hCNetSDK == null) { if (!createSDKInstance()) { System.out.println("Load SDK fail"); return; } } // linux系统建议调用以下接口加载组件库 if (osSelect.isLinux()) { HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256); HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256); // 这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限 String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1"; String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1"; System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length()); ptrByteArray1.write(); hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_SDK_INIT_CFG_LIBEAY_PATH, ptrByteArray1.getPointer()); System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length()); ptrByteArray2.write(); hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_SDK_INIT_CFG_SSLEAY_PATH, ptrByteArray2.getPointer()); String strPathCom = System.getProperty("user.dir") + "/lib/"; HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH(); System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length()); struComPath.write(); hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_SDK_INIT_CFG_SDK_PATH, struComPath.getPointer()); } // SDK初始化,一个程序只需要调用一次 boolean initSuc = hCNetSDK.NET_DVR_Init(); // 异常消息回调 if (fExceptionCallBack == null) { fExceptionCallBack = new FExceptionCallBack_Imp(); } Pointer pUser = null; if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) { return; } System.out.println("设置异常消息回调成功"); // 启动SDK写日志 hCNetSDK.NET_DVR_SetLogToFile(3, "./sdkLog", false); // 设备登录 lUserID = loginDevice("109.136.71.182", (short) 10000, "admin", "sess2025"); System.out.println("实时获取裸码流示例代码"); lPlayHandle = VideoDemo.getESRealStreamData(lUserID, 33); } /** * 登录设备,支持 V40 和 V30 版本,功能一致。 * * @param ip 设备IP地址 * @param port SDK端口,默认为设备的8000端口 * @param user 设备用户名 * @param psw 设备密码 * @return 登录成功返回用户ID,失败返回-1 */ public static int loginDevice(String ip, short port, String user, String psw) { // 创建设备登录信息和设备信息对象 HCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO(); HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30(); // 设置设备IP地址 byte[] deviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN]; byte[] ipBytes = ip.getBytes(); System.arraycopy(ipBytes, 0, deviceAddress, 0, Math.min(ipBytes.length, deviceAddress.length)); loginInfo.sDeviceAddress = deviceAddress; // 设置用户名和密码 byte[] userName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN]; byte[] password = psw.getBytes(); System.arraycopy(user.getBytes(), 0, userName, 0, Math.min(user.length(), userName.length)); System.arraycopy(password, 0, loginInfo.sPassword, 0, Math.min(password.length, loginInfo.sPassword.length)); loginInfo.sUserName = userName; // 设置端口和登录模式 loginInfo.wPort = port; loginInfo.bUseAsynLogin = false; // 同步登录 loginInfo.byLoginMode = 0; // 使用SDK私有协议 // 执行登录操作 int userID = hCNetSDK.NET_DVR_Login_V30(ip, port, user, psw, deviceInfo); if (userID == -1) { System.err.println("登录失败,错误码为: " + hCNetSDK.NET_DVR_GetLastError()); } else { System.out.println(ip + " 设备登录成功!"); // 处理通道号逻辑 int startDChan = deviceInfo.byStartDChan; System.out.println("预览起始通道号: " + startDChan); } return userID; // 返回登录结果 } }我控制台输出取流成功之后为什么显示异常事件类型:32773
09-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值