質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

2回答

1720閲覧

C# 「エラー処理の記述方法」と「フォームだけは残してその他処理は終了させる方法」について

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2018/10/02 00:00

編集2018/11/19 04:20

visualstudio2017で自動ダウンロードツールを作成しています。
ここで質問をさせていただき、参考にしつつ初めて自身で作成したものです。
流れは、下記になります。
①Pingで疎通確認(YES→②に NO→①を繰り返す)
②疎通確認出来ればサイトにログイン(MyClock1-4を同時に動作)
②ログインしてからダウンロードURLを開き、ダイアログ等の処理を行う(MyClock1-4を同時に動作)
③ ①と②を指定時間ごとに繰り返し(MyClock1-4を同時に動作)
※どの処理途中でも停止ボタンを押したい(button_Click2)フォームだけは残してその他処理は終了させたい
今回
「エラー処理の記述方法」と「フォームだけは残してその他処理は終了させる方法」についてご教授お願い致します。
「フォームだけは残してその他処理は終了させる方法」について質問して、なんとなくこうすればいいんだろうなと掴めつつはありますが自分のソースに置き換えたときにどう記述すれば出来るのかを下記ソースの場合で教えていただき、そこから理解出来ればと思っています。
よろしくお願いします。

C#

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Diagnostics; 5using System.Net.NetworkInformation; 6using System.Runtime.InteropServices; 7using System.Threading; 8using System.Threading.Tasks; 9using System.Windows.Forms; 10namespace WindowsFormsApp1 11{ 12 public partial class Form1 : Form 13 { 14 //宣言文 15 [DllImport("user32.dll")] 16 static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 17 [DllImport("user32.dll")] 18 static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfeter, string lpszClass, string lpszWindow); 19 [DllImport("user32.dll")] 20 static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, String lParam); 21 [DllImport("user32.dll")] 22 static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 23 // キャンセレーショントークンソース 24 private CancellationTokenSource CancellationTokenSource; 25 public Form1() 26 { 27 InitializeComponent(); 28 button1.Enabled = true; 29 button2.Enabled = false; 30 } 31 32 public void Timers(EventHandler eventHandler)//3秒ごとに動くタイマー 33 { 34 var timer = new System.Windows.Forms.Timer(); 35 timer.Tick += new EventHandler(eventHandler); 36 timer.Interval = 1000; 37 timer.Start(); 38 } 39 public void loop(EventHandler eventHandler)//numericUpDown1 * 60秒 でループするタイマー 40 { 41 int intVal = Decimal.ToInt32(numericUpDown1.Value); 42 var timer = new System.Windows.Forms.Timer(); 43 timer.Tick += new EventHandler(eventHandler); 44 timer.Interval = intVal * 60000; 45 timer.Start(); 46 } 47 private int status; 48 private void timer_Handler(object sender, EventArgs e)//MyClockを順番に動作させる 49 { 50 switch (status) 51 { 52 case 1: 53 MyClock1(); 54 status = 2; 55 break; 56 case 2: 57 MyClock2(); 58 status = 3; 59 break; 60 case 3: 61 MyClock3(); 62 status = 4; 63 break; 64 case 4: 65 MyClock4(); 66 status = 0; 67 break; 68 default: 69 status = 1; 70 break; 71 } 72 } 73 //メインの処理 74 public void button1_Click(object sender, EventArgs e) 75 { 76 button1.Enabled = false; 77 button2.Enabled = true; 78 this.CancellationTokenSource = new CancellationTokenSource(); 79 // 処理を開始します(キャンセルトークンを渡す必要があります) 80 First_run(CancellationTokenSource.Token); 81 loop(Main_loop); 82 } 83 public async Task Ping_com(CancellationToken token) 84 { 85 await Task.Delay(1000); 86 string address = textBox0.Text; 87 System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(); 88 //結果を表示 89 while (true) 90 { 91 label1.Text = "\n通信確認中"; 92 Task.Delay(1000).Wait(); 93 label1.Refresh(); 94 Ping ins_Ping = new Ping(); 95 string host = textBox0.Text; 96 int timeout = 1000; 97 PingReply ins_PingReply = ins_Ping.Send(host, timeout); 98 if (ins_PingReply.Status == IPStatus.Success) 99 { 100 label1.Text = "\n通信成功"; 101 label1.Refresh(); 102 Task.Delay(5000).Wait(); 103 // ループ終了 104 break; 105 } 106 else 107 { 108 label1.Text = "\n通信失敗"; 109 label1.Refresh(); 110 if (token.IsCancellationRequested) 111 { 112 // キャンセル処理 113 Debug.WriteLine("comをキャンセルします..."); 114 // ループ終了 115 116 } 117 await Task.Delay(1000); 118 } 119 } 120 } 121 public async Task First_run(CancellationToken token) 122 { 123 try 124 { 125        //MyClock1-4のループ 126 Timers(timer_Handler); 127 status = 1; 128        //疎通確認 129 await Ping_com(token); 130 label1.Text = "接続中"; 131 label1.Refresh(); 132 //特定のURLに接続 133 webBrowser1.Visible = true; 134 webBrowser1.Navigate("https://"); 135 //ページの読み込み完了まで待つ 136 OpenWebWait(); 137 //1番目フレーム内のNameを取得 138 HtmlWindow iframe = webBrowser1.Document.Window.Frames[0]; 139 HtmlElementCollection elements = iframe.Document.All; 140 HtmlElement id = elements.GetElementsByName("userName")[0]; 141 HtmlElement pw = elements.GetElementsByName("pwd")[0]; 142 //ID・passを入力 143 id.InnerText = textBox1.Text; 144 pw.InnerText = textBox2.Text; 145 //Submitボタンをクリック 146 HtmlElement login = elements.GetElementsByName("Submit")[0]; 147 login.InvokeMember("click"); 148 //ダウンロードページを開く 149 webBrowser2.Visible = true; 150 webBrowser2.Navigate("https://"); 151 label1.Text = "\nダウンロード処理中"; 152 } 153 catch (Exception e) when (e is ObjectDisposedException || e is InvalidOperationException || e is System.ArgumentOutOfRangeException) 154 { 155 Task.Delay(5000).Wait(); 156 First_run(CancellationTokenSource.Token); 157 } 158 } 159 private void Main_loop(object sender, EventArgs e) 160 { 161 try 162 { 163 //特定のURLに接続 164 webBrowser1.Visible = true; 165 webBrowser1.Navigate("https://"); 166 //ページの読み込み完了まで待つ 167 OpenWebWait(); 168 //1番目フレーム内のNameを取得 169 HtmlWindow iframe = webBrowser1.Document.Window.Frames[0]; 170 HtmlElementCollection elements = iframe.Document.All; 171 HtmlElement id = elements.GetElementsByName("userName")[0]; 172 HtmlElement pw = elements.GetElementsByName("pwd")[0]; 173 //ID・passを入力 174 id.InnerText = textBox1.Text; 175 pw.InnerText = textBox2.Text; 176 //Submitボタンをクリック 177 HtmlElement login = elements.GetElementsByName("Submit")[0]; 178 login.InvokeMember("click"); 179 //ダウンロードページを開く 180 webBrowser2.Visible = true; 181 webBrowser2.Navigate("https://"); 182 } 183 catch (Exception w) when (w is ObjectDisposedException || w is InvalidOperationException || w is ArgumentOutOfRangeException) 184 { 185 Task.Delay(1000).Wait(); 186 } 187 } 188 189 void MyClock1() 190 { 191 //「セキュリティの警告」ダイアログがもしあればを承認する文 192 } 193 void MyClock2() 194 { 195 //「ファイルのダウンロード」ダイアログがもしあれば保存ボタンを押す文 196 } 197 void MyClock3() 198 { 199 //「名前をつけて保存」ダイアログがもしあればダウンロードを行う処理文 200 } 201 202 void MyClock4() 203 { 204 //「ダウンロードの完了」ダイアログがもしあればを閉じる処理文 205 } 206 private void button2_Click(object sender, EventArgs e) 207 { 208 //アプリケーションを終了させる(フォームのみ残してその他処理は終了させたい) 209 backgroundWorker1.RunWorkerAsync(); 210 } 211 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 212    { 213 Application.Exit(); 214 } 215 private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 216 { 217 Application.Exit(); 218 } 219 public bool OpenWebWait() 220 { 221 try 222 { 223 //読み込み完了まで待つ 224 while (webBrowser1.IsBusy || webBrowser1.ReadyState != WebBrowserReadyState.Complete) 225 { 226 //無処理 227 System.Windows.Forms.Application.DoEvents(); 228 System.Threading.Thread.Sleep(300); 229 } 230 return true; 231 } 232 catch (Exception ex) 233 { 234 return false; 235 } 236 } 237 } 238}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

①Pingで疎通確認(YES→②に NO→①を繰り返す)
②疎通確認出来ればサイトにログイン(MyClock1-4を同時に動作)

それより、とにかく目的の URL に WebBrowser を Navigate し、DocumentCompleted イベントの発生を待ってそのハンドラで必要な処置を行う、WebBrowser.Navigate からある一定時間内に DocumentCompleted イベントが発生しなければ次の URL に進めるというように考えてはいかがですか?

そうすれば、「エラー処理の記述方法」と「フォームだけは残してその他処理は終了させる方法」はもっと洗練されるような気がします。(コードは詳しく読んでないので気がするだけです。ハズレでしたらすみません)

とにかく、以下のようなコードは NG だと思います。ReadyState がComplete にならない場合は while は無限ループになりますが、その無限ループの中で無限に DoEvents が実行されて問題ないということは言えないと思います。ここだけは何とかすることをお勧めします。

while (webBrowser1.IsBusy || webBrowser1.ReadyState != WebBrowserReadyState.Complete) { //無処理 System.Windows.Forms.Application.DoEvents(); System.Threading.Thread.Sleep(100); }

投稿2018/10/02 03:51

編集2018/10/02 03:55
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/10/04 04:24 編集

ああああ
退会済みユーザー

退会済みユーザー

2018/10/02 06:58 編集

> https://web.biz-prog.net/fundamental/fundamental.html#wait > これであれば問題ないでしょうか。 その「これ」というのは質問文のコードと同じですよね。であれば私が上の回答で述べた通り、問題ありと思っています。 たとえ無限ループにならなくても(なったらもちろんダメですが)、例えば応答が返ってくるのに 5 秒かかったとすると(5 秒ぐらい待たされるのはちょくちょくあるはず)、50 回 DoEvents が実行されることになるはずですが、それはどう考えても問題ないとは言い切れないと思います。 ページ内で iframe などを使っている場合は DocumentCompleted イベントが複数発生するので、そのような場合は要注意ですが、それだけ気を付ければ対応できると思いますけど。
退会済みユーザー

退会済みユーザー

2018/10/02 07:00

コメント変更しましたね? 上の私のレスは行き違いになってしまいましたが、変更前の質問に対するものです。
退会済みユーザー

退会済みユーザー

2018/10/04 04:24 編集

あああ
退会済みユーザー

退会済みユーザー

2018/10/04 03:14

> タイムアウト時間を設定する方法が良いと思ったのですが、その方法がわかりません。 例えば(あくまで例えばです)、 10 秒ごとに Tick する Timer を設け、最初の URL に Navigate する際 Timer を Start させ、Tick 前に DocumentCompleted イベントが発生したらそのハンドラで Timer を Stop して必要な処置を行った後次の URL に Navigate して Timer を Start する。 Navigate 後 10 秒以内に DocumentCompleted イベントが発生しなかったら、先に Tick イベントが発生するはずなので、そのハンドラで次の URL に Navigate し Timer を再 Start する ・・・という方法が思いつきます。ただし、 > 私の場合はどのように書くのがベストでしょうか。 質問者さんのケースでベストかどうかは分かりません。そこは質問者さんの方で考えていただくことだと思います。 > 他の部分も大幅に変える必要がありそうな気もしますがどうでしょうか。 そうでしょうね。ping で疎通確認は必要なくなりますし。 でも、ping の応答は返ってこなくても、ブラウザでアクセスすると問題なく表示されるサイトが多いと思いますので、そもそも質問のやり方が適切かどうかは検討の余地があるのではないでしょうか。
退会済みユーザー

退会済みユーザー

2018/10/04 04:24 編集

あああ
退会済みユーザー

退会済みユーザー

2018/10/04 06:23

Teratail の運営にはこういう人は二度と出てこれないような仕組みを作ってもらえないだろうか・・・
len_souko

2018/10/04 13:22

退会すれば何度でもやり直せるのがね、他のサイトでもそうなんだろうけどcancatだかそんな名前のも荒らして逃亡したしね
guest

0

フォームやボタン操作などの表示ブロックと、ダウンロード動作などの実処理ブロックは分離させるようにしましょう
ダイアログ表示やらログ出力はデリゲートで登録するようにする、とかで、そのブロックを別クラスで独立させてしまいます。そうすれば、わざわざフォームだけを残す、という考え方しなくて済みます

投稿2018/10/02 00:22

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/10/04 04:24 編集

あああ
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問