<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      跟我做WinForm開發(2)-后臺邏輯操作

      2012-01-08 12:32  空逸云  閱讀(5474)  評論(27)    收藏  舉報

      上一篇中,我簡單了介紹了實現自定義UI的步驟和其中一些需要注意的點;詳見:跟我做WinForm開發(1)-自定義UI,下面,我就繼續完成上篇沒完成的邏輯操作;

      獲取聲音

      這是一個發音器,聲音的來源是Google,打開Google翻譯,輸入一段英文,并點擊發音,Google很快就讀取了我所輸入的句子,打開HttpWatch,發現,實際上每次發音,都會把輸入的句子做一次UrlEncode,然后發往Google服務器,最后返回一個Mp3的流;這個URL如下http://translate.google.cn/translate_tts?ie=UTF-8&q=hello%20world%2C2012&tl=en&prev=input;從上面我們應該可以看到去參數就是你要發音的內容,而tl就是該語言的簡寫;那么我們需要做的,就是修改q獲得我們想要的MP3流;PS:在后面的嘗試當中,我發現Google做了限制,只允許長度為100;超出100則無返回結果,這個100是Length;而不是所占字節長度,所以,中文在這里更占優勢;

      好了;既然目標已確定,那就開始吧;那有什么辦法能讓我拿到這個MP3流呢?答案不言而喻,就是HttpWebRequest;在這里,我新建了一個叫HttpHelper的類,它主要用于做簡單的Http Get請求;

      internal static class HttpHelper
      {
          /// <summary>
          /// 發起請求,用于GET.
          /// </summary>
          /// <param name="url">The URL.</param>
          internal static void SendRequest(string url, WebRequestCallBack callBack)
          {
              Log.Info("Send Request");
              try
              {
                  HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                  request.KeepAlive = false;
                  request.Method = "GET";
                  CallbackParam cp = new CallbackParam
                  {
                      Request = request,
                      CallBack = callBack
                  };
                  Log.Info("Begin get Responsen.");
                  request.BeginGetResponse(BeginGetResponse, cp);
              }
              catch (Exception ex)
              {
                  Log.Info("Error:" + ex.Message);
                  callBack(null, HttpStatusCode.Continue, WebExceptionStatus.UnknownError, ex);
              }
          }
      
          static void BeginGetResponse(IAsyncResult ar)
          {
              Log.Info("Get Response");
              CallbackParam cp = ar.AsyncState as CallbackParam;
              try
              {
                  using (HttpWebResponse response = (HttpWebResponse)cp.Request.EndGetResponse(ar))
                  {
                      using (var responseStream = response.GetResponseStream())
                      {
                          MemoryStream ms = new MemoryStream();
                          byte[] buffer = new byte[1024];
                          int byteReader;
                          do
                          {
                              byteReader = responseStream.Read(buffer, 0, buffer.Length);
                              ms.Write(buffer, 0, byteReader);
                          }
                          while (byteReader > 0);
      
                          ms.Flush();
                          cp.CallBack(ms, response.StatusCode, WebExceptionStatus.Success, null);
                      }
                  }
              }
              catch (WebException ex)
              {
                  Log.Info("Error:" + ex.Message);
                  HttpWebResponse response = (HttpWebResponse)ex.Response;
                  cp.CallBack(null, response.StatusCode, ex.Status, ex);
              }
              catch (Exception ex)
              {
                  Log.Info("Error:" + ex.Message);
                  cp.CallBack(null, HttpStatusCode.Continue, WebExceptionStatus.UnknownError, ex);
              }
          }
      }
      

      從上面的代碼看到,首先,我創建了一個HttpWebRequest對象,并將其請求方法設置為GET;隨后,開始了異步請求;當獲取到

      服務器響應的時候,便將相應流讀出來,發送給回調方法,這里為什么要用異步?一個是避免主線程阻塞,導致UI掛起;另外就是這面編碼看起來更有Feel吧! :-)~~

      現在就可以直接獲取MP3流了吧!等等;還不行!應為我們還沒講輸入的字符串UrlEncode,那怎么辦?寫唄!

      public class SpeakTextHandler
      {
      
          public static string GetSpeakerUrl(string sourceText)
          {
              var config = ConfigManger.GetConfig();
              return string.Format(config.SpeakerUrl, GetEncodeText(sourceText), GetTextLanguage(config, sourceText));
          }
      
          private static string GetEncodeText(string source)
          {
              if (string.IsNullOrEmpty(source)) return string.Empty;
              return HttpUtility.UrlPathEncode(source);
          }
      
          private static string GetTextLanguage(Config config, string source)
          {
      
              foreach (var language in config.Languages)
              {
                  if (Regex.Match(source, language.Unicode).Success)
                      return language.Name;
              }
              return config.DefaultLanguage.Name;
          }
      }
      

      這里我創建了一個SpeakerTextHandler的類,它主要工作就是將傳入的字符串UrlEncode,并獲取配置,拼接出相應的Url;到這

      里,獲取聲音就大功告成了!

      播放聲音

      拿到聲音之后需要做什么?必然就是將其播放出來;由于沒弄過這方面的東西(平時都是些Asp.net);好吧,就Google吧;網上給出了好幾個解決方案;

      A:使用SoundPlayer;這個很明顯就不行,有使用經驗的童鞋應該知道,SoundPlayer只支持wav格式的播放,雖然它能支持傳入Stream流參數,但若是傳入MP3流,還是報異常;

      B:WindowsMediaPlay;但是這個必須是讀取文件;先不說是否支持MP3,單單是每次都需要先把流存儲到本地再讀取;我這懶人就無法忍受了;

      C:利用DX庫來操作;這個淡淡看解決方案就很復雜;雖然可控性可能比較強;但這復雜度。。懶人望而生畏!:-(

      難道就沒其他解決方案了嗎?幾經波折,終于在StackOverflow中找到了一個可行方案;

      Play Audio from a Stream using C#

      其中使用的是一個叫NAudio的開源組件,那么,它的確是可以解決我現在的窘境;照著StackOverflow上的代碼來寫,的確是可以播放出軟件了,但是隨后關閉軟件的時候,都會出現一個錯誤的斷言,跟蹤NAudio的實現,發現是流沒釋放;囧;最終幾次嘗試;終于把這個錯誤斷言去掉了;

      if (stream != null && ex == null)
      {
          stream.Position = 0;
          var mp3Reader = new Mp3FileReader(stream);
          var pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader);
          using (WaveStream blockAlignedStream = new BlockAlignReductionStream(pcmStream))
          {
              using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
              {
                  waveOut.Init(blockAlignedStream);
                  waveOut.PlaybackStopped += (sender, e) =>
                  {
                      waveOut.Stop();
                  };
                  waveOut.Play();
                  while (waveOut.PlaybackState == PlaybackState.Playing)
                  {
                      System.Threading.Thread.Sleep(100);
                  }
                  waveOut.Dispose();
              }
          }
      

      該實現在HttpHelper的回調當中(更多代碼請看后面放出的下載);

      快捷鍵支持

      除了僅僅能發音,那還需要支持快捷鍵放大/縮小;或者是快捷鍵發音等;那還等什么?Come On!實際上,對這方面有經驗的同學應該就能很自然的想到利用的就是“鉤子”,當然,這個鉤子的概念和我們平時編寫代碼時所使用的鉤子這個概念有所區別,例如,Asp.net中控件/Page中有很多事件,OnLoad,OnCompleted等等。我們寫代碼的時候也可能會寫一些空實現,讓子類來做實現;這就是編程概念上的“鉤子”,而這里的“鉤子”,是指在觸發系統一些事件的時候,也把我們所依附上的方法也執行了;其中的實現主要還是依靠與Win32API;

      public delegate void HotkeyEventHandler(int hotKeyID);
      public class Hotkey : System.Windows.Forms.IMessageFilter
      {
          Hashtable keyIDs = new Hashtable();
          IntPtr hWnd;
      
          public event HotkeyEventHandler OnHotkey;
      
          [DllImport("user32.dll")]
          public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 fsModifiers, UInt32 vk);
      
          [DllImport("user32.dll")]
          public static extern UInt32 UnregisterHotKey(IntPtr hWnd, UInt32 id);
      
          [DllImport("kernel32.dll")]
          public static extern UInt32 GlobalAddAtom(String lpString);
      
          [DllImport("kernel32.dll")]
          public static extern UInt32 GlobalDeleteAtom(UInt32 nAtom);
      
          public Hotkey(IntPtr hWnd)
          {
              this.hWnd = hWnd;
              Application.AddMessageFilter(this);
          }
      
          public int RegisterHotkey(Keys Key, KeyFlags keyflags)
          {
              UInt32 hotkeyid = GlobalAddAtom(System.Guid.NewGuid().ToString());
              RegisterHotKey((IntPtr)hWnd, hotkeyid, (UInt32)keyflags, (UInt32)Key);
              keyIDs.Add(hotkeyid, hotkeyid);
              return (int)hotkeyid;
          }
      
          public void UnregisterHotkeys()
          {
              Application.RemoveMessageFilter(this);
              foreach (UInt32 key in keyIDs.Values)
              {
                  UnregisterHotKey(hWnd, key);
                  GlobalDeleteAtom(key);
              }
          }
      
          public bool PreFilterMessage(ref System.Windows.Forms.Message m)
          {
              if (m.Msg == 0x312)
              {
                  if (OnHotkey != null)
                  {
                      foreach (UInt32 key in keyIDs.Values)
                      {
                          if ((UInt32)m.WParam == key)
                          {
                              OnHotkey((int)m.WParam);
                              return true;
                          }
                      }
                  }
              }
              return false;
          }
      }
      
      [Flags]
      public enum KeyFlags
      {
          Alt = 0x1,
          Ctrl = 0x2,
          Shift = 0x4,
          Win = 0x8
      }
      

      調用方法很簡單;

      Hotkey hotkey = new Hotkey(handle);
      int speakHotkey = hotkey.RegisterHotkey(System.Windows.Forms.Keys.Q, KeyFlags.Ctrl);
      hotkey.OnHotkey += new HotkeyEventHandler(it =>
      {
          if (it == speakHotkey)
          {
              SendCtrlC(Win32.GetForegroundWindow());
              Thread.Sleep(500);
              Speaker.Speak(Clipboard.GetText());
          }
      });
      

      屏幕取詞

      相信大部分同學都有使用過翻譯軟件,其中的屏幕取詞不可謂不是一大殺器,如果你想翻譯一個單詞都必須要先復制,然后在打開翻譯軟件,粘貼,這樣的話效率未免也太低了,對于用戶體驗也不好;于是,我便想著自己實現這方面的功能;Google許久,得出主要的實現方式如下:

      [討論]關于C#屏幕取詞的技術實現
      200分求[C#屏幕取詞]
      屏幕取詞技術實現原理與關鍵源碼
      如何獲取鼠標選中文本內容,請賜教
      C# 如何獲取鼠標選中文本內容

      其中可行的方法就是利用金山詞霸的dll,可惜,最終嘗試都失敗了!不過,其中單選記事本,編輯器中的文字成功,但瀏覽器/其他軟件讀詞失敗;看來,屏幕取詞,不涉及到底層,單單用C#來實現還是很有難度;那我就換個思路吧,也只能通過選中文字,按下快捷鍵,先復制到剪貼板中,再將其讀取出來;經過幾番努力,最后可行方案如下:

       public class HotKeyManager
       {
           public static void RegistSelectedSectionHotKey(IntPtr handle)
           {
               Hotkey hotkey = new Hotkey(handle);
               int speakHotkey = hotkey.RegisterHotkey(System.Windows.Forms.Keys.Q, KeyFlags.Ctrl);
               hotkey.OnHotkey += new HotkeyEventHandler(it =>
               {
                   if (it == speakHotkey)
                   {
                       SendCtrlC(Win32.GetForegroundWindow());
                       Thread.Sleep(500);
                       Speaker.Speak(Clipboard.GetText());
                   }
               });
           }
      
      
           private static void SendCtrlC(IntPtr hWnd)
           {
               Win32.SetForegroundWindow(hWnd);
               Win32.keybd_event(0x11, 0, 0, 0);
               Win32.keybd_event(67, 0, 0, 0);
               Win32.keybd_event(0x11, 0, 2, 0);
               Win32.keybd_event(67, 0, 2, 0);
           }
       }
      

      我新建了一個HotKeyManager的類,里面的RegistSelectedSectionHotKey方法注冊了熱鍵,事件先通過

      Win32API發送復制指令,線程阻塞500毫秒(將文字復制到剪貼板中需要一定的延遲時間);然后獲取剪切板的文字就大功告成了!

      尾聲

      項目雖小,卻多有趣味;其中更是應用到了一些我從來沒接觸過的東西;也學到了不少東西;故寫下備忘;也給需要這方面資料的童鞋一個幫助;總是如此,寫下來時總覺無什么可寫;但其中的收獲和感言卻不少;只有親自動手才能有所收獲;以后還需多多寫!多多益善~~

      源碼下載:Speaker.rar

      主站蜘蛛池模板: 国产欧美日韩另类在线专区| 边添小泬边狠狠躁视频| 久久精品99国产国产精| 日本一区二区久久人妻高清| 精品日本乱一区二区三区| 99热精品国产三级在线观看| 天堂v亚洲国产v第一次| 在线精品另类自拍视频| 国产成年码av片在线观看| 漂亮的保姆hd完整版免费韩国| 免费大片av手机看片高清 | 超碰自拍成人在线观看| 亚洲经典av一区二区| 欧美精品亚洲精品日韩专| 国产精品自拍午夜福利| 激情综合五月丁香亚洲| 狠狠色丁香婷婷亚洲综合| 午夜福利高清在线观看| 18禁黄无遮挡网站免费| 九九九国产| 亚洲人成网站77777在线观看| 性色av不卡一区二区三区| 国产成人无码精品久久久露脸| 亚洲高潮喷水无码AV电影| 亚洲中文字幕无码久久精品1| 国内精品人妻一区二区三区 | 欧美亚洲综合成人A∨在线| 欧美成人片一区二区三区| 午夜福利国产盗摄久久性| 国产一级区二级区三级区| 国产精品午夜爆乳美女视频| 2019亚洲午夜无码天堂| 亚洲中文字幕国产综合| 亚洲中文一区二区av| 中文字幕波多野不卡一区| 亚洲欧美高清在线精品一区二区 | 一本色道久久—综合亚洲| 成人激情视频一区二区三区 | 少妇又爽又刺激视频| 国产综合av一区二区三区| 肉大捧一进一出免费视频|