事情是这样的,有一台海康威视的摄像头,客户需要一个activex控件嵌入到网页中,通过点击按钮开始录制和结束录制来进行视频的录制和保存,关于海康摄像头的二次开发在此就不多说了,可以参考sdk中的说明。
直接上流程:
1.开发环境:vs2010,这个打包方便,之前用vs2013打包的,总是调用不了,不知道原因是什么;sdk是32位的,用64位的在winform中可以正常使用,在网页中使用控件时会报错。
2.新建项目:新建一个类库项目,如下:
右键点击项目,添加“用户控件”,如下:
界面拖控件,如下:
控件代码如下,其中guid是“工具”->“创建guid”自动生成的,#region->#endregion折叠部分是实现的iobjectsafety接口
using system; namespace videohelper { [system.security.securitysafecritical] public class videos { private bool m_initsdk = false; /// <summary> /// 正在录制 /// </summary> private bool m_record = false; private uint lasterr = 0; private int32 m_realhandle = -1; private int32 m_luserid = -1; public intptr handle { get; set; } public bool initialize(string ip = "192.168.1.64", int port = 8000, string username = "admin", string password = "8910jqk#") { try { m_initsdk = chcnetsdk.net_dvr_init(); if (m_initsdk) { chcnetsdk.net_dvr_setlogtofile(3, "c:\\sdklog\\", true); //设备参数结构体 chcnetsdk.net_dvr_deviceinfo_v30 deviceinfo = new chcnetsdk.net_dvr_deviceinfo_v30(); //注册设备 m_luserid = chcnetsdk.net_dvr_login_v30(ip, port, username, password, ref deviceinfo); return m_luserid >= 0; } return false; } catch (exception ex) { system.windows.forms.messagebox.show("initialize:" + ex.message); return false; } } public bool start(intptr handle, string filename) { try { chcnetsdk.net_dvr_previewinfo lppreviewinfo = new chcnetsdk.net_dvr_previewinfo(); lppreviewinfo.lchannel = 1; lppreviewinfo.dwlinkmode = 0; lppreviewinfo.dwstreamtype = 0; lppreviewinfo.bblocked = true; lppreviewinfo.dwdisplaybufnum = 15; lppreviewinfo.hplaywnd = handle; intptr puser = intptr.zero;//new intptr(); //获取实时视频流 m_realhandle = chcnetsdk.net_dvr_realplay_v40(m_luserid, ref lppreviewinfo, null, puser); if (m_record == false) { chcnetsdk.net_dvr_makekeyframe(m_luserid, 1); if (!chcnetsdk.net_dvr_saverealdata(m_realhandle, filename)) { lasterr = chcnetsdk.net_dvr_getlasterror(); return false; } else { m_record = true; return true; } } else { return false; } } catch { return false; } } public bool end() { if (m_record) { if (!chcnetsdk.net_dvr_stopsaverealdata(m_realhandle)) { lasterr = chcnetsdk.net_dvr_getlasterror(); return false; } m_record = false; m_realhandle = -1; return true; } else { return false; } } public void dispose() { try { if (m_luserid >= 0) { chcnetsdk.net_dvr_logout_v30(m_luserid); m_luserid = -1; } if (m_realhandle >= 0) { chcnetsdk.net_dvr_stoprealplay(m_realhandle); m_realhandle = -1; } chcnetsdk.net_dvr_cleanup(); } catch { } } } } 录制视频操作类
录制视频操作类
using system; using system.runtime.interopservices; namespace videohelper { [comimport, guidattribute("cb5bdc81-93c1-11cf-8f20-00805f2cd064")] [interfacetypeattribute(cominterfacetype.interfaceisiunknown)] public interface iobjectsafety { [preservesig] int getinterfacesafetyoptions(ref guid riid, [marshalas(unmanagedtype.u4)] ref int pdwsupportedoptions, [marshalas(unmanagedtype.u4)] ref int pdwenabledoptions); [preservesig()] int setinterfacesafetyoptions(ref guid riid, [marshalas(unmanagedtype.u4)] int dwoptionsetmask, [marshalas(unmanagedtype.u4)] int dwenabledoptions); } } 接口代码
using system; using system.windows.forms; using system.io; using system.runtime.interopservices; namespace videohelper { [system.security.securitysafecritical] [guid("79629620-3c0c-4d47-b93b-2d36aef8ef31")] public partial class videocontrol : usercontrol,iobjectsafety { public videocontrol() { initializecomponent(); } string videopath = environment.currentdirectory; videos video; intptr handle; private void btnlogin_click(object sender, eventargs e) { if (btnlogin.text == "登录") { try { if (string.isnullorwhitespace(this.txtip.text)) { messagebox.show("ip地址不能为空!"); return; } if (string.isnullorwhitespace(this.txtuserid.text)) { messagebox.show("用户名不能为空!"); return; } if (string.isnullorwhitespace(this.txtpwd.text)) { messagebox.show("密码不能为空!"); return; } video = new videos(); if (video.initialize(this.txtip.text, convert.toint32(this.numericupdown1.value), this.txtuserid.text, this.txtpwd.text)) { this.btnlogin.text = "注销"; messagebox.show("登录成功!"); this.btnstart.enabled = true; this.btnsave.enabled = true; } else { messagebox.show("登录失败!"); } } catch (exception ee) { messagebox.show("登录异常:" + ee.message); } } else if (btnlogin.text == "注销") { try { video.dispose(); this.btnlogin.text = "登录"; this.btnstart.enabled = false; this.btnsave.enabled = false; } catch (exception ee) { messagebox.show("注销异常:" + ee.message); } } } private void btnstart_click(object sender, eventargs e) { try { string filename = txtfile.text.trim(); if (filename.indexofany(path.getinvalidfilenamechars()) >= 0 || string.isnullorwhitespace(filename)) { messagebox.show("文件名含有非法字符或空格,请重新输入"); txtfile.focus(); return; } video.start(handle, filename + combobox1.selecteditem.tostring()); this.btnstart.enabled = false; this.btnsave.enabled = true; } catch (exception ee) { messagebox.show("异常:" + ee.message); } } private void btnsave_click(object sender, eventargs e) { try { if (video.end()) { messagebox.show("视频已保存!"); this.btnstart.enabled = true; this.btnsave.enabled = false; } else { messagebox.show("保存失败!"); this.btnstart.enabled = true; this.btnsave.enabled = true; } } catch (exception ee) { messagebox.show("异常:" + ee.message); } } private void button1_click(object sender, eventargs e) { try { system.diagnostics.process.start(videopath); } catch { } } private void videocontrol_load(object sender, eventargs e) { this.combobox1.selecteditem = ".mp4"; this.handle = picturebox1.handle; this.btnstart.enabled = false; this.btnsave.enabled = false; } #region iobjectsafety 成员 private const string _iid_idispatch = "{00020400-0000-0000-c000-000000000046}"; private const string _iid_idispatchex = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}"; private const string _iid_ipersiststorage = "{0000010a-0000-0000-c000-000000000046}"; private const string _iid_ipersiststream = "{00000109-0000-0000-c000-000000000046}"; private const string _iid_ipersistpropertybag = "{37d84f60-42cb-11ce-8135-00aa004bb851}"; private const int interfacesafe_for_untrusted_caller = 0x00000001; private const int interfacesafe_for_untrusted_data = 0x00000002; private const int s_ok = 0; private const int e_fail = unchecked((int)0x80004005); private const int e_nointerface = unchecked((int)0x80004002); private bool _fsafeforscripting = true; private bool _fsafeforinitializing = true; public int getinterfacesafetyoptions(ref guid riid, ref int pdwsupportedoptions, ref int pdwenabledoptions) { int rslt = e_fail; string strguid = riid.tostring("b"); pdwsupportedoptions = interfacesafe_for_untrusted_caller | interfacesafe_for_untrusted_data; switch (strguid) { case _iid_idispatch: case _iid_idispatchex: rslt = s_ok; pdwenabledoptions = 0; if (_fsafeforscripting == true) pdwenabledoptions = interfacesafe_for_untrusted_caller; break; case _iid_ipersiststorage: case _iid_ipersiststream: case _iid_ipersistpropertybag: rslt = s_ok; pdwenabledoptions = 0; if (_fsafeforinitializing == true) pdwenabledoptions = interfacesafe_for_untrusted_data; break; default: rslt = e_nointerface; break; } return rslt; } public int setinterfacesafetyoptions(ref guid riid, int dwoptionsetmask, int dwenabledoptions) { int rslt = e_fail; string strguid = riid.tostring("b"); switch (strguid) { case _iid_idispatch: case _iid_idispatchex: if (((dwenabledoptions & dwoptionsetmask) == interfacesafe_for_untrusted_caller) && (_fsafeforscripting == true)) rslt = s_ok; break; case _iid_ipersiststorage: case _iid_ipersiststream: case _iid_ipersistpropertybag: if (((dwenabledoptions & dwoptionsetmask) == interfacesafe_for_untrusted_data) && (_fsafeforinitializing == true)) rslt = s_ok; break; default: rslt = e_nointerface; break; } return rslt; } #endregion } } 控件代码
namespace videohelper { partial class videocontrol { /// <summary> /// 必需的设计器变量。 /// </summary> private system.componentmodel.icontainer components = null; /// <summary> /// 清理所有正在使用的资源。 /// </summary> /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> protected override void dispose(bool disposing) { if (disposing && (components != null)) { components.dispose(); } base.dispose(disposing); } #region 组件设计器生成的代码 /// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// </summary> private void initializecomponent() { this.button1 = new system.windows.forms.button(); this.combobox1 = new system.windows.forms.combobox(); this.label4 = new system.windows.forms.label(); this.txtfile = new system.windows.forms.textbox(); this.btnsave = new system.windows.forms.button(); this.btnstart = new system.windows.forms.button(); this.btnlogin = new system.windows.forms.button(); this.label3 = new system.windows.forms.label(); this.txtpwd = new system.windows.forms.textbox(); this.label2 = new system.windows.forms.label(); this.txtuserid = new system.windows.forms.textbox(); this.label1 = new system.windows.forms.label(); this.numericupdown1 = new system.windows.forms.numericupdown(); this.ip = new system.windows.forms.label(); this.txtip = new system.windows.forms.textbox(); this.picturebox1 = new system.windows.forms.picturebox(); ((system.componentmodel.isupportinitialize)(this.numericupdown1)).begininit(); ((system.componentmodel.isupportinitialize)(this.picturebox1)).begininit(); this.suspendlayout(); // // button1 // this.button1.cursor = system.windows.forms.cursors.hand; this.button1.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.button1.location = new system.drawing.point(377, 360); this.button1.name = "button1"; this.button1.size = new system.drawing.size(138, 22); this.button1.tabindex = 58; this.button1.text = "打开视频存放位置"; this.button1.usevisualstylebackcolor = true; this.button1.click += new system.eventhandler(this.button1_click); // // combobox1 // this.combobox1.dropdownstyle = system.windows.forms.comboboxstyle.dropdownlist; this.combobox1.flatstyle = system.windows.forms.flatstyle.flat; this.combobox1.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.combobox1.formattingenabled = true; this.combobox1.items.addrange(new object[] { ".mp4", ".avi", ".wmv", ".3gp", ".flv"}); this.combobox1.location = new system.drawing.point(303, 361); this.combobox1.name = "combobox1"; this.combobox1.size = new system.drawing.size(55, 25); this.combobox1.tabindex = 57; // // label4 // this.label4.autosize = true; this.label4.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.label4.location = new system.drawing.point(14, 360); this.label4.name = "label4"; this.label4.size = new system.drawing.size(116, 17); this.label4.tabindex = 56; this.label4.text = "请输入视频文件名:"; // // txtfile // this.txtfile.location = new system.drawing.point(136, 360); this.txtfile.name = "txtfile"; this.txtfile.size = new system.drawing.size(161, 21); this.txtfile.tabindex = 55; // // btnsave // this.btnsave.cursor = system.windows.forms.cursors.hand; this.btnsave.font = new system.drawing.font("微软雅黑", 10.5f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.btnsave.location = new system.drawing.point(490, 298); this.btnsave.name = "btnsave"; this.btnsave.size = new system.drawing.size(57, 45); this.btnsave.tabindex = 54; this.btnsave.text = "保存"; this.btnsave.usevisualstylebackcolor = true; this.btnsave.click += new system.eventhandler(this.btnsave_click); // // btnstart // this.btnstart.cursor = system.windows.forms.cursors.hand; this.btnstart.font = new system.drawing.font("微软雅黑", 10.5f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.btnstart.location = new system.drawing.point(421, 298); this.btnstart.name = "btnstart"; this.btnstart.size = new system.drawing.size(57, 45); this.btnstart.tabindex = 53; this.btnstart.text = "录制"; this.btnstart.usevisualstylebackcolor = true; this.btnstart.click += new system.eventhandler(this.btnstart_click); // // btnlogin // this.btnlogin.cursor = system.windows.forms.cursors.hand; this.btnlogin.font = new system.drawing.font("微软雅黑", 10.5f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.btnlogin.location = new system.drawing.point(352, 298); this.btnlogin.name = "btnlogin"; this.btnlogin.size = new system.drawing.size(57, 45); this.btnlogin.tabindex = 52; this.btnlogin.text = "登录"; this.btnlogin.usevisualstylebackcolor = true; this.btnlogin.click += new system.eventhandler(this.btnlogin_click); // // label3 // this.label3.autosize = true; this.label3.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.label3.location = new system.drawing.point(172, 325); this.label3.name = "label3"; this.label3.size = new system.drawing.size(44, 17); this.label3.tabindex = 51; this.label3.text = "密码:"; // // txtpwd // this.txtpwd.location = new system.drawing.point(221, 322); this.txtpwd.name = "txtpwd"; this.txtpwd.passwordchar = '*'; this.txtpwd.size = new system.drawing.size(115, 21); this.txtpwd.tabindex = 50; this.txtpwd.text = "8910jqk#"; this.txtpwd.usesystempasswordchar = true; // // label2 // this.label2.autosize = true; this.label2.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.label2.location = new system.drawing.point(8, 322); this.label2.name = "label2"; this.label2.size = new system.drawing.size(44, 17); this.label2.tabindex = 49; this.label2.text = "用户名"; // // txtuserid // this.txtuserid.location = new system.drawing.point(66, 322); this.txtuserid.name = "txtuserid"; this.txtuserid.size = new system.drawing.size(100, 21); this.txtuserid.tabindex = 48; this.txtuserid.text = "admin"; // // label1 // this.label1.autosize = true; this.label1.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.label1.location = new system.drawing.point(172, 295); this.label1.name = "label1"; this.label1.size = new system.drawing.size(44, 17); this.label1.tabindex = 47; this.label1.text = "端口:"; // // numericupdown1 // this.numericupdown1.location = new system.drawing.point(222, 295); this.numericupdown1.maximum = new decimal(new int[] { 65535, 0, 0, 0}); this.numericupdown1.minimum = new decimal(new int[] { 1, 0, 0, 0}); this.numericupdown1.name = "numericupdown1"; this.numericupdown1.size = new system.drawing.size(114, 21); this.numericupdown1.tabindex = 46; this.numericupdown1.value = new decimal(new int[] { 8000, 0, 0, 0}); // // ip // this.ip.autosize = true; this.ip.font = new system.drawing.font("微软雅黑", 9f, system.drawing.fontstyle.regular, system.drawing.graphicsunit.point, ((byte)(134))); this.ip.location = new system.drawing.point(20, 295); this.ip.name = "ip"; this.ip.size = new system.drawing.size(19, 17); this.ip.tabindex = 45; this.ip.text = "ip"; // // txtip // this.txtip.location = new system.drawing.point(66, 295); this.txtip.name = "txtip"; this.txtip.size = new system.drawing.size(100, 21); this.txtip.tabindex = 44; this.txtip.text = "192.168.1.64"; // // picturebox1 // this.picturebox1.location = new system.drawing.point(5, 5); this.picturebox1.name = "picturebox1"; this.picturebox1.size = new system.drawing.size(542, 269); this.picturebox1.tabindex = 43; this.picturebox1.tabstop = false; // // videocontrol // this.autoscaledimensions = new system.drawing.sizef(6f, 12f); this.autoscalemode = system.windows.forms.autoscalemode.font; this.controls.add(this.button1); this.controls.add(this.combobox1); this.controls.add(this.label4); this.controls.add(this.txtfile); this.controls.add(this.btnsave); this.controls.add(this.btnstart); this.controls.add(this.btnlogin); this.controls.add(this.label3); this.controls.add(this.txtpwd); this.controls.add(this.label2); this.controls.add(this.txtuserid); this.controls.add(this.label1); this.controls.add(this.numericupdown1); this.controls.add(this.ip); this.controls.add(this.txtip); this.controls.add(this.picturebox1); this.name = "videocontrol"; this.size = new system.drawing.size(556, 398); this.load += new system.eventhandler(this.videocontrol_load); ((system.componentmodel.isupportinitialize)(this.numericupdown1)).endinit(); ((system.componentmodel.isupportinitialize)(this.picturebox1)).endinit(); this.resumelayout(false); this.performlayout(); } #endregion private system.windows.forms.button button1; private system.windows.forms.combobox combobox1; private system.windows.forms.label label4; private system.windows.forms.textbox txtfile; private system.windows.forms.button btnsave; private system.windows.forms.button btnstart; private system.windows.forms.button btnlogin; private system.windows.forms.label label3; private system.windows.forms.textbox txtpwd; private system.windows.forms.label label2; private system.windows.forms.textbox txtuserid; private system.windows.forms.label label1; private system.windows.forms.numericupdown numericupdown1; private system.windows.forms.label ip; private system.windows.forms.textbox txtip; private system.windows.forms.picturebox picturebox1; } } 控件设计器代码
控件设计器代码
至此,此项目结束。
右键点击解决方案,添加新项目,如下,至于为什么建立两个项目,我一会儿在下面解释,
在hkhelper项目中添加类chcnetsdk.cs,此类是海康提供的,可以在官网找到
接下来,最重要的,项目属性设置如下,两个项目都要设置:
至此,自定义控件已经完成,接下来就是打包,新建一个安装项目:
右键点击安装项目,“添加”->“项目输出”,并选择自定义控件的项目,然后确定
然后添加海康提供的sdk的库文件文件夹下的所有文件和文件夹到项目中,如下:
然后生成项目,会生成setup.exe和setupvideo.msi两个文件,然后用打包文件,把这两个文件打包称cab文件就ok了
打包文件一共三个cabarc.exe、build.bat、install.inf
build.bat文件:
"cabarc.exe" n videosetup.cab setupvideo.msi install.inf
install.inf文件:
[version] signature="$chicago$"advancedinf=2.0[setup hooks] hook1=hook1 [hook1] run=msiexec.exe /i "%extract_dir%\setupvideo.msi" /qn
cabarc.exe是微软提供的工具
最后说一下为什么要分为两个项目去实现控件,那是因为如果在一个项目中的话,调用海康动态库的类chcnetsdk.cs不能进行com注册
以上就是c#制作activex控件中如何调用海康sdk的问题解决的详细内容。
