 using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading;using Debug = System.Diagnostics.Debug;namespace Piao{  public partial class MainForm : Form  {    private delegate void UpdateFormControlDelegate(object arg);    Func<Image, string> captchaHandle;//initialized in ctor.    private static Mutex threadMutex = new Mutex(false, "{69082C9C-0783-41B8-BC32-BD5556F10D09}");    DateTime lastPress = DateTime.Today;    string pressed = string.Empty;    int WORKER_TIMEOUT_MINUTES = 60;    int ORDER_DAY_AHEAD = 11;    Win7ProcessIcon win7SuperIcon = new Win7ProcessIcon();    public MainForm()    {      InitializeComponent();      InitializeBackgroundWorker();      InitializeControlsFromSetting();      InitializeCaptchaDelegate();#if DEBUG      this.Text = " - DEBUG VERSION";#endif    }    private void txt_userFromStation_Autocompletion(object sender, KeyPressEventArgs e)    {      ComboBox box = (sender as ComboBox);      BindingSource filterSource = box.DataSource as BindingSource;      if (filterSource == null)        return;      //reset all columns      if (e.KeyChar == (char)Keys.Escape)      {        if (box.SelectedIndex > 0)        {          string text = box.Text;          filterSource.Filter = string.Empty;          box.Text = text;        }        else          filterSource.Filter = string.Empty;        e.Handled = true;        return;      }      //only accept valid input [a-zA-Z]      //65-90 97-122      bool onlyLetters = (e.KeyChar >= (char)65 && e.KeyChar <= (char)90) || (e.KeyChar >= (char)97 && e.KeyChar <= (char)122);      if (!onlyLetters)        return;      //timeout to clear cached input      TimeSpan ts = DateTime.Now - lastPress;      if (ts.TotalSeconds > 1)      {        pressed = string.Empty;      }      lastPress = DateTime.Now;      pressed = e.KeyChar.ToString().ToUpper();      //dont use empty data source , the combox will throw ArgumentOutofRangeException      //before that there is an empty row added in the table, it will be default item when search has no result      string searchQuery = string.Format("[{0}] like '{1}%'", Global.DataComlumnPinYin, pressed);      if (Global.StationNameTable.Select(searchQuery).Length == 0)        searchQuery = string.Format("[{0}] is null", Global.DataComlumnPinYin);      Log.Debug("filter by {0}", searchQuery);      filterSource.Filter = searchQuery;      //only handle the first char for navigation      if (pressed.Length != 1)        e.Handled = true;      Debug.WriteLine(pressed);    }    private void txt_webCaptcha_KeyPressForFilter(object sender, KeyPressEventArgs e)    {      if (e.KeyChar == (char)Keys.Back || e.KeyChar == (char)Keys.Delete)        return;      if (txt_webCaptcha.Text.Length >= 4)      {        e.Handled = true;        return;      }      if ((e.KeyChar < '0' && e.KeyChar > '9')        || (e.KeyChar < 'a' && e.KeyChar > 'z')        || (e.KeyChar < 'A' && e.KeyChar > 'Z')        || (e.KeyChar == ' ')        )        e.Handled = true;    }    /// <summary>    /// read server city names.    /// </summary>    private void StartPrep()    {      Log.Debug("start:after logon init.");      UpdateFormControlDelegate initialzeStationThreadDelegate = new UpdateFormControlDelegate(arg =>      {        if (Global.StationNameDict.Count == 0)        {          MessageBox.Show("未能初始化,关闭并重启窗口再试。", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);          return;        }        try        {          //here assign data source only once          if (txt_userFromStation.DataSource == null)          {            Log.Debug("apply data source to controls");            BindingSource bindSourceFrom = new BindingSource();            BindingSource bindSourceTo = new BindingSource();            //use different data source            bindSourceFrom.DataSource = Global.StationNameTable;            bindSourceTo.DataSource = Global.StationNameTable.Copy();            txt_userFromStation.DataSource = bindSourceFrom;            txt_userFromStation.ValueMember = Global.DataComlumnDisplayText;            txt_userToStation.DataSource = bindSourceTo;            txt_userToStation.ValueMember = Global.DataComlumnDisplayText;          }          txt_userFromStation.Enabled = true;          txt_userToStation.Enabled = true;          txt_userFromStation.Text = Configurations.txt_userFromStation;          txt_userToStation.Text = Configurations.txt_userToStation;        }        catch (Exception exc)        {          Log.Debug(exc.ToString());        }      });      UpdateFormControlDelegate initialzeSeatTypesThreadDelegate = new UpdateFormControlDelegate(arg =>        {          Log.Debug("refresh seat types.");          List<JsonObject> list = arg as List<JsonObject>;          if (list == null || list.Count == 0)            return;          try          {            foreach (JsonObject obj in list)            {              if (chk_userSeatTypes.Items.Contains(obj.value) == false)              { chk_userSeatTypes.Items.Add(obj.value);              }            }            if (chk_userSeatTypes.Items.Count > 2)            {              chk_userSeatTypes.SetItemChecked(0, true);              chk_userSeatTypes.SetItemChecked(1, true);            }            Log.Debug("end:select first seat as default.");            txt_userToStation_QueryStStrainAll(txt_userToStation, EventArgs.Empty);          }          catch (Exception exc)          {            Log.Debug(exc.ToString());          }        });      UpdateFormControlDelegate initialzeControlDisplayThreadDelegate = new UpdateFormControlDelegate(arg =>        {          Log.Debug("end:app init is complete.");          menu_status.Text = "Ready";          this.TopMost = false;          group_captcha.Enabled = true;          group_login.Enabled = true;          group_ticket.Enabled = true;          group_webform.Enabled = true;        });      Thread thPrep = new Thread(() =>      {        int i = 0;        while (i  < 2)        {          if (Global.StationNameDict.Count == 0)            UserOpration.Instance.QueryStationName();          else if (Global.TicketCodeList.Count == 0)            UserOpration.Instance.QuerySeatTypes();          else            break;          CheckThreadStateToAbort();          Thread.Sleep(1000);        }        this.Invoke(initialzeStationThreadDelegate, Global.StationNameDict);        this.Invoke(initialzeSeatTypesThreadDelegate, Global.TicketCodeList);        this.Invoke(initialzeControlDisplayThreadDelegate, "");      });      thPrep.Start();    }    private void btn_login_Click(object sender, EventArgs e)    {      Log.Debug("start:log in");      this.btn_login.Enabled = false;      txt_webCaptcha.Focus();      string user = txt_userWebName.Text;      string pwd = txt_userWebPassword.Text;      UpdateFormControlDelegate loginComplete = new UpdateFormControlDelegate(arg =>      {        string welcomename = arg as string;        user_imageBox.Image = null;        lbl_userCaptchaInfo.Text = string.Empty;        txt_webCaptcha.Text = null;        btn_login.Enabled = true;        btn_login.Focus();        if (!string.IsNullOrEmpty(welcomename))        {          this.Text = arg.ToString();          menu_status.Text = "登陆成功";          menu_start.ForeColor = Color.Red;          menu_start.Enabled = true;          StartPrep();          Log.Message("已登陆, 等待加载成功后点击 {0} 刷新; 站名首字母查询不支持多音字。", menu_start.Text);        }        Log.Debug("log in action is complete.");      });      Thread waitInputThread = new Thread(() =>      {        string propmtString = string.Empty;        for (int i = 0; i < int.MaxValue; i )        {          //retry logon for 3 times if failed          propmtString = UserOpration.NewInstance().Login(captchaHandle, user, pwd);          if (!string.IsNullOrEmpty(propmtString))            break;        }        this.Invoke(loginComplete, propmtString);      });      waitInputThread.SetApartmentState(ApartmentState.STA);      waitInputThread.Start();    }    private void txt_userToStation_QueryStStrainAll(object sender, EventArgs e)    {      if (txt_userToStation.SelectedIndex < 0 ||        txt_userFromStation.SelectedIndex < 0 ||        string.IsNullOrEmpty(txt_userToStation.Text) ||        string.IsNullOrEmpty(txt_userFromStation.Text))        return;      if (txt_dateTimePicker.Value <= DateTime.Today)      {        Log.Error("日期需要大于今日. ");        return;      }      Log.Debug("start:search trains.");      txt_userTrains.Items.Clear();      txt_userTrains.Enabled = false;      txt_userOrderTrainName.Text = string.Empty;      txt_userOrderTicketLeft.Text = string.Empty;      string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");      //first one is initial letter for index      string fromText = txt_userFromStation.Text.Split(',')[1];      string toText = txt_userToStation.Text.Split(',')[1];      //already in dropdown so index won't be out of bound.      string fromCode = FindCodeByChineseName(fromText);      string toCode = FindCodeByChineseName(toText);      if (fromCode == toCode) return;      if (txt_userFromStation.SelectedIndex < 0 || txt_userToStation.SelectedIndex < 0)      {        txt_userTrains.Enabled = false;        return;      }      SetWorkStatus(true);      UpdateFormControlDelegate initializeTrainListThreadDelegate = new UpdateFormControlDelegate(arg =>      {        try        {          Log.Debug("start:set data to controls for seat types.");          Comparison<JsonObject> compareDelegate = delegate(JsonObject x, JsonObject y)          {            if (x.value[0] == y.value[0])            { return 0; }            int result = x.value[0] > y.value[0] ? -1 : 1;            return result;          };          List<object> extraNames = new List<object>();          List<JsonObject> source = arg as List<JsonObject>;          source.Sort(compareDelegate);          foreach (JsonObject item in source)          {            if (item.end_station_name == toText) //put exact match to the beginning and put the rest to endtxt_userTrains.Items.Add(item.value);            else              extraNames.Add(item.value);          }          txt_userTrains.Items.AddRange(extraNames.ToArray<object>());          if (txt_userTrains.Items.Count > 0)          {            txt_userTrains.Enabled = true;            if (txt_userTrains.Items.Contains(Configurations.txt_userTrains))            {              txt_userTrains.SelectedItem = Configurations.txt_userTrains;            }            else              txt_userTrains.SelectedIndex = 0;            Log.Debug("end:retrieve train list is complete.");            txt_userTrains.Focus();          }          else          {            Log.Error("[{0}] 到 [{1}] 车次信息暂无。", fromText, toText);          }        }        catch (Exception ex)        {          Log.Debug(ex.ToString());        }        finally        {          SetWorkStatus(false);        }      });      Thread thPrep = new Thread(() =>      {        if (threadMutex.WaitOne(TimeSpan.Zero))        {          try          {            object stationData = UserOpration.Instance.QueryStStrainAll(day, fromCode, toCode);            this.Invoke(initializeTrainListThreadDelegate, stationData);          }          finally          {            threadMutex.ReleaseMutex();          }        }        else        {          Log.Debug("Thread is busy, job of this thread is aborted. from {0} to {1}", fromText, toText);        }      });      thPrep.SetApartmentState(ApartmentState.STA);      thPrep.Start();    }    /// <summary>    /// get train info by id.     /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void txt_userTrains_QueryLeftTickets(object sender, EventArgs e)    {      if (txt_dateTimePicker.Value <= DateTime.Today)      {        Log.Error("日期需要大于今日. ");        return;      }      lst_trainDetail.Items.Clear();      txt_userOrderTicketLeft.Text = "";      txt_userOrderTrainName.Text = "";      if (txt_userTrains.SelectedIndex < 0)      {        this.lst_trainDetail.Tag = null;        return;      }      Log.Debug("start:query left tickets");      string trainId = txt_userTrains.SelectedItem.ToString();      var train = Global.TrainCodeList.Find(t => t.value == trainId);      if (train == null)      {        this.lst_trainDetail.Tag = null;        return;      }      try      {        SetWorkStatus(true);        //query left ticket        string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");        string from = FindCodeByChineseName(txt_userFromStation.Text.Split(',')[1]);        string to = FindCodeByChineseName(txt_userToStation.Text.Split(',')[1]);        //set data tag        OrderData odata = new OrderData()        {          station_train_code = train.value,          train_date = day,          seattype_num = "",          from_station_telecode = from,          to_station_telecode = to,          include_student = "00",          from_station_telecode_name = "始发站",          to_station_telecode_name = "目的站",          round_train_date = "",          round_start_time_str = "00:00--24:00",          single_round_type = "1",          train_pass_type = "QB",          train_class_arr = "QB#D#Z#T#K#QT#",          start_time_str = "00:00--24:00",          lishi = train.lishi,          train_start_time = train.start_time,          trainno = train.id,          arrive_time = "15:42",          from_station_name = "始发站",          to_station_name = "目的站",          ypInfoDetail = train.ypInfoDetail,        };        txt_userOrderTrainName.Text = train.value;        //station chinese name to code after output        bool result = UserOpration.Instance.QueryLeftTicket(day, ref from, ref to, train.id, ref odata);        txt_userOrderTicketLeft.Text = result ? "有" : "无";        Log.Debug("end: query left ticket, attach object data to tag.");        //update listview with property 'lishi'        var propList = train.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);        foreach (var p in propList)        {          string val = p.GetValue(train) as string;          var item = new ListViewItem(p.Name);          item.SubItems.Add(val);          lst_trainDetail.Items.Add(item);        }        this.lst_trainDetail.Tag = odata;      }      catch (Exception ex)      {        Log.Debug(ex.ToString());      }      finally      { SetWorkStatus(false); }    }    private void menu_start_Click(object sender, EventArgs e)    {      Log.Debug("start:timer enabled for search.");      Global.SeatTypeTargets = new List<JsonObject>();      foreach (var checkeditem in chk_userSeatTypes.CheckedItems)      {        JsonObject obj = null;        if (          (obj = Global.TicketCodeList.Find(j => j.value == checkeditem.ToString()))          != null)        {          Global.SeatTypeTargets.Add(obj);          continue;        }      }      if (Global.SeatTypeTargets.Count == 0)      {        MessageBox.Show("需要选择票类型", "Error");        return;      }      if (lst_trainDetail.Tag == null)      {        MessageBox.Show("需要选择一个列车, 等待加载或选择。", "Error");        return;      }      SetWorkStatus(true);      UserData user = new UserData();      //user.passenger_1_seat = tickets[0].id;      user.passenger_1_ticket = "1"; //成人      user.passenger_1_name = txt_userSeatName.Text;      user.passenger_1_cardtype = "1";//二代身份证      user.passenger_1_cardno = txt_userIdNumber.Text;      user.passenger_1_mobileno = txt_userSeatTel.Text;      this.backgroundWorker1.RunWorkerAsync(user);    }    private void menu_cancel_Click(object sender, EventArgs e)    {      Log.Debug("start:timer abort signal sent.");      if (this.backgroundWorker1.IsBusy)      {        this.backgroundWorker1.CancelAsync();      }    }    private void menu_ShowWebPage_Click(object sender, EventArgs e)    {      WebForm web = new WebForm();      web.Show();    }    void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)    {      this.Invoke(new UpdateFormControlDelegate(a =>      {        win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NOPROGRESS);        Log.Message("##运行已经停止。##");        SetWorkStatus(false);        notifyIcon1.ShowBalloonTip(3000, "12306", "运行已经停止。", ToolTipIcon.Info);      }),      "");    }    void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)    {      BackgroundWorker worker = sender as BackgroundWorker;      OrderData odata = lst_trainDetail.Tag as OrderData;      UserData user = e.Argument as UserData;      if (user == null)      {        return;      }      Log.Message("开始运行, 查询超时约{1}分钟后停止, 点击 {0} 可以立刻停止。", menu_cancel.Text, WORKER_TIMEOUT_MINUTES);      System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();      watch.Start();      bool result = false;      while (watch.Elapsed.TotalMinutes < WORKER_TIMEOUT_MINUTES)      {        if ((worker.CancellationPending == true))        {          e.Cancel = true;          break;        }        else        {          result = UserOpration.Instance.QueryLeftTicket(odata.train_date,              ref odata.from_station_telecode,              ref odata.to_station_telecode,              odata.trainno,              ref odata);          if (result)            break;          Thread.Sleep(1000);        }        int percent = (int)(100 * watch.Elapsed.TotalMinutes / WORKER_TIMEOUT_MINUTES);        percent = percent < 30 ? 30 : percent; //for virsual effort set to 30%        worker.ReportProgress(percent);      }      if (result == false)      {        Log.Error("车次信息不可用, 停止提交。 ");        return;      }      UserOpration.Instance.SubmitOrderRequest(odata, user, captchaHandle);    }    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)    {      win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NORMAL);      win7SuperIcon.SetProgress(this.Handle, (ulong)e.ProgressPercentage, 100);    }    protected override void OnClosing(CancelEventArgs e)    {      menu_cancel_Click(menu_cancel, null);      if (txt_userFromStation.Text != null)        Configurations.txt_userFromStation = txt_userFromStation.Text.ToString();      if (txt_userToStation.Text != null)        Configurations.txt_userToStation = txt_userToStation.Text.ToString();      if (txt_userTrains.Text != null)        Configurations.txt_userTrains = txt_userTrains.Text.ToString();      Properties.Settings.Default.Save();      Configurations.Save();      base.OnClosing(e);    }    #region private func    private void SetWorkStatus(bool isworking = true)    {      menu_status.Text = isworking ? "正在查询" : "Ready";      menu_start.Enabled = !isworking;      group_login.Enabled = !isworking;      group_webform.Enabled = !isworking;      menu_cancel.Enabled = isworking;    }    private void InitializeControlsFromSetting()    {      string procName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;      int pCount = System.Diagnostics.Process.GetProcessesByName(procName).Length - 1;      this.StartPosition = FormStartPosition.Manual;      this.Location = new Point(        Screen.PrimaryScreen.WorkingArea.Width - Width - 400 * pCount,        100 * pCount);      this.Icon = Icon.ExtractAssociatedIcon(Environment.ExpandEnvironmentVariables("%windir%"  @"\system32\winver.exe"));      this.notifyIcon1.Icon = this.Icon;      txt_dateTimePicker.Value = DateTime.Today.Add(new TimeSpan(ORDER_DAY_AHEAD, 0, 0, 0));      chk_userSeatTypes.Items.AddRange(Configurations.chk_userSeatTypes.Split(','));      Log.Add(new FormLog(this.txt_log));      foreach (string p in Properties.Settings.Default.webProxy)      {        ToolStripMenuItem menuItem = new ToolStripMenuItem(p);        menuItem.Click = (object sender, EventArgs e) =>        {          foreach (ToolStripMenuItem i in Proxy_toolStripMenuItem.DropDownItems)          {            i.CheckState = CheckState.Unchecked;          }          ToolStripMenuItem item = sender as ToolStripMenuItem;          item.CheckState = CheckState.Checked;          UserOpration.Instance.ProxyName = item.Text;        };        Proxy_toolStripMenuItem.DropDownItems.Add(menuItem);      }      KeyPressEventHandler submitHandler = delegate(object sender, KeyPressEventArgs e)      {        if (e.KeyChar == (char)Keys.Enter)        {          btn_login_Click(btn_login, EventArgs.Empty);          e.Handled = true;        }      };      txt_userWebName.KeyPress = submitHandler;      txt_userWebPassword.KeyPress = submitHandler;    }    private void InitializeCaptchaDelegate()    {      UpdateFormControlDelegate updateImage = new UpdateFormControlDelegate(arg =>      {        if (!cb_autoCaptcha.Checked)        {          this.BringToFront();          this.Activate();          txt_webCaptcha.Focus();        }        user_imageBox.Image = arg as Image;        lbl_userCaptchaInfo.Text = "60秒内输入验证码, 不区分大小写。";      });      UpdateFormControlDelegate clearCaptchaCode = new UpdateFormControlDelegate(arg =>      {        this.TopMost = false;        txt_webCaptcha.Text = string.Empty;        user_imageBox.Image = null;        lbl_userCaptchaInfo.Text = string.Empty;      });      UpdateFormControlDelegate updateAutoCaptcha = new UpdateFormControlDelegate(arg =>      {        txt_webCaptcha.Text = arg as string;      });      captchaHandle = (img) =>      {        if (img == null)        {          Log.Error("出现错误, 不能获取验证码。 ");          return string.Empty;        }        ImageUtil.GrayImage(ref img);        this.Invoke(updateImage, img);        if (cb_autoCaptcha.Checked)        {          tessnet2.Tesseract tessocr = new tessnet2.Tesseract();          tessocr.SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");          tessocr.Init(null, "eng", false); // To use correct tessdata          List<tessnet2.Word> result = tessocr.DoOCR(new Bitmap(img), Rectangle.Empty);          string _result = result[0].Text.Trim();          if(_result.Length<4)          {            _result = "1234";          }          this.Invoke(updateAutoCaptcha, _result);          //txt_webCaptcha.Text = result[0].Text.Trim();          Log.Error("验证码为:"  result[0].Text.Trim()  "置信度为:"  result[0].Confidence);        }        else        {          Log.Error("!!!!!!!!! 输入验证码 !!!!!!!!!!!");        }        int i = 0;        while (i  < 20)        {          Thread.Sleep(2000);          if (txt_webCaptcha.Text.Length >= 4)            break;          CheckThreadStateToAbort();        }        string ret = txt_webCaptcha.Text;        this.Invoke(clearCaptchaCode, "");        return ret;      };    }    private void InitializeBackgroundWorker()    {      this.backgroundWorker1.WorkerSupportsCancellation = true;      this.backgroundWorker1.DoWork = new DoWorkEventHandler(backgroundWorker1_DoWork);      this.backgroundWorker1.RunWorkerCompleted = new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);    }    private void CheckThreadStateToAbort()    {      if (this.IsDisposed || Thread.CurrentThread.ThreadState == ThreadState.AbortRequested)        Thread.CurrentThread.Abort();    }    private string FindCodeByChineseName(string name)    {      var rows = Global.StationNameTable.Select(string.Format("{0}='{1}'", Global.DataComlumnChineseName, name));      string code = rows[0][Global.DataComlumnCodeName] as string;      return code;    }    #endregion  }}
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading;using Debug = System.Diagnostics.Debug;namespace Piao{  public partial class MainForm : Form  {    private delegate void UpdateFormControlDelegate(object arg);    Func<Image, string> captchaHandle;//initialized in ctor.    private static Mutex threadMutex = new Mutex(false, "{69082C9C-0783-41B8-BC32-BD5556F10D09}");    DateTime lastPress = DateTime.Today;    string pressed = string.Empty;    int WORKER_TIMEOUT_MINUTES = 60;    int ORDER_DAY_AHEAD = 11;    Win7ProcessIcon win7SuperIcon = new Win7ProcessIcon();    public MainForm()    {      InitializeComponent();      InitializeBackgroundWorker();      InitializeControlsFromSetting();      InitializeCaptchaDelegate();#if DEBUG      this.Text = " - DEBUG VERSION";#endif    }    private void txt_userFromStation_Autocompletion(object sender, KeyPressEventArgs e)    {      ComboBox box = (sender as ComboBox);      BindingSource filterSource = box.DataSource as BindingSource;      if (filterSource == null)        return;      //reset all columns      if (e.KeyChar == (char)Keys.Escape)      {        if (box.SelectedIndex > 0)        {          string text = box.Text;          filterSource.Filter = string.Empty;          box.Text = text;        }        else          filterSource.Filter = string.Empty;        e.Handled = true;        return;      }      //only accept valid input [a-zA-Z]      //65-90 97-122      bool onlyLetters = (e.KeyChar >= (char)65 && e.KeyChar <= (char)90) || (e.KeyChar >= (char)97 && e.KeyChar <= (char)122);      if (!onlyLetters)        return;      //timeout to clear cached input      TimeSpan ts = DateTime.Now - lastPress;      if (ts.TotalSeconds > 1)      {        pressed = string.Empty;      }      lastPress = DateTime.Now;      pressed = e.KeyChar.ToString().ToUpper();      //dont use empty data source , the combox will throw ArgumentOutofRangeException      //before that there is an empty row added in the table, it will be default item when search has no result      string searchQuery = string.Format("[{0}] like '{1}%'", Global.DataComlumnPinYin, pressed);      if (Global.StationNameTable.Select(searchQuery).Length == 0)        searchQuery = string.Format("[{0}] is null", Global.DataComlumnPinYin);      Log.Debug("filter by {0}", searchQuery);      filterSource.Filter = searchQuery;      //only handle the first char for navigation      if (pressed.Length != 1)        e.Handled = true;      Debug.WriteLine(pressed);    }    private void txt_webCaptcha_KeyPressForFilter(object sender, KeyPressEventArgs e)    {      if (e.KeyChar == (char)Keys.Back || e.KeyChar == (char)Keys.Delete)        return;      if (txt_webCaptcha.Text.Length >= 4)      {        e.Handled = true;        return;      }      if ((e.KeyChar < '0' && e.KeyChar > '9')        || (e.KeyChar < 'a' && e.KeyChar > 'z')        || (e.KeyChar < 'A' && e.KeyChar > 'Z')        || (e.KeyChar == ' ')        )        e.Handled = true;    }    /// <summary>    /// read server city names.    /// </summary>    private void StartPrep()    {      Log.Debug("start:after logon init.");      UpdateFormControlDelegate initialzeStationThreadDelegate = new UpdateFormControlDelegate(arg =>      {        if (Global.StationNameDict.Count == 0)        {          MessageBox.Show("未能初始化,关闭并重启窗口再试。", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);          return;        }        try        {          //here assign data source only once          if (txt_userFromStation.DataSource == null)          {            Log.Debug("apply data source to controls");            BindingSource bindSourceFrom = new BindingSource();            BindingSource bindSourceTo = new BindingSource();            //use different data source            bindSourceFrom.DataSource = Global.StationNameTable;            bindSourceTo.DataSource = Global.StationNameTable.Copy();            txt_userFromStation.DataSource = bindSourceFrom;            txt_userFromStation.ValueMember = Global.DataComlumnDisplayText;            txt_userToStation.DataSource = bindSourceTo;            txt_userToStation.ValueMember = Global.DataComlumnDisplayText;          }          txt_userFromStation.Enabled = true;          txt_userToStation.Enabled = true;          txt_userFromStation.Text = Configurations.txt_userFromStation;          txt_userToStation.Text = Configurations.txt_userToStation;        }        catch (Exception exc)        {          Log.Debug(exc.ToString());        }      });      UpdateFormControlDelegate initialzeSeatTypesThreadDelegate = new UpdateFormControlDelegate(arg =>        {          Log.Debug("refresh seat types.");          List<JsonObject> list = arg as List<JsonObject>;          if (list == null || list.Count == 0)            return;          try          {            foreach (JsonObject obj in list)            {              if (chk_userSeatTypes.Items.Contains(obj.value) == false)              { chk_userSeatTypes.Items.Add(obj.value);              }            }            if (chk_userSeatTypes.Items.Count > 2)            {              chk_userSeatTypes.SetItemChecked(0, true);              chk_userSeatTypes.SetItemChecked(1, true);            }            Log.Debug("end:select first seat as default.");            txt_userToStation_QueryStStrainAll(txt_userToStation, EventArgs.Empty);          }          catch (Exception exc)          {            Log.Debug(exc.ToString());          }        });      UpdateFormControlDelegate initialzeControlDisplayThreadDelegate = new UpdateFormControlDelegate(arg =>        {          Log.Debug("end:app init is complete.");          menu_status.Text = "Ready";          this.TopMost = false;          group_captcha.Enabled = true;          group_login.Enabled = true;          group_ticket.Enabled = true;          group_webform.Enabled = true;        });      Thread thPrep = new Thread(() =>      {        int i = 0;        while (i  < 2)        {          if (Global.StationNameDict.Count == 0)            UserOpration.Instance.QueryStationName();          else if (Global.TicketCodeList.Count == 0)            UserOpration.Instance.QuerySeatTypes();          else            break;          CheckThreadStateToAbort();          Thread.Sleep(1000);        }        this.Invoke(initialzeStationThreadDelegate, Global.StationNameDict);        this.Invoke(initialzeSeatTypesThreadDelegate, Global.TicketCodeList);        this.Invoke(initialzeControlDisplayThreadDelegate, "");      });      thPrep.Start();    }    private void btn_login_Click(object sender, EventArgs e)    {      Log.Debug("start:log in");      this.btn_login.Enabled = false;      txt_webCaptcha.Focus();      string user = txt_userWebName.Text;      string pwd = txt_userWebPassword.Text;      UpdateFormControlDelegate loginComplete = new UpdateFormControlDelegate(arg =>      {        string welcomename = arg as string;        user_imageBox.Image = null;        lbl_userCaptchaInfo.Text = string.Empty;        txt_webCaptcha.Text = null;        btn_login.Enabled = true;        btn_login.Focus();        if (!string.IsNullOrEmpty(welcomename))        {          this.Text = arg.ToString();          menu_status.Text = "登陆成功";          menu_start.ForeColor = Color.Red;          menu_start.Enabled = true;          StartPrep();          Log.Message("已登陆, 等待加载成功后点击 {0} 刷新; 站名首字母查询不支持多音字。", menu_start.Text);        }        Log.Debug("log in action is complete.");      });      Thread waitInputThread = new Thread(() =>      {        string propmtString = string.Empty;        for (int i = 0; i < int.MaxValue; i )        {          //retry logon for 3 times if failed          propmtString = UserOpration.NewInstance().Login(captchaHandle, user, pwd);          if (!string.IsNullOrEmpty(propmtString))            break;        }        this.Invoke(loginComplete, propmtString);      });      waitInputThread.SetApartmentState(ApartmentState.STA);      waitInputThread.Start();    }    private void txt_userToStation_QueryStStrainAll(object sender, EventArgs e)    {      if (txt_userToStation.SelectedIndex < 0 ||        txt_userFromStation.SelectedIndex < 0 ||        string.IsNullOrEmpty(txt_userToStation.Text) ||        string.IsNullOrEmpty(txt_userFromStation.Text))        return;      if (txt_dateTimePicker.Value <= DateTime.Today)      {        Log.Error("日期需要大于今日. ");        return;      }      Log.Debug("start:search trains.");      txt_userTrains.Items.Clear();      txt_userTrains.Enabled = false;      txt_userOrderTrainName.Text = string.Empty;      txt_userOrderTicketLeft.Text = string.Empty;      string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");      //first one is initial letter for index      string fromText = txt_userFromStation.Text.Split(',')[1];      string toText = txt_userToStation.Text.Split(',')[1];      //already in dropdown so index won't be out of bound.      string fromCode = FindCodeByChineseName(fromText);      string toCode = FindCodeByChineseName(toText);      if (fromCode == toCode) return;      if (txt_userFromStation.SelectedIndex < 0 || txt_userToStation.SelectedIndex < 0)      {        txt_userTrains.Enabled = false;        return;      }      SetWorkStatus(true);      UpdateFormControlDelegate initializeTrainListThreadDelegate = new UpdateFormControlDelegate(arg =>      {        try        {          Log.Debug("start:set data to controls for seat types.");          Comparison<JsonObject> compareDelegate = delegate(JsonObject x, JsonObject y)          {            if (x.value[0] == y.value[0])            { return 0; }            int result = x.value[0] > y.value[0] ? -1 : 1;            return result;          };          List<object> extraNames = new List<object>();          List<JsonObject> source = arg as List<JsonObject>;          source.Sort(compareDelegate);          foreach (JsonObject item in source)          {            if (item.end_station_name == toText) //put exact match to the beginning and put the rest to endtxt_userTrains.Items.Add(item.value);            else              extraNames.Add(item.value);          }          txt_userTrains.Items.AddRange(extraNames.ToArray<object>());          if (txt_userTrains.Items.Count > 0)          {            txt_userTrains.Enabled = true;            if (txt_userTrains.Items.Contains(Configurations.txt_userTrains))            {              txt_userTrains.SelectedItem = Configurations.txt_userTrains;            }            else              txt_userTrains.SelectedIndex = 0;            Log.Debug("end:retrieve train list is complete.");            txt_userTrains.Focus();          }          else          {            Log.Error("[{0}] 到 [{1}] 车次信息暂无。", fromText, toText);          }        }        catch (Exception ex)        {          Log.Debug(ex.ToString());        }        finally        {          SetWorkStatus(false);        }      });      Thread thPrep = new Thread(() =>      {        if (threadMutex.WaitOne(TimeSpan.Zero))        {          try          {            object stationData = UserOpration.Instance.QueryStStrainAll(day, fromCode, toCode);            this.Invoke(initializeTrainListThreadDelegate, stationData);          }          finally          {            threadMutex.ReleaseMutex();          }        }        else        {          Log.Debug("Thread is busy, job of this thread is aborted. from {0} to {1}", fromText, toText);        }      });      thPrep.SetApartmentState(ApartmentState.STA);      thPrep.Start();    }    /// <summary>    /// get train info by id.     /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void txt_userTrains_QueryLeftTickets(object sender, EventArgs e)    {      if (txt_dateTimePicker.Value <= DateTime.Today)      {        Log.Error("日期需要大于今日. ");        return;      }      lst_trainDetail.Items.Clear();      txt_userOrderTicketLeft.Text = "";      txt_userOrderTrainName.Text = "";      if (txt_userTrains.SelectedIndex < 0)      {        this.lst_trainDetail.Tag = null;        return;      }      Log.Debug("start:query left tickets");      string trainId = txt_userTrains.SelectedItem.ToString();      var train = Global.TrainCodeList.Find(t => t.value == trainId);      if (train == null)      {        this.lst_trainDetail.Tag = null;        return;      }      try      {        SetWorkStatus(true);        //query left ticket        string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");        string from = FindCodeByChineseName(txt_userFromStation.Text.Split(',')[1]);        string to = FindCodeByChineseName(txt_userToStation.Text.Split(',')[1]);        //set data tag        OrderData odata = new OrderData()        {          station_train_code = train.value,          train_date = day,          seattype_num = "",          from_station_telecode = from,          to_station_telecode = to,          include_student = "00",          from_station_telecode_name = "始发站",          to_station_telecode_name = "目的站",          round_train_date = "",          round_start_time_str = "00:00--24:00",          single_round_type = "1",          train_pass_type = "QB",          train_class_arr = "QB#D#Z#T#K#QT#",          start_time_str = "00:00--24:00",          lishi = train.lishi,          train_start_time = train.start_time,          trainno = train.id,          arrive_time = "15:42",          from_station_name = "始发站",          to_station_name = "目的站",          ypInfoDetail = train.ypInfoDetail,        };        txt_userOrderTrainName.Text = train.value;        //station chinese name to code after output        bool result = UserOpration.Instance.QueryLeftTicket(day, ref from, ref to, train.id, ref odata);        txt_userOrderTicketLeft.Text = result ? "有" : "无";        Log.Debug("end: query left ticket, attach object data to tag.");        //update listview with property 'lishi'        var propList = train.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);        foreach (var p in propList)        {          string val = p.GetValue(train) as string;          var item = new ListViewItem(p.Name);          item.SubItems.Add(val);          lst_trainDetail.Items.Add(item);        }        this.lst_trainDetail.Tag = odata;      }      catch (Exception ex)      {        Log.Debug(ex.ToString());      }      finally      { SetWorkStatus(false); }    }    private void menu_start_Click(object sender, EventArgs e)    {      Log.Debug("start:timer enabled for search.");      Global.SeatTypeTargets = new List<JsonObject>();      foreach (var checkeditem in chk_userSeatTypes.CheckedItems)      {        JsonObject obj = null;        if (          (obj = Global.TicketCodeList.Find(j => j.value == checkeditem.ToString()))          != null)        {          Global.SeatTypeTargets.Add(obj);          continue;        }      }      if (Global.SeatTypeTargets.Count == 0)      {        MessageBox.Show("需要选择票类型", "Error");        return;      }      if (lst_trainDetail.Tag == null)      {        MessageBox.Show("需要选择一个列车, 等待加载或选择。", "Error");        return;      }      SetWorkStatus(true);      UserData user = new UserData();      //user.passenger_1_seat = tickets[0].id;      user.passenger_1_ticket = "1"; //成人      user.passenger_1_name = txt_userSeatName.Text;      user.passenger_1_cardtype = "1";//二代身份证      user.passenger_1_cardno = txt_userIdNumber.Text;      user.passenger_1_mobileno = txt_userSeatTel.Text;      this.backgroundWorker1.RunWorkerAsync(user);    }    private void menu_cancel_Click(object sender, EventArgs e)    {      Log.Debug("start:timer abort signal sent.");      if (this.backgroundWorker1.IsBusy)      {        this.backgroundWorker1.CancelAsync();      }    }    private void menu_ShowWebPage_Click(object sender, EventArgs e)    {      WebForm web = new WebForm();      web.Show();    }    void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)    {      this.Invoke(new UpdateFormControlDelegate(a =>      {        win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NOPROGRESS);        Log.Message("##运行已经停止。##");        SetWorkStatus(false);        notifyIcon1.ShowBalloonTip(3000, "12306", "运行已经停止。", ToolTipIcon.Info);      }),      "");    }    void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)    {      BackgroundWorker worker = sender as BackgroundWorker;      OrderData odata = lst_trainDetail.Tag as OrderData;      UserData user = e.Argument as UserData;      if (user == null)      {        return;      }      Log.Message("开始运行, 查询超时约{1}分钟后停止, 点击 {0} 可以立刻停止。", menu_cancel.Text, WORKER_TIMEOUT_MINUTES);      System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();      watch.Start();      bool result = false;      while (watch.Elapsed.TotalMinutes < WORKER_TIMEOUT_MINUTES)      {        if ((worker.CancellationPending == true))        {          e.Cancel = true;          break;        }        else        {          result = UserOpration.Instance.QueryLeftTicket(odata.train_date,              ref odata.from_station_telecode,              ref odata.to_station_telecode,              odata.trainno,              ref odata);          if (result)            break;          Thread.Sleep(1000);        }        int percent = (int)(100 * watch.Elapsed.TotalMinutes / WORKER_TIMEOUT_MINUTES);        percent = percent < 30 ? 30 : percent; //for virsual effort set to 30%        worker.ReportProgress(percent);      }      if (result == false)      {        Log.Error("车次信息不可用, 停止提交。 ");        return;      }      UserOpration.Instance.SubmitOrderRequest(odata, user, captchaHandle);    }    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)    {      win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NORMAL);      win7SuperIcon.SetProgress(this.Handle, (ulong)e.ProgressPercentage, 100);    }    protected override void OnClosing(CancelEventArgs e)    {      menu_cancel_Click(menu_cancel, null);      if (txt_userFromStation.Text != null)        Configurations.txt_userFromStation = txt_userFromStation.Text.ToString();      if (txt_userToStation.Text != null)        Configurations.txt_userToStation = txt_userToStation.Text.ToString();      if (txt_userTrains.Text != null)        Configurations.txt_userTrains = txt_userTrains.Text.ToString();      Properties.Settings.Default.Save();      Configurations.Save();      base.OnClosing(e);    }    #region private func    private void SetWorkStatus(bool isworking = true)    {      menu_status.Text = isworking ? "正在查询" : "Ready";      menu_start.Enabled = !isworking;      group_login.Enabled = !isworking;      group_webform.Enabled = !isworking;      menu_cancel.Enabled = isworking;    }    private void InitializeControlsFromSetting()    {      string procName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;      int pCount = System.Diagnostics.Process.GetProcessesByName(procName).Length - 1;      this.StartPosition = FormStartPosition.Manual;      this.Location = new Point(        Screen.PrimaryScreen.WorkingArea.Width - Width - 400 * pCount,        100 * pCount);      this.Icon = Icon.ExtractAssociatedIcon(Environment.ExpandEnvironmentVariables("%windir%"  @"\system32\winver.exe"));      this.notifyIcon1.Icon = this.Icon;      txt_dateTimePicker.Value = DateTime.Today.Add(new TimeSpan(ORDER_DAY_AHEAD, 0, 0, 0));      chk_userSeatTypes.Items.AddRange(Configurations.chk_userSeatTypes.Split(','));      Log.Add(new FormLog(this.txt_log));      foreach (string p in Properties.Settings.Default.webProxy)      {        ToolStripMenuItem menuItem = new ToolStripMenuItem(p);        menuItem.Click = (object sender, EventArgs e) =>        {          foreach (ToolStripMenuItem i in Proxy_toolStripMenuItem.DropDownItems)          {            i.CheckState = CheckState.Unchecked;          }          ToolStripMenuItem item = sender as ToolStripMenuItem;          item.CheckState = CheckState.Checked;          UserOpration.Instance.ProxyName = item.Text;        };        Proxy_toolStripMenuItem.DropDownItems.Add(menuItem);      }      KeyPressEventHandler submitHandler = delegate(object sender, KeyPressEventArgs e)      {        if (e.KeyChar == (char)Keys.Enter)        {          btn_login_Click(btn_login, EventArgs.Empty);          e.Handled = true;        }      };      txt_userWebName.KeyPress = submitHandler;      txt_userWebPassword.KeyPress = submitHandler;    }    private void InitializeCaptchaDelegate()    {      UpdateFormControlDelegate updateImage = new UpdateFormControlDelegate(arg =>      {        if (!cb_autoCaptcha.Checked)        {          this.BringToFront();          this.Activate();          txt_webCaptcha.Focus();        }        user_imageBox.Image = arg as Image;        lbl_userCaptchaInfo.Text = "60秒内输入验证码, 不区分大小写。";      });      UpdateFormControlDelegate clearCaptchaCode = new UpdateFormControlDelegate(arg =>      {        this.TopMost = false;        txt_webCaptcha.Text = string.Empty;        user_imageBox.Image = null;        lbl_userCaptchaInfo.Text = string.Empty;      });      UpdateFormControlDelegate updateAutoCaptcha = new UpdateFormControlDelegate(arg =>      {        txt_webCaptcha.Text = arg as string;      });      captchaHandle = (img) =>      {        if (img == null)        {          Log.Error("出现错误, 不能获取验证码。 ");          return string.Empty;        }        ImageUtil.GrayImage(ref img);        this.Invoke(updateImage, img);        if (cb_autoCaptcha.Checked)        {          tessnet2.Tesseract tessocr = new tessnet2.Tesseract();          tessocr.SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");          tessocr.Init(null, "eng", false); // To use correct tessdata          List<tessnet2.Word> result = tessocr.DoOCR(new Bitmap(img), Rectangle.Empty);          string _result = result[0].Text.Trim();          if(_result.Length<4)          {            _result = "1234";          }          this.Invoke(updateAutoCaptcha, _result);          //txt_webCaptcha.Text = result[0].Text.Trim();          Log.Error("验证码为:"  result[0].Text.Trim()  "置信度为:"  result[0].Confidence);        }        else        {          Log.Error("!!!!!!!!! 输入验证码 !!!!!!!!!!!");        }        int i = 0;        while (i  < 20)        {          Thread.Sleep(2000);          if (txt_webCaptcha.Text.Length >= 4)            break;          CheckThreadStateToAbort();        }        string ret = txt_webCaptcha.Text;        this.Invoke(clearCaptchaCode, "");        return ret;      };    }    private void InitializeBackgroundWorker()    {      this.backgroundWorker1.WorkerSupportsCancellation = true;      this.backgroundWorker1.DoWork = new DoWorkEventHandler(backgroundWorker1_DoWork);      this.backgroundWorker1.RunWorkerCompleted = new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);    }    private void CheckThreadStateToAbort()    {      if (this.IsDisposed || Thread.CurrentThread.ThreadState == ThreadState.AbortRequested)        Thread.CurrentThread.Abort();    }    private string FindCodeByChineseName(string name)    {      var rows = Global.StationNameTable.Select(string.Format("{0}='{1}'", Global.DataComlumnChineseName, name));      string code = rows[0][Global.DataComlumnCodeName] as string;      return code;    }    #endregion  }}

 
  
					
				
评论