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#中的大文件上传吧,网上有很多例子了,可以参考如下文章中的代码进行开发http://www.jb51.net/article/53377.htm,可是无法上传成功,于是解读了一下代码,发现他将信息中的\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系统也要做一些修改,不过不是这篇文章的主要内容,关于服务器端的修改的小节,后续会有相关的报导。

(0)

相关推荐

  • C#获取文件相关信息的方法

    本文实例讲述了C#获取文件相关信息的方法.分享给大家供大家参考.具体分析如下: C#可以通过FileInfo类可以获得指定文件的信息,包含文件的名字,大小等. FileInfo fi = new FileInfo(@"C:\file.txt"); if(fi.Exists) { Console.WriteLine("Filename : {0}",fi.Name); Console.WriteLine("Path : {0}",fi.FullNa

  • C#实现客户端弹出消息框封装类实例

    本文实例讲述了C#实现客户端弹出消息框封装类.分享给大家供大家参考.具体如下: asp.net在服务器端运行,是不能在服务器端弹出对话框的,但是C#可以通过在页面输出JS代码实现弹出消息框的效果,这个C#类封装了常用的消息框弹出JS代码,可以在服务器端调用,在客户端显示对话框.不但可以显示JS的警告框,还可以显示模式窗口,非常方便. using System; using System.Web; using System.Web.UI; using System.Web.UI.WebContro

  • C#获取计算机名,IP,MAC信息实现代码

    利用C#获取计算机名,IP,MAC信息,如下为源代码: 复制代码 代码如下: using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Management; namespace Wenanry.Net { /// <summary> /// 获取计算机系统信息 /// </summary> public class ManagementSyst

  • C#获取客户端相关信息实例总结

    本文实例讲述了C#获取客户端相关信息的方法.分享给大家供大家参考.具体如下: [本机IP地址] 第一种方法: IPHostEntry hostentry = Dns.Resolve(Dns.GetHostName()); IPAddress address=hostentry.AddressList[0]; 第二种方法: 复制代码 代码如下: Dns.GetHostAddresses(Dns.GetHostName())[0].ToString(); [判断当前用户是否连网] PingReply

  • c#多线程网络聊天程序代码分享(服务器端和客户端)

    XuLIeHua类库 复制代码 代码如下: using System;using System.Collections;  using System.Collections.Generic;using System.Threading;  using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;using System.Text;using System.IO;using Sy

  • C#实现支持断点续传多线程下载客户端工具类

    复制代码 代码如下: /* .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient) * Reflector 了一下 System.Net.WebClient ,改写或增加了若干: * DownLoad.Upload 相关方法! * DownLoad 相关改动较大! * 增加了 DataReceive.ExceptionOccurrs 事件! * 了解服务器端与客户端交互的 HTTP 协议参阅: * 使文件下载的自定义连接支持

  • 在C#中对TCP客户端的状态封装详解

    TCP客户端连接TCP服务器端有几种应用状态:1.与服务器的连接已建立2.与服务器的连接已断开3.与服务器的连接发生异常 应用程序可按需求合理处理这些逻辑,比如:1.连接断开后自动重连2.连接断开后选择备用地址重连3.所有状态变化上报告警本文描述的TcpClient实现了状态变化的事件通知机制. 复制代码 代码如下: /// <summary>   /// 异步TCP客户端   /// </summary>   public class AsyncTcpClient : IDisp

  • 客户端实现蓝牙接收(C#)知识总结

    在实现蓝牙接收时,网上的资料很多,使用起来也很简单,但是我觉得还是有必要把这些知识总结下来.蓝牙开发需要用到一个第三方的库InTheHand.Net.Personal.dll,其中关键的两个类是 BluetoothClient 和 BluetoothListener,首先开启一个子线程来不断的接收数据,使用很简单,直接上代码: 复制代码 代码如下: using InTheHand.Net.Sockets; using System.Threading; public MainWindow() {

  • c#通过ip获取地理信息

    复制代码 代码如下: /// <summary>      /// 通过IP得到IP所在地省市(Porschev)      /// </summary>      /// <param name="ip"></param>      /// <returns></returns>      public string GetAdrByIp(string ip)      {          string url

  • C#聊天程序服务端与客户端完整实例代码

    本文所述为基于C#实现的多人聊天程序服务端与客户端完整代码.本实例省略了结构定义部分,服务端主要是逻辑处理部分代码,因此使用时需要完善一些窗体按钮之类的. 先看服务端代码如下: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Net; using

  • C#获取系统版本信息方法

    直接贴代码: 复制代码 代码如下: public class OSInfoMation { public static string OSBit() { try { ConnectionOptions oConn = new ConnectionOptions(); System.Management.ManagementScope managementScope = new System.Management.ManagementScope("\\\\localhost", oCon

  • C#用Activex实现Web客户端读取RFID功能的代码

    由于要在Web项目中采用RFID读取功能,所以有必要开发Activex,一般情况下开发Activex都采用VC,VB等,但对这两块不是很熟悉,所以采用C#编写Activex的方式实现. 本文方法参考网络 1.编写WindowsFromControls 2.发布WindowsFormControls为Activex 3.在web中使用该Activex 首先编写windows控件 如何编写不再详述(注意一个地方,GUID自己用vs工具生成一个,下面会用到.我的0CBD6597-3953-4B88-8

随机推荐