使用C#开发纽曼USB来电小秘书客户端小结

在前面用C#开发完CRM的来电弹屏之后,有些客户有了新的要求,他们希望不但能够实现来电弹屏,更希望能够将呼入呼出的电话录音并上传到CRM服务器上,方便日后跟踪记录。于是便有了来电小秘书客户端的开发。 
  来电小秘书客户端的开发是基于纽曼USB来电通客户端的基础上进行开发的,由于纽曼USB来电通的硬件没有录音功能,于是硬件上使用了纽曼的另一个硬件产品来电小秘书,虽然是同一个厂家的产品,可是它们的API却是完全不兼容,更烦的是,来电小秘书API没有来电的回调接口,无法通过回调触发程序,也没有C#的Demo,很多功能只能通过一个不是那么详细的文档和一个Delphi的Demo摸索着做了,经历了一些挫折和困惑,终于完成了这个客户端程序。 
  首先,开发要做的就是与硬件的API进行沟通,依然通过C#的P/Invoke来完成,以下是来电小秘书的P/Invoke代码。

C#代码  

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. namespace WindowsApplication1
  6. {
  7. class LDT1
  8. {
  9. [DllImport("usbms.dll", EntryPoint = "LoadDRV")]
  10. public static extern int LoadDRV();
  11. [DllImport("usbms.dll", EntryPoint = "EnableCard")]
  12. public static extern int EnableCard();
  13. [DllImport("usbms.dll", EntryPoint = "StopSigCheck")]
  14. public static extern int StopSigCheck(int Handle);
  15. [DllImport("usbms.dll", EntryPoint = "ReSetUsb")]
  16. public static extern int ReSetUsb(int Handle);
  17. [DllImport("usbms.dll", EntryPoint = "HangUp")]
  18. public static extern int HangUp(int Handle);
  19. [DllImport("usbms.dll", EntryPoint = "InitDtmfBuf")]
  20. public static extern int InitDtmfBuf(int Handle);
  21. [DllImport("usbms.dll", EntryPoint = "SetDialPara")]
  22. public static extern int SetDialPara(UInt16 RingBack1, UInt16 RingBack0, UInt16 BusyLen, UInt16 RingTimes, UInt16 SendNoSignalLen);
  23. [DllImport("usbms.dll", EntryPoint = "DisableCard")]
  24. public static extern int DisableCard();
  25. [DllImport("usbms.dll", EntryPoint = "FreeDRV")]
  26. public static extern int FreeDRV();
  27. [DllImport("usbms.dll", EntryPoint = "GetDtmfCode")]
  28. public static extern int GetDtmfCode(UInt16 Line);
  29. [DllImport("usbms.dll", EntryPoint = "IsRing")]
  30. public static extern bool IsRing(UInt16 Line);
  31. [DllImport("usbms.dll", EntryPoint = "GetCallerIDStr")]
  32. public static extern UInt16 GetCallerIDStr(UInt16 Line, StringBuilder IDStr);
  33. [DllImport("usbms.dll", EntryPoint = "IsOffHook")]
  34. public static extern bool IsOffHook(UInt16 Line);
  35. [DllImport("usbms.dll", EntryPoint = "StartRecordFile")]
  36. public static extern bool StartRecordFile(UInt16 Line, string FileName, UInt32 dwRecordLen);
  37. [DllImport("usbms.dll", EntryPoint = "CheckRecordEnd")]
  38. public static extern bool CheckRecordEnd(UInt16 Line);
  39. [DllImport("usbms.dll", EntryPoint = "StopRecordFile")]
  40. public static extern bool StopRecordFile(UInt16 Line);
  41. [DllImport("usbms.dll", EntryPoint = "PCMtoWave")]
  42. public static extern int PCMtoWave(string SourceFileName, string TargetFileName);
  43. [DllImport("usbms.dll", EntryPoint = "ReadCheckResult")]
  44. public static extern int ReadCheckResult(int line, int mode);
  45. [DllImport("usbms.dll", EntryPoint = "StartSigCheck")]
  46. public static extern void StartSigCheck(int line);
  47. [DllImport("usbms.dll", EntryPoint = "ReadUsbState")]
  48. public static extern bool ReadUsbState(int line);
  49. [DllImport("usbms.dll", EntryPoint = "GetRingNum")]
  50. public static extern int GetRingNum(int line);
  51. [DllImport("usbms.dll", EntryPoint = "InitRingNum")]
  52. public static extern void InitRingNum(int line);
  53. [DllImport("usbms.dll", EntryPoint = "ReadSerialNo")]
  54. public static extern int ReadSerialNo(int line,StringBuilder serialNo);
  55. }
  56. }

然后就是关于设备状态检测了,由于没有API直接支持来电回调,所以只能自己手动的检测设备状态来判断,要实现这一部分一般有两种方式,使用Timer或者使用Thread,Delphi的Demo中使用了Timer,可是Timer实现的弊端需要使用异步的思考方式,不符合我的思维模式,灵活度也不够,而且C#创建线程太方便了,而线程是通过同步方式思考的,所以使用了Thread模式。 
  然后在特定的时刻,记录电话号码、弹屏(如果是来电)、电话结束后录音和上传文件和信息到CRM服务器,其中来电号码可以很容易的获取,可是播出的号码获取就比较的麻烦了,C#中可以使用如下代码:

