使用C#开发纽曼USB来电小秘书客户端小结
在前面用C#开发完CRM的来电弹屏之后,有些客户有了新的要求,他们希望不但能够实现来电弹屏,更希望能够将呼入呼出的电话录音并上传到CRM服务器上,方便日后跟踪记录。于是便有了来电小秘书客户端的开发。
来电小秘书客户端的开发是基于纽曼USB来电通客户端的基础上进行开发的,由于纽曼USB来电通的硬件没有录音功能,于是硬件上使用了纽曼的另一个硬件产品来电小秘书,虽然是同一个厂家的产品,可是它们的API却是完全不兼容,更烦的是,来电小秘书API没有来电的回调接口,无法通过回调触发程序,也没有C#的Demo,很多功能只能通过一个不是那么详细的文档和一个Delphi的Demo摸索着做了,经历了一些挫折和困惑,终于完成了这个客户端程序。
首先,开发要做的就是与硬件的API进行沟通,依然通过C#的P/Invoke来完成,以下是来电小秘书的P/Invoke代码。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Runtime.InteropServices;
- namespace WindowsApplication1
- {
- class LDT1
- {
- [DllImport("usbms.dll", EntryPoint = "LoadDRV")]
- public static extern int LoadDRV();
- [DllImport("usbms.dll", EntryPoint = "EnableCard")]
- public static extern int EnableCard();
- [DllImport("usbms.dll", EntryPoint = "StopSigCheck")]
- public static extern int StopSigCheck(int Handle);
- [DllImport("usbms.dll", EntryPoint = "ReSetUsb")]
- public static extern int ReSetUsb(int Handle);
- [DllImport("usbms.dll", EntryPoint = "HangUp")]
- public static extern int HangUp(int Handle);
- [DllImport("usbms.dll", EntryPoint = "InitDtmfBuf")]
- public static extern int InitDtmfBuf(int Handle);
- [DllImport("usbms.dll", EntryPoint = "SetDialPara")]
- public static extern int SetDialPara(UInt16 RingBack1, UInt16 RingBack0, UInt16 BusyLen, UInt16 RingTimes, UInt16 SendNoSignalLen);
- [DllImport("usbms.dll", EntryPoint = "DisableCard")]
- public static extern int DisableCard();
- [DllImport("usbms.dll", EntryPoint = "FreeDRV")]
- public static extern int FreeDRV();
- [DllImport("usbms.dll", EntryPoint = "GetDtmfCode")]
- public static extern int GetDtmfCode(UInt16 Line);
- [DllImport("usbms.dll", EntryPoint = "IsRing")]
- public static extern bool IsRing(UInt16 Line);
- [DllImport("usbms.dll", EntryPoint = "GetCallerIDStr")]
- public static extern UInt16 GetCallerIDStr(UInt16 Line, StringBuilder IDStr);
- [DllImport("usbms.dll", EntryPoint = "IsOffHook")]
- public static extern bool IsOffHook(UInt16 Line);
- [DllImport("usbms.dll", EntryPoint = "StartRecordFile")]
- public static extern bool StartRecordFile(UInt16 Line, string FileName, UInt32 dwRecordLen);
- [DllImport("usbms.dll", EntryPoint = "CheckRecordEnd")]
- public static extern bool CheckRecordEnd(UInt16 Line);
- [DllImport("usbms.dll", EntryPoint = "StopRecordFile")]
- public static extern bool StopRecordFile(UInt16 Line);
- [DllImport("usbms.dll", EntryPoint = "PCMtoWave")]
- public static extern int PCMtoWave(string SourceFileName, string TargetFileName);
- [DllImport("usbms.dll", EntryPoint = "ReadCheckResult")]
- public static extern int ReadCheckResult(int line, int mode);
- [DllImport("usbms.dll", EntryPoint = "StartSigCheck")]
- public static extern void StartSigCheck(int line);
- [DllImport("usbms.dll", EntryPoint = "ReadUsbState")]
- public static extern bool ReadUsbState(int line);
- [DllImport("usbms.dll", EntryPoint = "GetRingNum")]
- public static extern int GetRingNum(int line);
- [DllImport("usbms.dll", EntryPoint = "InitRingNum")]
- public static extern void InitRingNum(int line);
- [DllImport("usbms.dll", EntryPoint = "ReadSerialNo")]
- public static extern int ReadSerialNo(int line,StringBuilder serialNo);
- }
- }
然后就是关于设备状态检测了,由于没有API直接支持来电回调,所以只能自己手动的检测设备状态来判断,要实现这一部分一般有两种方式,使用Timer或者使用Thread,Delphi的Demo中使用了Timer,可是Timer实现的弊端需要使用异步的思考方式,不符合我的思维模式,灵活度也不够,而且C#创建线程太方便了,而线程是通过同步方式思考的,所以使用了Thread模式。
然后在特定的时刻,记录电话号码、弹屏(如果是来电)、电话结束后录音和上传文件和信息到CRM服务器,其中来电号码可以很容易的获取,可是播出的号码获取就比较的麻烦了,C#中可以使用如下代码:
- while (LDT1.IsOffHook((ushort)this.line))
- {
- int temp = LDT1.GetDtmfCode((ushort)this.line);
- if (temp > 0)
- {
- phonenum = phonenum + this.convertInt(temp);
- }
- Thread.Sleep(300);
- }
- private string convertInt(int code)
- {
- string ret="";
- switch (code)
- {
- case 10:
- ret = "0";
- break;
- case 11:
- ret = "*";
- break;
- case 12:
- ret = "#";
- break;
- case 13:
- ret = "A";
- break;
- case 14:
- ret = "B";
- break;
- case 15:
- ret = "C";
- break;
- case 16:
- ret = "D";
- break;
- default:
- ret = code.ToString();
- break;
- }
- return ret;
- }
下面说一下C#中的大文件上传吧,网上有很多例子了,我参考了如下blog的代码进行开发http://www.cnblogs.com/bccu/archive/2009/01/05/1363771.html,可是无法上传成功,于是我读了一下代码,发现他将信息中的\r\n用空字符代替了,导致服务器无法识别,于是我更改了他的代码,解决了问题,代码如下:
- public static string UploadFileEx(string uploadfile, string url,
- string fileFormName, string contenttype, NameValueCollection querystring,
- CookieContainer cookies)
- {
- if ((fileFormName == null) ||
- (fileFormName.Length == 0))
- {
- fileFormName = "file";
- }
- if ((contenttype == null) ||
- (contenttype.Length == 0))
- {
- contenttype = "application/octet-stream";
- }
- string postdata;
- postdata = "?";
- if (querystring != null)
- {
- foreach (string key in querystring.Keys)
- {
- postdata += key + "=" + querystring.Get(key) + "&";
- }
- }
- Uri uri = new Uri(url + postdata);
- string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
- HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
- //webrequest.CookieContainer = cookies;
- webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
- webrequest.Method = "POST";
- string huanhang = "\r\n";
- byte[] huanhangbyte = Encoding.UTF8.GetBytes(huanhang);
- // Build up the post message header
- StringBuilder sb = new StringBuilder();
- sb.Append("--");
- sb.Append(boundary);
- sb.Append("\r\n");
- sb.Append("Content-Disposition: form-data; name=\"");
- sb.Append(fileFormName);
- sb.Append("\"; filename=\"");
- sb.Append(Path.GetFileName(uploadfile));
- sb.Append("\"");
- sb.Append("\r\n");
- sb.Append("Content-Type: ");
- sb.Append(contenttype);
- sb.Append("\r\n");
- sb.Append("\r\n");
- string postHeader = sb.ToString();
- byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);
- // Build the trailing boundary string as a byte array
- // ensuring the boundary appears on a line by itself
- byte[] boundaryBytes =
- Encoding.ASCII.GetBytes("--" + boundary + "");
- FileStream fileStream = new FileStream(uploadfile,
- FileMode.Open, FileAccess.Read);
- long length = postHeaderBytes.Length + fileStream.Length +
- boundaryBytes.Length + huanhangbyte.Length;
- webrequest.ContentLength = length;
- Stream requestStream = webrequest.GetRequestStream();
- // Write out our post header
- requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
- // Write out the file contents
- byte[] buffer = new Byte[checked((uint)Math.Min(4096,
- (int)fileStream.Length))];
- int bytesRead = 0;
- while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
- requestStream.Write(buffer, 0, bytesRead);
- requestStream.Write(huanhangbyte, 0, huanhangbyte.Length);
- // Write out the trailing boundary
- requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
- fileStream.Dispose();
- requestStream.Dispose();
- WebResponse responce = webrequest.GetResponse();
- Stream s = responce.GetResponseStream();
- StreamReader sr = new StreamReader(s);
- string retval=sr.ReadToEnd();
- sr.Dispose();
- if (File.Exists(uploadfile))
- {
- try
- {
- File.Delete(uploadfile);
- }catch(Exception e)
- {
- }
- }
- return retval;
- }
CRM来电小秘书客户端完成了,当然要配合这个功能,服务器端CRM系统也要做一些修改,不过不是这篇文章的主要内容,关于服务器端的修改的小节,就等下次再说吧。
转载于:https://www.cnblogs.com/gc2013/p/3842601.html
使用C#开发纽曼USB来电小秘书客户端小结相关推荐
- C#开发纽曼来电小秘书总结(指南)
最近帮别人开发纽曼来电小秘书,小踩了几个坑,在此与大家分享,给大家排排雷 坑1. 文档不够详细,函数不全,更没有介入流程介绍,总之就是一个大坑. EnableCard()CheckLine(Line: ...
- 2019百度云智峰会重磅发布:全自研昆仑云服务器、智能来电小秘书
8月29日,"ABC SUMMIT 2019百度云智峰会"在北京国家会议中心举行.此次大会以"AI工业化,加速产业智能"为主题.百度副总裁.智能云事业群组总经理 ...
- FPGA基础入门【12】开发板USB鼠标控制
上一篇教程介绍了NEXYS4 开发板中UART串口通信的使用方式,这一篇介绍USB接口接收鼠标和键盘信号 FPGA基础入门[12]开发板USB鼠标控制 开发板USB芯片 信号时序图 鼠标初始化 逻辑设 ...
- 使用koa2+wechaty打造个人微信小秘书
前言 开篇连连问? 你是不是有闲置的微信号? 你想不想有个小秘书定时提醒你将要做的事情? 你是否为忘记一些纪念日而懊恼? 你是否加班到很晚,而忘记了今天和别人有约? 你是不是下班还记得拿快递,到家后才 ...
- CSDN 小秘书免责声明
CSDN 小秘书免责声明 本软件采用Visual Studio 2005开发,系统环境:Windows XP,需要在.Net Framework 2.0(以上)环境支持. 本软件为开源程序,您可以随意 ...
- 聊天机器人是一场真正的革命?未来将成为私人小秘书
著名的网络媒体"BackChanel"日前撰文称,聊天机器人作为一项热门的技术,将会颠覆手机应用(APP),在个人生活.公司客服.政府服务方面都有很好的应用. 文章将此称为即将到来 ...
- Android开发中的一些小知识点记录(101-120)
编写不易,如有转载,请声明出处:http://blog.csdn.net/zxc514257857/article/details/118554522 Android开发中的一些小知识点记录(1-20 ...
- Vue团队核心成员开发的39行小工具 install-pkg 安装包,值得一学!
1. 前言 大家好,我是若川.最近组织了源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构 ...
- 大型程序是如何开发的_大型小程序如何研发提效
作者:王梦君 微信公众号:滴滴顺风车技术 出处:https://mp.weixin.qq.com/s/M1VArJ_ORY-eXSKzD6ysQw 导读: 自2016年小程序诞生以来,小程序以其&qu ...
最新文章
- 把一个人的特点写具体作文_部编版五年级下册语文习作把一个人的特点写具体教案课件+范文...
- 标星7.2万热门开源项目youtube-dl遭下架,开发者的权益谁来保护?
- Java字符串处理技巧
- Python之路(第三十一篇) 网络编程:简单的tcp套接字通信、粘包现象
- anaconda使用记录
- 中奖名单模板_春分纪中奖名单出炉~才艺主公用“树叶阵法”致敬率土!
- java 把string转为keyevent_盘点现在Java强大第三方库(字符串操作),程序员都该知道!...
- Linux启动和退出系统的方法,实验二 Linux的启动与关闭
- 打包jar文件 外部调用资源 so等
- 域服务器批量修改用户密码,Windows域控制器批量创建用户
- JS判断IE6/IE7/IE8系列的写法
- [: -ge: unary operator expected 错误
- http://maven.apache.org/POM/4.0.0 报红
- SpringApplication run方法解析:SpringApplicationRunListeners(二)
- Eclipse ADT 进行android应用签名打包详解
- 设置后台事务的执行人
- com/lsass.exe smss.exe(磁碟机病毒) 感染方式之我分析 -- 2008第一博
- BCR-ABL融合基因及检测
- Excel2010 count,countif,countifs使用
- anaconda环境安装搜不到的环境
热门文章
- 的ppt_PPT丨清新淡雅年终总结PPT模板
- arcgis中img 批量转换tif_在ArcGIS中Python使用及批量裁剪示技巧讲解 !
- SpringMVC中RequestMethod同时支持POST和GET访问
- ECharts力导向布局图增加滚动条
- Linux下Tomcat指定JDK和设置内存大小
- 【PAT乙】1069 微博转发抽奖 (20分) set
- c语言程序一些常见的不足,C语言常见错误分析及解决方法
- jQuery→事件、jQuery事件对象属性方法、多事件、自定义事件
- wps 甘特图_【WPS神技能】在Excel表格中用图表阶梯式的展示任务进程?找甘特图呀...
- p70_域名解析系统DNS