最近做项目的时候,需要对接厂商提供的 IP 摄像头。但是他们只提供了 C++ 的 SDK,没办法,只能开始撸 C# 的 SDK Helper 类。本篇文章主要记录了对接 C++ DLL 需要注意的几个地方,以及常见类型的转换。

要对接 C++ 的 DLL,首先得知道如何引用 DLL 内的方法。在 C# 当中,只需要编写符合 C++ 的函数签名,再使用 [DllImport] 特性指定 DLL 文件路径和入口点等参数即可。

假如你需要使用 Win32 API 提供的方法,这里我以 SetProcessDPIAware 函数为例:

public static class Win32Helper
{[DllImport("user32.dll")]public static extern bool SetProcessDPIAware();
}

接下来你只需要像使用静态方法一样,调用 Win32Helper.SetProcessDPIAware() 方法即可。

对接 DLL 时的问题记录

一般来说,提供 SDK 的厂商都会给你一份 DEMO 项目,或者是包含有函数定义的头文件 (*.h)。你只需要按照转换规则,将头文件里面的函数签名翻译成 C# 版本的即可。

函数签名不正确

有的时候,你名字直接和头文件一样还不行,得手动指定 EntryPoint 参数。你可以使用 DLL Export Viewer 工具来查看 DLL 的所有开放函数签名,将其复制下来,填写到 EntryPoint 参数即可。

[DllImport(@"ThirdFiles\AlprSDK.dll", EntryPoint = "AlprSDK_Startup@12", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)]
public static extern int AlprSDK_Startup(IntPtr hNotifyWnd, uint nCommandId, string pLocalAddress);

传递回调函数

有时第三方 SDK 需要你传递回调函数,一般都只提供了一个 void* 定义,也就是一个函数指针。那我们在 C# 如何将委托传递给该参数作为回调函数呢?

ALPRSDK_API OS_Error WINAPI AlprSDK_SearchAllCameras(unsigned int nTimeout,void* callback, char *pLocalAddr = NULL);

这个时候就需要使用到 [UnmanagedFunctionPointer] 特性来指定函数指针了,只需要将其标注到委托定义上,指定函数的调用方式即可。

最后我在 C# 里面编写的方法签名如下:

[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Ansi)]
public delegate void SearchAllCamerasCallback(uint deviceType, string deviceName, string deviceIp,byte[] macAddress, ushort wPortWeb, ushort wPortListen, string pSubMask, string pGateway,string pMultiAddress, string pDnsAddress, ushort wMultiPort, int nChannelNum, int nFindCount,uint dwDeviceId);[DllImport(@"ThirdFiles\AlprSDK.dll", EntryPoint = "_AlprSDK_SearchAllCameras@12", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)]
public static extern int AlprSDK_SearchAllCameras(uint nTimeout, SearchAllCamerasCallback callback, string pLocalAddress);

获取摄像头传递的位图

原始 C++ 的函数签名如下:


//捕获一张bmp图片.
//pBmpBuf:存放数据的缓冲区,传入参数时应该为NULL,内存由SDK自行管理.外面的应用程序不用去释放内存
//len:    数据的长度
ALPRSDK_API OS_Error WINAPI AlprSDK_CaptureBmp(int nHandleID, void **pBmpBuf, int *len);

主要的难点在于参数 void** pbmp 的翻译,这里参数 xx 就是指针的指针。因为这个位图是 SDK 来生成的,所以它会在内存空间开辟一段区域用于位图的存储。所以 void* 指向的是这个位图的起始地址,而我传递 void** 就是让 SDK 将这个起始地址传递给我。

所以 void* 可以翻译为 IntPtr,而这个地址不是我赋值的,而是 SDK 给我的地址,所以我们需要加上按引用传递关键字 ref

如此,我们便获得了位图在内存空间的起始地址,而且方法也将这个位图的大小给了我们。我们只需要从起始地址读取 N 个字节的数据,将其转储到 byte[] 即可。有了 byte[] 对象,你就可以进行其他的操作了,例如加载,保存等。

在 C# 内部,我是这样定义方法签名,并进行使用的:

[DllImport(@"ThirdFiles\AlprSDK.dll", EntryPoint = "_AlprSDK_CaptureBmp@12", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)]
public static extern uint AlprSDK_CaptureBmp(int nHandleId, ref IntPtr pBmpBuf, ref int len);

读取位图数据,并将其存储到磁盘当中。

var bitmapPtr = IntPtr.Zero;
var length = 0;var result = AlprSdk.AlprSDK_CaptureBmp(0, ref bitmapPtr, ref length);
ThrowIfResultNotZero("无法从摄像头获取位图",result);var bytes = new byte[length];
Marshal.Copy(bitmapPtr, bytes, 0, length);
using (var ms = File.Create(@"D:\bitmap.bmp"))
{using (var writer = new StreamWriter(ms)){writer.Write(bytes);}
}

附录 1:常用数据类型对照表