C#代码  

  1. while (LDT1.IsOffHook((ushort)this.line))
  2. {
  3. int temp = LDT1.GetDtmfCode((ushort)this.line);
  4. if (temp > 0)
  5. {
  6. phonenum = phonenum + this.convertInt(temp);
  7. }
  8. Thread.Sleep(300);
  9. }
  10. private string convertInt(int code)
  11. {
  12. string ret="";
  13. switch (code)
  14. {
  15. case 10:
  16. ret = "0";
  17. break;
  18. case 11:
  19. ret = "*";
  20. break;
  21. case 12:
  22. ret = "#";
  23. break;
  24. case 13:
  25. ret = "A";
  26. break;
  27. case 14:
  28. ret = "B";
  29. break;
  30. case 15:
  31. ret = "C";
  32. break;
  33. case 16:
  34. ret = "D";
  35. break;
  36. default:
  37. ret = code.ToString();
  38. break;
  39. }
  40. return ret;
  41. }

下面说一下C#中的大文件上传吧,网上有很多例子了,我参考了如下blog的代码进行开发http://www.cnblogs.com/bccu/archive/2009/01/05/1363771.html,可是无法上传成功,于是我读了一下代码,发现他将信息中的\r\n用空字符代替了,导致服务器无法识别,于是我更改了他的代码,解决了问题,代码如下:

C#代码  

  1. public static string UploadFileEx(string uploadfile, string url,
  2. string fileFormName, string contenttype, NameValueCollection querystring,
  3. CookieContainer cookies)
  4. {
  5. if ((fileFormName == null) ||
  6. (fileFormName.Length == 0))
  7. {
  8. fileFormName = "file";
  9. }
  10. if ((contenttype == null) ||
  11. (contenttype.Length == 0))
  12. {
  13. contenttype = "application/octet-stream";
  14. }
  15. string postdata;
  16. postdata = "?";
  17. if (querystring != null)
  18. {
  19. foreach (string key in querystring.Keys)
  20. {
  21. postdata += key + "=" + querystring.Get(key) + "&";
  22. }
  23. }
  24. Uri uri = new Uri(url + postdata);
  25. string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
  26. HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
  27. //webrequest.CookieContainer = cookies;
  28. webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
  29. webrequest.Method = "POST";
  30. string huanhang = "\r\n";
  31. byte[] huanhangbyte = Encoding.UTF8.GetBytes(huanhang);
  32. // Build up the post message header
  33. StringBuilder sb = new StringBuilder();
  34. sb.Append("--");
  35. sb.Append(boundary);
  36. sb.Append("\r\n");
  37. sb.Append("Content-Disposition: form-data; name=\"");
  38. sb.Append(fileFormName);
  39. sb.Append("\"; filename=\"");
  40. sb.Append(Path.GetFileName(uploadfile));
  41. sb.Append("\"");
  42. sb.Append("\r\n");
  43. sb.Append("Content-Type: ");
  44. sb.Append(contenttype);
  45. sb.Append("\r\n");
  46. sb.Append("\r\n");
  47. string postHeader = sb.ToString();
  48. byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);
  49. // Build the trailing boundary string as a byte array
  50. // ensuring the boundary appears on a line by itself
  51. byte[] boundaryBytes =
  52. Encoding.ASCII.GetBytes("--" + boundary + "");
  53. FileStream fileStream = new FileStream(uploadfile,
  54. FileMode.Open, FileAccess.Read);
  55. long length = postHeaderBytes.Length + fileStream.Length +
  56. boundaryBytes.Length + huanhangbyte.Length;
  57. webrequest.ContentLength = length;
  58. Stream requestStream = webrequest.GetRequestStream();
  59. // Write out our post header
  60. requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
  61. // Write out the file contents
  62. byte[] buffer = new Byte[checked((uint)Math.Min(4096,
  63. (int)fileStream.Length))];
  64. int bytesRead = 0;
  65. while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
  66. requestStream.Write(buffer, 0, bytesRead);
  67. requestStream.Write(huanhangbyte, 0, huanhangbyte.Length);
  68. // Write out the trailing boundary
  69. requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
  70. fileStream.Dispose();
  71. requestStream.Dispose();
  72. WebResponse responce = webrequest.GetResponse();
  73. Stream s = responce.GetResponseStream();
  74. StreamReader sr = new StreamReader(s);
  75. string retval=sr.ReadToEnd();
  76. sr.Dispose();
  77. if (File.Exists(uploadfile))
  78. {
  79. try
  80. {
  81. File.Delete(uploadfile);
  82. }catch(Exception e)
  83. {
  84. }
  85. }
  86. return retval;
  87. }

