ちりぬるお本舗制作日誌

同人ゲーム・同人コミックその他制作サークル「ちりぬるお本舗」の主催でありプリキュアヲタクの奇々浦ヌル夫がゲーム、ドット絵、その他色々な物を作るブログです

キュアジャン開発記録-非同期処理がうまく実装できない件-【解決済】

キュアジャンの事を書き始めて2記事目ですが、早くもコーディングで行き詰りました…読者の皆さん、知恵をお貸しください…

 

やりたいこと:オンラインアップデート機能の実現

ゲーム起動時にサーバに接続し、最新バージョンがリリースされていれば最新バージョンの実行ファイル(および付随して必要となる設定ファイルやdll等)をダウンロードしてきてローカルのファイルを上書きし、ゲームを起動する。

この機能さえ実現しておけば、最初のリリース時点では盛り込めなかった機能も、後から追加でリリースしていく事が可能です。だから、他の機能は後回しでもいいから、このオンラインアップデート機能だけはなんとしても実装しておきたいのです。

 

※正確には、オンラインアップデータとゲームアプリケーション本体を別exeファイルに分割し、下記のような流れで実現する予定です。

  1. ユーザーがオンラインアップデータを起動
  2. オンラインアップデータは最新バージョンの有無をサーバに問合せする
  3. 最新バージョンが存在した場合、ダウンロードする
  4. オンラインアップデータはゲームアプリケーション本体を起動して、自身は終了する。

※ こういう構成にしたため、オンラインアップデート機能以外は最悪、バグっていてもアップデートで後から修正可能なのですが、オンラインアップデート機能自体はバージョンアップできないので、この機能だけは着実に堅牢に構築してリリースしておかないといけないという事になります。

試したこと

CodeZineで「VB.NETによるオンラインアップデート」というそのものズバリな記事を見つけたのでこちらのサンプルコードを参考に、自分のアプリに組み込みました。

codezine.jpテストすると、ちゃんとオンラインアップデート機能が実現できていたのですが、その後で1つ問題点が浮上しました。

上記記事は会員登録が必要なので、簡単にサンプルコードの内容を説明しておくと、サーバにアクセスしてアップデートの有無の確認や、最新バージョンファイルのダウンロードをする間にUIスレッドが応答不能になるのを防ぐために「Forms.Application.DoEvents」を使っていました。しかし、調べたらDoEvents関数でメインスレッドを中断してWindowメッセージを処理するのは現在では非推奨の方法らしいです。

 

.NET系のエンジニアにどうしたらいいでしょう?と聞くと「最新の.NET FrameworkならAsync/Awaitが使えるから、それ使ってマルチスレッド処理を実現するのが最近の主流ですし、書くの楽だよ」と複数の方からアドバイスいただけました。

Async および Await を使用した非同期プログラミング (C# および Visual Basic)

 

そこで、上記のDoEventsを使用するバージョンのコードを、AsyncとAwaitを使った形に書き直したのですが、「最新バージョンがあるかどうかチェックする」確認まではちゃんと非同期的処理が実現できていましたが、「最新バージョンをダウンロードしてくる」処理の実行中にTargetInvocationExceptionが発生してしまいました。

f:id:nulluo:20180924200339p:plain

 

今のソースコードはこんな感じです。(GitHubのページへ飛びます)

1) ダウンロード処理本体のクラス

https://github.com/nulluo/ChiriNulluo.Mahjong/blob/master/OnlineUpdaterTest/DownLoader.vb

2) 1)を非同期的に呼び出ししているFormクラス

https://github.com/nulluo/ChiriNulluo.Mahjong/blob/master/OnlineUpdaterTest/View/DownloadNewVersionForm%20.vb

 

最新のソースコードから、オンラインアップデート機能に関するところだけ抜き出したものをReleaseに置きましたので手元の環境で動作確認される方は下記のページから「OnlineUpdaterTest-Ver-0.1.1.25.zip」クリックしてダウンロードしてお使いください。(スタートアッププロジェクトはOnlineUpdaterTestです)

 

github.com

 質問内容

.NETで、ファイルのダウンロード処理をAsync/Await使って書く場合、どういう形で書くべきなんでしょうか?有識者の方のご意見お待ちしています。

 

不足している情報などありましたらコメント欄にお寄せください。