zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

c#客户端开发 总结 USB 来电
2023-06-13 09:15:41 时间

在使用C#开发完CRM的来电弹屏之后,有些客户有了新的要求,他们希望不但能够实现来电弹屏,更希望能够将呼入呼出的电话录音并上传到CRM服务器上,方便日后跟踪记录。于是便有了来电小秘书客户端的开发。

本文所述的来电小秘书客户端的开发是基于纽曼USB来电通客户端的基础上进行开发的,由于纽曼USB来电通的硬件没有录音功能,于是硬件上使用了纽曼的另一个硬件产品来电小秘书,虽然是同一个厂家的产品,可是它们的API却是完全不兼容,更烦的是,来电小秘书API没有来电的回调接口,无法通过回调触发程序,也没有C#的Demo,很多功能只能通过一个不是那么详细的文档和一个Delphi的Demo摸索着做了,经历了一些挫折和困惑,终于完成了这个客户端程序。

首先,开发要做的就是与硬件的API进行沟通,依然通过C#的P/Invoke来完成,以下是来电小秘书的P/Invoke代码。

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Runtime.InteropServices;

namespaceWindowsApplication1
{
classLDT1
{
[DllImport("usbms.dll",EntryPoint="LoadDRV")]
publicstaticexternintLoadDRV();

[DllImport("usbms.dll",EntryPoint="EnableCard")]
publicstaticexternintEnableCard();

[DllImport("usbms.dll",EntryPoint="StopSigCheck")]
publicstaticexternintStopSigCheck(intHandle);

[DllImport("usbms.dll",EntryPoint="ReSetUsb")]
publicstaticexternintReSetUsb(intHandle);

[DllImport("usbms.dll",EntryPoint="HangUp")]
publicstaticexternintHangUp(intHandle);

[DllImport("usbms.dll",EntryPoint="InitDtmfBuf")]
publicstaticexternintInitDtmfBuf(intHandle);

[DllImport("usbms.dll",EntryPoint="SetDialPara")]
publicstaticexternintSetDialPara(UInt16RingBack1,UInt16RingBack0,UInt16BusyLen,UInt16RingTimes,UInt16SendNoSignalLen);


[DllImport("usbms.dll",EntryPoint="DisableCard")]
publicstaticexternintDisableCard();

[DllImport("usbms.dll",EntryPoint="FreeDRV")]
publicstaticexternintFreeDRV();

[DllImport("usbms.dll",EntryPoint="GetDtmfCode")]
publicstaticexternintGetDtmfCode(UInt16Line);

[DllImport("usbms.dll",EntryPoint="IsRing")]
publicstaticexternboolIsRing(UInt16Line);

[DllImport("usbms.dll",EntryPoint="GetCallerIDStr")]
publicstaticexternUInt16GetCallerIDStr(UInt16Line,StringBuilderIDStr);


[DllImport("usbms.dll",EntryPoint="IsOffHook")]
publicstaticexternboolIsOffHook(UInt16Line);


[DllImport("usbms.dll",EntryPoint="StartRecordFile")]
publicstaticexternboolStartRecordFile(UInt16Line,stringFileName,UInt32dwRecordLen);

[DllImport("usbms.dll",EntryPoint="CheckRecordEnd")]
publicstaticexternboolCheckRecordEnd(UInt16Line);


[DllImport("usbms.dll",EntryPoint="StopRecordFile")]
publicstaticexternboolStopRecordFile(UInt16Line);

[DllImport("usbms.dll",EntryPoint="PCMtoWave")]
publicstaticexternintPCMtoWave(stringSourceFileName,stringTargetFileName);

[DllImport("usbms.dll",EntryPoint="ReadCheckResult")]
publicstaticexternintReadCheckResult(intline,intmode);

[DllImport("usbms.dll",EntryPoint="StartSigCheck")]
publicstaticexternvoidStartSigCheck(intline);

[DllImport("usbms.dll",EntryPoint="ReadUsbState")]
publicstaticexternboolReadUsbState(intline);

[DllImport("usbms.dll",EntryPoint="GetRingNum")]
publicstaticexternintGetRingNum(intline);

[DllImport("usbms.dll",EntryPoint="InitRingNum")]
publicstaticexternvoidInitRingNum(intline);

[DllImport("usbms.dll",EntryPoint="ReadSerialNo")]
publicstaticexternintReadSerialNo(intline,StringBuilderserialNo);

}
}