C/C++ C# 备注
WORD ushort
DWORD uint
UCHAR intbyte
UCHAR* stringIntPtr
unsigned char* [MarshalAs(UnmanagedType.LPArray)]byte[]
char* string
LPCTSTR string
LPTSTR [MarshalAs(UnmanagedType.LPTStr)] string
long int
ulong uint
HANDLE IntPtr
HWND IntPtr
void* IntPtr
int int
int* ref int
*int IntPtr
unsigned int uint
COLORREF uint
CHAR char
HDC int
HGDIOBJ int
BOOL bool
LPSTR string
LPCSTR string
BYTE byte

参考文章:C# 与 C++ 数据类型对照

附录 2:相关工具软件下载

DLL Export Viewer v1.66:https://files.cnblogs.com/files/myzony/DLL_Export_Viewer_v1.66.zip

C# 结合 PInvoke 对接 IP 摄像头的笔记相关推荐

  1. 【python记录】使用ip摄像头 vlc打开rtsp服务 python远程调用摄像头记录过程

    关于rtsp: RTSP(Real-Time Stream Protocol)协议是一个基于文本的多媒体播放控制协议,属于应用层.RTSP以客户端方式工作,对流媒体提供播放.暂停.后退.前进等操作.该 ...

  2. Java TCP/IP Socket 编程 笔记

    http://jimmee.iteye.com/blog/617110 http://jimmee.iteye.com/category/93740 Java TCP/IP Socket 编程 笔记( ...

  3. 【opencv】VideoCapture打不开本地视频文件或者网络IP摄像头

    1.前提:成功打开本地USB摄像头 // 创建VideoCapture对象 VideoCapture vc = new VideoCapture(); // 可以成功打开本地USB摄像头 // 参数可 ...

  4. 很多IP摄像头厂商都在用的固件中存在多个严重漏洞

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 法国网络安全公司 RandoriSec指出,十几家厂商提供的摄像头易受远程攻击,原因是它们都在用的一款固件中存在多个严重漏洞. 研究人员在 ...

  5. 如何使用IP摄像头进行电脑直播

    打开直播软件,都需要添加一个摄像头.电脑插个USB摄像头还是很容易的.吾有一个USB摄像头,效果较差. 如果想用IP摄像头呢?IP摄像头功能强大,能直播当然很好.吾试图找个软件,把IP摄像头模拟成电脑 ...

  6. 【转载】各大主流IP摄像头的rtsp地址介绍

    记录一下海康威视(hkvision)和安迅士(axis)IP摄像头的rtsp地址规则 海康威视 主码流: rtsp://admin:pass@192.168.1.64:554/Streamer/Cha ...

  7. OpenCV+ip摄像头实现远程实时监控

    一.项目准备 本项目所使用的内容有: 1.ip摄像头app 主要依靠连接其ip来实现远程连接的效果,效果和遥控无人机所用的app功能类似 2. 外接扩展显示屏(HDMI接口) 这个不是必需品,但是多一 ...

  8. android 摄像头 ip,摄像头已连接,但没有发生任何事情,openCV-IP摄像头Android

    这是处理,我试图将我的S3作为摄像头接口,使用IP WebCam android应用程序,然后在软件内制作IP摄像头,通常地址是http://192.168.1.XX:8080/greet.html也 ...

  9. python-OpenCv调用IP摄像头APP

    使用流程: 手机安装IP摄像头APP. 手机打开IP摄像头APP. 右上角选择 "运动检测"(这个时候你应该能看到手机摄像头打开了). 屏幕中间勾选 "RTSP服务器&q ...

最新文章

  1. redis中有key但是删不掉_一篇图文,搞定Redis事务
  2. 寒假每日一题(入门组)【week1 完结】
  3. lazadashopee代运营服务有哪些,能帮商家解决哪些问题?
  4. SAP生产订单预留(上)
  5. CISCO WLC架构及配置介绍
  6. leetcode 926. Flip String to Monotone Increasing | 926. 将字符串翻转到单调递增(前缀和)
  7. 文献记录(part80)--基于平均互信息的最优社区发现方法
  8. 左手菲尔兹右手突破奖,这个中国女婿其实是英国贵族?拿到300万奖金后他这样说……...
  9. Delphi应用程序的调试(三)监视变量
  10. python编程(指针)
  11. Python的一些单行代码(摘抄)
  12. 关于Demo3D中的Random
  13. 重邮第八届ACM大赛-预赛题解报告
  14. 一元线性模型的中位数回归
  15. 双十一数码好物指南,双十一不踩坑推荐
  16. 宁静以致远,淡泊以明志
  17. VB程序启动后如何在通知区域显示
  18. 两台计算机直接相连教程,两台电脑怎么连接局域网,小编告诉你两台电脑怎么连接局域网...
  19. 一键免费部署看板管理应用——Wekan
  20. 2021-2022学年广州市第七中学九年级第一学期11月考英语试题

热门文章

  1. Magento 默认排序为最新 How to sort Magento products by date added as default
  2. iPhone入门教程 (视频)
  3. 【今日CS 视觉论文速览】14 Dec 2018
  4. 装箱与拆箱 c# 1231
  5. 了解C#常用关键字 1214
  6. css 文本溢出 0302
  7. django-自定义错误页面-404
  8. 索引-jquery-第二版-pyhui
  9. 如何成为一名架构师,架构师成长之路(转)
  10. 什么样的前端框架才是一个好框架