CRM来电小秘书客户端完成了,当然要配合这个功能,服务器端CRM系统也要做一些修改,不过不是这篇文章的主要内容,关于服务器端的修改的小节,就等下次再说吧。

使用C#开发纽曼USB来电小秘书客户端小结

时间: 2024-11-05 13:49:48

使用C#开发纽曼USB来电小秘书客户端小结的相关文章

使用C#开发纽曼USB来电通来电弹屏客户端小结

基于CRM客户和咨询者的普遍需求,老板决定在CRM系统上加入来电弹屏功能,所谓来电弹屏,就是当一个电话打入时,电脑会弹出该电话号码对应的客户.联系人或者供应商详细信息,如果是新号码,则添加一个新的客户.     要达到这样的效果,首先需要硬件的支持,最后老板决定使用纽曼USB来电通作为电话与电脑的连接媒介,它提供二次开发接口,可以实现电脑中获取电话来电号码并弹屏.其次需要在CRM系统中预留一个接口支持根据电话号码弹出信息.由于CRM以前和某知名呼叫中心集成,所以留有这样的借口.     于是就只

Android开发的16条小经验总结

Android开发的16条小经验总结,希望对各位搞Android开发的朋友有所帮助. 1. TextView中的getTextSize返回值是以像素(px)为单位的, 而setTextSize()是以sp为单位的. 所以如果直接用返回的值来设置会出错,解决办法是用setTextSize()的另外一种形式,可以指定单位: setTextSize(int unit, int size)    TypedValue.COMPLEX_UNIT_PX : Pixels    TypedValue.COMP

Android开发中15条小经验

Android开发中15条小经验 1. TextView中的getTextSize返回值是以像素(px)为单位的,而setTextSize()是以sp为单位的. 所以如果直接用返回的值来设置会出错,解决办法是用setTextSize()的另外一种形式,可以指定单位: setTextSize(intunit,intsize) TypedValue.COMPLEX_UNIT_PX:Pixels TypedValue.COMPLEX_UNIT_SP:ScaledPixels TypedValue.CO

一个人开发一个产品,小程序从0到1 ,第1章 开发工具

微信小程序于2017年1月9日正式上线后,受到了广大用户的关注,其较低的开发成本和微信庞大的用户量,为许多企业和个人提供了商机.为了帮助开发人员简单地新建项目,高效地开发微信小程序,微信团队提供了一套微信开发者工具. 1.1 下载安装 在微信官方文档.小程序(https://developers.weixin.qq.com/miniprogram/dev/framework)中,找到微信开发者工具的下载地址,按个人使用的操作系统下载对应的版本.不用纠结在什么平台下开发比较好的问题,毕竟它是跨平台

响应微博小秘书倡议 连夜加急撸出头像变灰小工具之开发历程

昨天看到了微博小秘书关于全国性悼念活动倡议,我非常支持这个倡议. 因为修改灰色头像会有一定技术门槛,于是思考能否开发一个小工具方便大家使用. 考虑到第二天就是哀悼日,准备夜间快速开发上线. 0X00 废话少说先上东西 有兴趣的老哥可以访问:http://smartding.top:81/ 或者 http://smartding.top:8080/ 因为暂时无法备案,所以只能采用带端口或者纯 IP 的方式访问,有点郁闷. 小工具里面记录了项目历程,有兴趣可以阅读, 0X01 选型 因为时间相当有限

Wince6.0应用开发:三、小技巧揭秘

在Wince6.0的应用开发过程中,掌握一些使用的小技巧,必定会事半功倍 那么,你做好心里准备了吗?3.2.1. 技巧一:我会告诉你你为Wince开发的程序可以在你的电脑上运行!                     这个技巧的用途有两个 1.测试程序能否达到预期效果 还记得我们上一篇帖子在模拟上用的小程序吗? 我们现在PC上运行一下 2.捕捉在Wince上不显示的异常 有时候,在Wince上运行应用程序,即使出错了也不会抛出异常,当这个时候我们只需要在电脑上运行程序便会捕捉到程序的异常,这对

Android开发短信备份小例子

主要是使用内容提供者ContentProvider #1.在activity_main.xml布局文件中添加写sdcard权限,并添加读短信的权限 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_par

Android KitKat 4.4平台开发-添加USB ADB和MTP功能支持

ADB和MTP是Android基于USB实现的两个重要功能,极大地方便了用户在PC与Android设备之间的互操作,比如传输文件.安装应用.开发调试应用. 本文讲述如何在特定软硬件平台下支持Android ADB和MTP功能. Android版本: KitKat 4.4.2 Linux内核版本: 3.10 (Vendor Kernel) 硬件平台: Atmel SAMA5D3 SoC 针对Linux内核的更改 Merge Android Linux内核USB Gadget驱动到处理器厂商Linu

(iOS)开发中收集的小方法

1.颜色转变成图片 - (UIImage *)createImageWithColor:(UIColor *)color {     CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);     UIGraphicsBeginImageContext(rect.size);     CGContextRef context = UIGraphicsGetCurrentContext();     CGContextSetFillColorWithCo