然后就是关于设备状态检测了,由于没有API直接支持来电回调,所以只能自己手动的检测设备状态来判断,要实现这一部分一般有两种方式,使用Timer或者使用Thread,Delphi的Demo中使用了Timer,可是Timer实现的弊端需要使用异步的思考方式,不符合我们的思维模式,灵活度也不够,而且C#创建线程太方便了,而线程是通过同步方式思考的,所以使用了Thread模式。

然后在特定的时刻,记录电话号码、弹屏(如果是来电)、电话结束后录音和上传文件和信息到CRM服务器,其中来电号码可以很容易的获取,可是播出的号码获取就比较的麻烦了,C#中可以使用如下代码:

while(LDT1.IsOffHook((ushort)this.line))
{
inttemp=LDT1.GetDtmfCode((ushort)this.line);
if(temp>0)
{
phonenum=phonenum+this.convertInt(temp);
}
Thread.Sleep(300);

}
privatestringconvertInt(intcode)
{
stringret="";
switch(code)
{
case10:
ret="0";
break;
case11:
ret="*";
break;
case12:
ret="#";
break;
case13:
ret="A";
break;
case14:
ret="B";
break;
case15:
ret="C";
break;
case16:
ret="D";
break;
default:
ret=code.ToString();
break;
}
returnret;
}
publicstaticstringUploadFileEx(stringuploadfile,stringurl,
stringfileFormName,stringcontenttype,NameValueCollectionquerystring,
CookieContainercookies)
{
if((fileFormName==null)||
(fileFormName.Length==0))
{
fileFormName="file";
}

if((contenttype==null)||
(contenttype.Length==0))
{
contenttype="application/octet-stream";
}


stringpostdata;
postdata="?";
if(querystring!=null)
{
foreach(stringkeyinquerystring.Keys)
{
postdata+=key+"="+querystring.Get(key)+"&";
}
}
Uriuri=newUri(url+postdata);

stringboundary="----------"+DateTime.Now.Ticks.ToString("x");
HttpWebRequestwebrequest=(HttpWebRequest)WebRequest.Create(uri);
//webrequest.CookieContainer=cookies;
webrequest.ContentType="multipart/form-data;boundary="+boundary;
webrequest.Method="POST";
stringhuanhang="\r\n";
byte[]huanhangbyte=Encoding.UTF8.GetBytes(huanhang);

//Buildupthepostmessageheader
StringBuildersb=newStringBuilder();
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");

stringpostHeader=sb.ToString();
byte[]postHeaderBytes=Encoding.UTF8.GetBytes(postHeader);

//Buildthetrailingboundarystringasabytearray
//ensuringtheboundaryappearsonalinebyitself
byte[]boundaryBytes=
Encoding.ASCII.GetBytes("--"+boundary+"");

FileStreamfileStream=newFileStream(uploadfile,
FileMode.Open,FileAccess.Read);
longlength=postHeaderBytes.Length+fileStream.Length+
boundaryBytes.Length+huanhangbyte.Length;
webrequest.ContentLength=length;

StreamrequestStream=webrequest.GetRequestStream();

//Writeoutourpostheader
requestStream.Write(postHeaderBytes,0,postHeaderBytes.Length);

//Writeoutthefilecontents
byte[]buffer=newByte[checked((uint)Math.Min(4096,
(int)fileStream.Length))];
intbytesRead=0;
while((bytesRead=fileStream.Read(buffer,0,buffer.Length))!=0)
requestStream.Write(buffer,0,bytesRead);
requestStream.Write(huanhangbyte,0,huanhangbyte.Length);
//Writeoutthetrailingboundary
requestStream.Write(boundaryBytes,0,boundaryBytes.Length);
fileStream.Dispose();
requestStream.Dispose();
WebResponseresponce=webrequest.GetResponse();
Streams=responce.GetResponseStream();
StreamReadersr=newStreamReader(s);
stringretval=sr.ReadToEnd();
sr.Dispose();

if(File.Exists(uploadfile))
{
try
{
File.Delete(uploadfile);
}catch(Exceptione)
{
}
}
returnretval;
}

CRM来电小秘书客户端完成了,当然要配合这个功能,服务器端CRM系统也要做一些修改,不过不是这篇文章的主要内容,关于服务器端的修改的小节,后续会有相关的报导。