C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

集約例外メソッドでラッピングした例外を取得できない /卵 (19/03/13(Wed) 20:39) #90478
Re[1]: 集約例外メソッドでラッピングした例外を取得できない /Azulean (19/03/13(Wed) 23:29) #90479
  └ Re[2]: 集約例外メソッドでラッピングした例外を取得できない /卵 (19/03/14(Thu) 09:32) #90483
    └ Re[3]: 集約例外メソッドでラッピングした例外を取得できない /Hongliang (19/03/14(Thu) 11:30) #90486
      └ Re[4]: 集約例外メソッドでラッピングした例外を取得できない /卵 (19/03/14(Thu) 21:05) #90494
        └ Re[5]: 集約例外メソッドでラッピングした例外を取得できない /Hongliang (19/03/14(Thu) 21:20) #90495


親記事 / ▼[ 90479 ]
■90478 / 親階層)  集約例外メソッドでラッピングした例外を取得できない
□投稿者/ 卵 (1回)-(2019/03/13(Wed) 20:39:58)

分類:[.NET 全般] 

Visual Basic2012を使用しています。
集約例外ハンドラを使っているのですが、思うように例外を受け取れていません。
ログファイルをオープンする際に例外が発生した場合に、ログ出力をしたくないので
下記のようにコードを書きました。

メインクラス
<STAThread> _
Public Shared Sub Main()
    AddHandler Application.ThreadException, _
        AddressOf Application_ThreadException

    Application.Run(New Form1())
End Sub

Private Shared Sub Application_ThreadException(sender As Object, _
        e As System.Threading.ThreadExceptionEventArgs)

        If TypeOf e.Exception Is Log_Exception Then   @
             'メッセージ表示のみ
        Else
             'メッセージ表示してログ出力
        End If
    
        'アプリケーション終了
        Application.Exit()
    
End Sub

ログ例外クラス
Public Class Log_Exception
        Inherits Exception
        'これの他、メッセージのみ、引数なしのコンストラクタを定義しています
        Public Sub New(ByVal errorMessage As String,ByVal _InnerException as  Exception)
                MyBase.New(errorMessage,_InnerException)
        End Sub
End Class

ログ出力クラス
Public sub Write_Log(ByVal _Log As String)
        Dim stream As IO.StreamWriter = Get_Stream
        stream.WriteLine(_Log)
End sub

Private Function Get_Stream() As IO.StreamWriter
         Try
                Return New IO.StreamWriter("ログファイルパス",True,System.Text.Encoding.GetEncoding("shift_jis"))
         Catch ex As IOException 
                 Throw New Log_Exception("ログファイルオープン時エラー発生",ex)    A
         End Try
End Function



ログファイルを別のアプリケーションで開いたままにすると
一応Aの後に@には来るんですけど、中を見るとIOExceptionになっているため、
If判定しても意味がないという状態になっています。
もうAでメッセージを出してアプリケーション終了させようかなと思ったのですが、
何故上手くいかないのかが気になって仕方ないです。
ちなみにメッセージのみ、または引数なしでLog_Exceptionを生成すると、何故かうまくいきます。
InnerExceptionがあるときだけ、おかしくなります。
AのLog_ExceptionをExceptionクラスに変えて試しましたが、
やはりInnerExceptionがあると@の時点でe.ExceptionがIOExceptionになっています。

[ □ Tree ] 返信 編集キー/

▲[ 90478 ] / ▼[ 90483 ]
■90479 / 1階層)  Re[1]: 集約例外メソッドでラッピングした例外を取得できない
□投稿者/ Azulean (1042回)-(2019/03/13(Wed) 23:29:54)
2019/03/13(Wed) 23:33:58 編集(投稿者)

Write_Log はどうやって呼び出していますか?
たとえば、Control.Invoke の先で呼び出されている場合、Control.Invoke の内部実装の都合により、Invoke の利用者には一番内側の InnerException が取り出されて通知されるという動きになります。

(参考)
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,7474
https://referencesource.microsoft.com/#mscorlib/system/exception.cs,afeecbe8989570cf
[ 親 90478 / □ Tree ] 返信 編集キー/

