使用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系统也要做一些修改,不过不是这篇文章的主要内容,关于服务器端的修改的小节,就等下次再说吧。
使用C#开发纽曼USB来电小秘书客户端小结的更多相关文章
- 【项目实例】使用C#开发纽曼USB来电通来电弹屏客户端小结
基于CRM客户和咨询者的普遍需求,老板决定在CRM系统上加入来电弹屏功能,所谓来电弹屏,就是当一个电话打入时,电脑会弹出该电话号码对应的客户.联系人或者供应商详细信息,如果是新号码,则添加一个新的客户 ...
- Android开发的16条小经验总结
Android开发的16条小经验总结,希望对各位搞Android开发的朋友有所帮助. 1. TextView中的getTextSize返回值是以像素(px)为单位的, 而setTextSize()是以 ...
- 开发H5程序或者小程序的时候,后端Web API项目在IISExpress调试中使用IP地址,便于开发调试
在我们开发开发H5程序或者小程序的时候,有时候需要基于内置浏览器或者微信开发者工具进行测试,这个时候可以采用默认的localhost进行访问后端接口,一般来说没什么问题,如果我们需要通过USB基座方式 ...
- TODO:即将开发的第一个小程序
TODO:即将开发的第一个小程序 微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验.个人理解小程序是寄宿在微信平台上的一个前端框架,具有跨平台功能, ...
- 移动开发之【微信小程序】的原理与权限问题以及相关的简易教程
这几天圈子里到处都在传播着这样一个东西,微信公众平台提供了一种新的开放能力,开发者可以快速开发一个小程序,取名曰:微信公众平台-小程序 据说取代移动开发安卓和苹果,那这个东东究竟是干吗用的?但很多人觉 ...
- 微信小程序的开发:通过微信小程序看前端
前言 2016年9月22日凌晨,微信官方通过"微信公开课"公众号发布了关于微信小程序(微信应用号)的内测通知.整个朋友圈瞬间便像炸开了锅似的,各种揣测.介绍性文章在一夜里诞生.而真 ...
- 零基础开发一款微信小程序商城
零基础开发一款微信小程序商城 一个朋友问我能不能帮忙做个商城?我一个完整网页都写不出的 菜鸟程序员,我该怎么拒绝呢?好吧,看在小程序这么火的形势下,我还是答应了!找了个开源项目,差不多花了三天时间搞定 ...
- 微信小程序开发教程 #043 - 在小程序开发中使用 npm
本文介绍了如何在微信小程序开发中使用 npm 中包的功能,大大提高微信小程序的开发效率,同时也是微信小程序系列教程的视频版更新. 微信小程序在发布之初没有对 npm 的支持功能,这也是目前很多前端开发 ...
- .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块
.Net Core ORM选择之路,哪个才适合你 因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...
随机推荐
- [Everyday Mathematics]20150202
设 $f:\bbR^2\to \bbR$ 为连续函数, 且满足条件 $$\bex f(x+1,y)=f(x,y+1)=f(x,y),\quad\forall\ (x,y)\in \bbR^2. \ee ...
- UVA 12532-Interval Product(BIT)
题意: 给n个数字的序列,C v p 把v位上的数字置成p , S l r代表求区间[l,r]各数字相乘得数的符号,对于每个S输出所得符号(’+‘,’-‘,’0‘) 分析: 开两个数组表示区间负数的个 ...
- UIButton 设置为圆形,并且使用图片(UIImage)当做背景
-(UIButton *)shareButtonWithIcon:(NSString *)iconName { UIButton *button = [UIButtonbuttonWithType:U ...
- Ye.云狐J2刷机笔记 | 完美切换内部存储卡和SD卡的改法.vold.fstab
================================================================================Ye.完美切换内部存储卡和SD卡成功.v ...
- TortoiseHg简单的入门使用说明
参考资料: 互普的 TortoiseHg使用说明_百度文库 Mercurial(Hg)基本操作 - Tim Gong - 博客园 Mercurial与TortoiseHg使用入门教程(转) - mee ...
- libpomelo的cocos2d-x客户端使用总结
这几天看了libpomelo的cocos2dx客户端这是个聊天室,由2个场景构成,登录场景LoginScene,聊天场景ChatScene. 一. LoginScene 客户端是以Login场景来启动 ...
- 网页抓取:PHP实现网页爬虫方式小结
来源:http://www.ido321.com/1158.html 抓取某一个网页中的内容,需要对DOM树进行解析,找到指定节点后,再抓取我们需要的内容,过程有点繁琐.LZ总结了几种常用的.易于实现 ...
- C语言——递归练习
1.炮弹一样的球状物体,能够堆积成一个金字塔,在顶端有一个炮弹,它坐落在一个4个炮弹组成的层面上,而这4个炮弹又坐落在一个9个炮弹组成的层面上,以此类推.写一个递归函数CannonBall,这个函数把 ...
- 机器学习中的数学(1)-回归(regression)、梯度下降(gradient descent)
版权声明: 本文由LeftNotEasy所有,发布于http://leftnoteasy.cnblogs.com.如果转载,请注明出处,在未经作者同意下将本文用于商业用途,将追究其法律责任. 前言: ...
- 视频资源下载方法[download video resources]
笔者做视频时钟分析,需要用到大量特殊的视频,如何获取需要的视频是一个问题? 以下载NBA视频为例: Tools:①腾讯视频软件 (自行下载) ②批处理文件(下文会给出代码) convert.bat ...