C#開發(fā)紐曼USB來電小秘書客戶端總結
在使用C#開發(fā)完CRM的來電彈屏之后,有些客戶有了新的要求,他們希望不但能夠實現(xiàn)來電彈屏,更希望能夠將呼入呼出的電話錄音并上傳到CRM服務器上,方便日后跟蹤記錄。于是便有了來電小秘書客戶端的開發(fā)。
本文所述的來電小秘書客戶端的開發(fā)是基于紐曼USB來電通客戶端的基礎上進行開發(fā)的,由于紐曼USB來電通的硬件沒有錄音功能,于是硬件上使用了紐曼的另一個硬件產品來電小秘書,雖然是同一個廠家的產品,可是它們的API卻是完全不兼容,更煩的是,來電小秘書API沒有來電的回調接口,無法通過回調觸發(fā)程序,也沒有C#的Demo,很多功能只能通過一個不是那么詳細的文檔和一個Delphi的Demo摸索著做了,經(jīng)歷了一些挫折和困惑,終于完成了這個客戶端程序。
首先,開發(fā)要做的就是與硬件的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); } }
然后就是關于設備狀態(tài)檢測了,由于沒有API直接支持來電回調,所以只能自己手動的檢測設備狀態(tài)來判斷,要實現(xiàn)這一部分一般有兩種方式,使用Timer或者使用Thread,Delphi的Demo中使用了Timer,可是Timer實現(xiàn)的弊端需要使用異步的思考方式,不符合我們的思維模式,靈活度也不夠,而且C#創(chuàng)建線程太方便了,而線程是通過同步方式思考的,所以使用了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#中的大文件上傳吧,網(wǎng)上有很多例子了,可以參考如下文章中的代碼進行開發(fā)http://www.dbjr.com.cn/article/53377.htm,可是無法上傳成功,于是解讀了一下代碼,發(fā)現(xiàn)他將信息中的\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系統(tǒng)也要做一些修改,不過不是這篇文章的主要內容,關于服務器端的修改的小節(jié),后續(xù)會有相關的報導。
相關文章
c# socket網(wǎng)絡編程接收發(fā)送數(shù)據(jù)示例代碼
這篇文章主要介紹了c# socket網(wǎng)絡編程,server端接收,client端發(fā)送數(shù)據(jù),大家參考使用吧2013-12-12