Access violationに惑わされて4時間奪われた話


あらすじ

C#で外部の端末との連携開発をしていて、OCXをWindows Formに貼りつけて1、event発火処理部分のDebugしているときに、ブレークポイントに引っかからず「vshost32.exe は動作を停止しました」なんていうダイアログが出て、スタックトレースも見れない状況で困っていた。

困ったらとりあえずGoogle

仕方なくVisual Studioの出力ウィンドウを見ていたら、インジケータが出ているときにキャンセルボタンを押したとき2に、こんな1行があった。

プログラム '[3284] TestApp.vshost.exe' はコード -1073741819 (0xc0000005) 'Access violation' で終了しました。

「Access violation」?なんだコイツは…
そう思ってググる。要約すると、

保護されたメモリの読み取りまたは書き込みが試行されたときにスローされる例外。

ということらしい。
ああOCXはC++みたいなもんだし(勝手な解釈)、メモリ周りの問題あるあるwww
…と思ったが、そもそもOCXは端末作ってる会社から提供されたものだし、こっちのコードの問題の可能性が高いと思い、ググり直し。
「C# OCX Access Violation」「OCX event access violation」「windows form access violation」…のように、ひたすらググって、英文読んで(Goolge翻訳大先生を使ったが)、コード書き換えて、試行錯誤して…

…直らん。

考え方を変えて、「AccessViolationExceptionの中身が見よう」と。と言ってもこの考え方が後回しになったのは理由があって、ググってる途中に以下の記事を見つけて、この方向は無いなと自己完結してしまったから。
AccessViolationExceptionを捕捉できるようにする
要約すると、

  • .NET Framework 3.5 以前は AccessViolationException を catch できていたが、.NET Framework 4 以降ではできなくした。
  • すでにメモリアクセス違反が発生してしまったものを復旧しつつ挙動させることは極めて困難だから、中途半端になって2次災害を引き起こすよりも突然の死を選ぶ方が安全である。

まあそらそうだ、と。

結局

でもブレークポイントで止めて内容を確認するぐらいならいいだろと、「debug AccessViolationException」みたいにググった一番上…
c# - How to debug AccessViolationException coming from native code - Stack Overflow

Project + Properties, Debug tab, tick "Enable unmanaged code debugging".

ん?こんな簡単に?まあやってみるか。
「プロジェクトのプロパティ>デバッグ>ネイティブ コードのデバッグを有効にする(T)」にチェック
ビルドして動かしてみるけど、まあ無理かな…

直った。vshost32.exeが強制終了しなくなった。

えぇ…

俺の4時間3が1クリックで済むレベルだったなんて…

ここでテスト

  • ネイティブ コードのデバッグを有効にする(T)
  • Visual Studio ホスティング プロセスを有効にする(O)

→ ダメ

  • ネイティブ コードのデバッグを有効にする(T)
  • Visual Studio ホスティング プロセスを有効にする(O)

→ イケる!

  • ネイティブ コードのデバッグを有効にする(T)
  • Visual Studio ホスティング プロセスを有効にする(O)

→ イケる!!!

つまり、vshost32.exeっていう名前のVisualStudioホスティングプロセスが悪さをしていたということか。
但しどんな悪さをしていたのかまでは調べる気力が尽きました。

現在22時。

明日(土曜日)も出勤です──────

ちなみに

UserControlをクラスライブラリ、WindowsFormをWindowsアプリケーション、というように別プロジェクトで作ったんですが、変えたのはWindowsアプリケーションのほうのプロジェクトで、クラスライブラリのプロジェクトは変えてないです。

…いまどきOCX周りで困る人って少数なんじゃないかな(偏見)


  1. 正確にはOCXを貼りつけたUserControlをWindorsFormに貼りつけた。OCXを直接使う部分はUserControlにコードを書いて、WindowsFormはUserControlのインターフェースメソッドを呼び出す。 

  2. インジケータが消えてデバッグするかそのまま終了するか選べるようになって終了を押したら、「プログラム '[12488] TestApp.vshost.exe' はコード 255 (0xff) で終了しました。」が出てきた。 

  3. この記事書くのに1時間使ったので正確には5時間です。