|
分類:[C# (Windows)]
次のようなコード
// using ディレクティブ省略
namespace Application
{
class DownloadItem
{
// フィールド・プロパティ宣言省略。
/// <summary>
/// ダウンロードを開始します。
/// </summary>
/// <param name="resume">リジュームを試行する場合は true、さもなければ false。</param>
public void Start(bool resume)
{
//==============================
// 状態更新
//==============================
MyState = DownloadState.Download;
//==============================
// 初期化
//==============================
MyTotalBytes = 0;
MyRecievedBytes = 0;
MyRecieveSpeed = 0;
MyStopWatch.Reset();
CallStatusChanged();
//==============================
// リクエスト生成
//==============================
try
{
MyRequest = (HttpWebRequest)WebRequest.Create(MyUrl);
}
catch
{
MyState = DownloadState.Failure;
CallStatusChanged();
return;
}
//==============================
// リジュームフィールド追加
//==============================
if (resume)
{
FileInfo locinfo = new FileInfo(MyLocation);
if (locinfo.Exists)
{
long length = locinfo.Length;
if (length > 0)
{
MyRequest.AddRange((int)length);
string etag = GetETag();
if (etag != null)
MyRequest.Headers.Add("If-Range", etag);
}
}
}
//==============================
// 全般フィールド追加
//==============================
MyRequest.KeepAlive = false;
MyRequest.Headers.Add("Pragma", "no-cache");
MyRequest.Headers.Add("Cache-Control", "no-cache");
//==============================
// リクエスト送信
//==============================
MyRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), null);
}
private void GetResponseCallback(IAsyncResult ar)
{
MyResponse = null;
//==============================
// レスポンス取得
//==============================
try
{
MyResponse = (HttpWebResponse)MyRequest.EndGetResponse(ar);
}
catch
{
MyState = DownloadState.Failure;
CallStatusChanged();
return;
}
//==============================
// エンティティタグ保存
//==============================
string etag = MyResponse.GetResponseHeader("ETag");
if (!string.IsNullOrEmpty(etag))
SetETag(etag);
//==============================
// ストリーム取得
//==============================
MyGetStream = MyResponse.GetResponseStream();
MyOutStream = File.Open(MyLocation, FileMode.OpenOrCreate, FileAccess.Write);
//==============================
// 保存ストリームシーク処理
//==============================
long pos = 0;
if (MyResponse.StatusCode == HttpStatusCode.PartialContent)
{
string crstr = MyResponse.GetResponseHeader("Content-Range");
Match rm = Regex.Match(crstr, @"bytes\s+(?:(?<first>\d*)-(?<last>\d*)|\*)/(?:(?<len>\d+)|\*)");
if (int.TryParse(rm.Groups["first"].Value, out pos))
pos = first;
else
pos = 0;
}
MyOutStream.SetLength(pos);
MyOutStream.Position = pos;
//==============================
// 全体バイト数取得
//==============================
MyTotalBytes = MyResponse.ContentLength;
//==============================
// 受信開始
//==============================
MyBuffer = new byte[4096];
MyGetStream.BeginRead(MyBuffer, 0, MyBuffer.Length, new AsyncCallback(BeginReadCallBack), null);
MyStopWatch.Start();
}
private void BeginReadCallBack(IAsyncResult result)
{
int len = MyGetStream.EndRead(result);
//==============================
// 受信終了
//==============================
if (len == 0 || MyCancelationPending)
{
MyCancelationPending = false;
MyOutStream.Close();
MyGetStream.Close();
if (MyResponse.ContentLength > 1000000)
MyState = DownloadState.Complete;
else
MyState = DownloadState.Failure;
CallStatusChanged();
return;
}
//==============================
// 受信
//==============================
MyOutStream.Write(MyBuffer, 0, len);
//==============================
// 状態更新
//==============================
MyRecievedBytes += len;
MyRecievedParcentage = (double)MyRecievedBytes / (double)MyTotalBytes;
double ms = MyStopWatch.Elapsed.TotalSeconds;
MyRecieveSpeed = (long)((double)len / (ms - MyLastRecieved));
MyLastRecieved = ms;
CallStatusChanged();
}
/// <summary>
/// 保存されているエンティティタグからこのダウンロードに一致するものを取得します。
/// </summary>
/// <returns>一致したエンティティタグ、または null。</returns>
private string GetETag() //省略
/// <summary>
/// 受信したエンティティタグを保存します。
/// </summary>
/// <param name="etag">エンティティタグ</param>
/// <returns>エンティティタグが上書きされた場合は true、新規登録された場合は false。</returns>
private bool SetETag(string etag) //省略
/// <summary>
/// ダウンロードを停止します。
/// このメソッドの実行には数秒かかることがあります。
/// </summary>
/// <returns>現在ダウンロードが実行されていなければ true、さもなければ false。</returns>
public bool Cancel()
{
if (MyState == DownloadState.Download)
{
if (MessageBox.Show(string.Format("{0} のダウンロードを停止しますか?", Title), "中断確認", MessageBoxButtons.YesNo) == DialogResult.No)
return false;
MyCancelationPending = true;
while (MyState == DownloadState.Download) ;
}
CallStatusChanged();
return true;
}
public bool StandBy()
{
if (Cancel())
{
MyState = DownloadState.StandBy;
CallStatusChanged();
}
}
public bool Suspend()
{
if (Cancel())
{
MyState = DownloadState.Suspend;
CallStatusChanged();
}
}
// 以下省略
}
}
のCancel()メソッドが怖いのですが、安全かつ確実に処理を停止させるにはマルチスレッドで実行したほうがよいのでしょうか?
どなたかご教授願います。
|