C#を使ってニューマンUSBを開発して秘書のクライアントの小さい結び目に電話します


前にC#でCRMの着信弾スクリーンを開発した後、一部のお客様は新しい要求がありました.彼らは着信弾スクリーンを実現するだけでなく、呼び出した電話を録音してCRMサーバーにアップロードし、後で記録を追跡するのに便利であることを望んでいます.そこで、小さな秘書クライアントの開発が行われた.
  着信秘書クライアントの開発はニューマンUSBに基づいてクライアントを電気的に通信する(詳細は参考:
http://renzhen.iteye.com/blog/580746)をベースに開発されたのですが、ニューマン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がなくて直接着信コールバックをサポートしているため、自分で手動でデバイス状態を検出して判断するしかないが、この部分を実現するには一般的に2つの方法があり、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を空の文字で取って代わったことを発見して、サーバーが識別することができなくて、そこで私は彼のコードを変更して、問題を解決して、コードは以下の通りです:

      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
"; byte[] huanhangbyte = Encoding.UTF8.GetBytes(huanhang); // Build up the post message header StringBuilder sb = new StringBuilder(); sb.Append("--"); sb.Append(boundary); sb.Append("\r
"); sb.Append("Content-Disposition: form-data; name=\""); sb.Append(fileFormName); sb.Append("\"; filename=\""); sb.Append(Path.GetFileName(uploadfile)); sb.Append("\""); sb.Append("\r
"); sb.Append("Content-Type: "); sb.Append(contenttype); sb.Append("\r
"); sb.Append("\r
"); 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システムもいくつかの修正をしなければなりませんが、この文章の主な内容ではありません.サーバー側の修正に関する小節は、次回にしましょう.