▲[ 90479 ] / ▼[ 90486 ]
■90483 / 2階層)  Re[2]: 集約例外メソッドでラッピングした例外を取得できない
□投稿者/ 卵 (2回)-(2019/03/14(Thu) 09:32:49)
No90479 (Azulean さん) に返信
> 2019/03/13(Wed) 23:33:58 編集(投稿者)
>
> Write_Log はどうやって呼び出していますか?
> たとえば、 Control.Invokeの先で呼び出されている場合、Control.Invoke の内部実装の都合により、Invoke の利用者には一番内側の InnerException が取り出されて通知されるという動きになります。
>
> (参考)
> https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,7474
> https://referencesource.microsoft.com/#mscorlib/system/exception.cs,afeecbe8989570cf

レスありがとうございます。

Write_LogはForm1の複数のメソッドから呼び出しています。
Invokeはどこにも使っていないですね。
マルチスレッドにもなっていないと思います。
明示的にそうしていなくても自動的にマルチスレッドになったりするのであれば、確認してみないとわかりませんが。
[ 親 90478 / □ Tree ] 返信 編集キー/

▲[ 90483 ] / ▼[ 90494 ]
■90486 / 3階層)  Re[3]: 集約例外メソッドでラッピングした例外を取得できない
□投稿者/ Hongliang (767回)-(2019/03/14(Thu) 11:30:12)
現在公開されている情報からは、
単純なコードから徐々に元のコードに復元していって、
何が原因かを探るという手法を提案できるぐらいですね。

とりあえず以下のもっとも単純な形では問題なくLogExceptionが表示されました。
(Windows 10 ver.1809, 対象フレームワーク:.NET 4.5.2および.NET 3.5)

1. 新しくWindows Formsのプロジェクトを作成する
2. Programという名前でモジュールを追加して、後述のコードを記述
3. Form1にボタンを1つ配置し、後述のコードを記述
4. プロジェクトのプロパティでアプリケーションフレームワーク有効のチェックを外し
 スタートアップオブジェクトをProgramに変更

ちなみにアプリケーションフレームワーク有効のまま、
ThreadExceptionへのAddHandlerをForm1_Loadに移動させても
問題ありませんでした。


Program.vb ------------------------------
Imports System.IO
Imports System.Text
Imports System.Threading

Module Program
    <STAThread>
    Public Sub Main()
        AddHandler Application.ThreadException, AddressOf Application_ThreadException
        Application.Run(New Form1())
    End Sub

    Public Sub Application_ThreadException(sender As Object, e As ThreadExceptionEventArgs)

        If TypeOf e.Exception Is Log_Exception Then
            MessageBox.Show("LogException")
        Else
            MessageBox.Show(e.Exception.ToString())
        End If
        Application.Exit()
    End Sub
End Module
Public Class Log_Exception
    Inherits Exception
    Public Sub New(ByVal errorMessage As String, ByVal _InnerException As Exception)
        MyBase.New(errorMessage, _InnerException)
    End Sub
End Class
Public Class Log
    Public Sub Write_Log(ByVal _Log As String)
        Using writer As StreamWriter = Get_Stream()
            writer.WriteLine(_Log)
        End Using
    End Sub
    Public Const LogPath As String = "F:\OCR\Documents\log.txt"
    Private Function Get_Stream() As StreamWriter
        Try
            Return New StreamWriter(LogPath, True, Encoding.GetEncoding("shift_jis"))
        Catch ex As IOException
            Throw New Log_Exception("ログファイルオープン時エラー発生", ex)
        End Try
    End Function
End Class

Form1.vb --------------------------------
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Using writer As New IO.StreamWriter(Log.LogPath)
            Dim log As New Log
            log.Write_Log("test")
        End Using
    End Sub
End Class

[ 親 90478 / □ Tree ] 返信 編集キー/

▲[ 90486 ] / ▼[ 90495 ]
■90494 / 4階層)  Re[4]: 集約例外メソッドでラッピングした例外を取得できない
□投稿者/ 卵 (3回)-(2019/03/14(Thu) 21:05:20)
Hongliangさん、レスありがとうございます。

一つ一つ調べてみたら、どうにもForm1.Shown内でWrite_Log実行した時だけ現象が発生するようです。
原因はわかりませんが…。
[ 親 90478 / □ Tree ] 返信 編集キー/

▲[ 90494 ] / 返信無し
■90495 / 5階層)  Re[5]: 集約例外メソッドでラッピングした例外を取得できない
□投稿者/ Hongliang (768回)-(2019/03/14(Thu) 21:20:52)
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Form.cs,c7c01bc2d87e3803
このOnLoadの最後のところからShownイベントが呼び出されるわけですが、まさにBeginInvokeしてますね。
[ 親 90478 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -