Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices

''' <summary>
''' 汎用的に使用されるライブラリです。
''' </summary>
''' <remarks></remarks>
Public MustInherit Class BaseLib
#Region "メソッド定義"
    ''' <summary>
    ''' 三項演算子のように、式の評価結果によって、2つのオブジェクトのうち1つを返します。
    ''' </summary>
    ''' <typeparam name="T">この関数の評価結果として返すオブジェクトの型を指定します。</typeparam>
    ''' <param name="Expression">評価する式をブール型で指定します。</param>
    ''' <param name="TruePart">ExpressionがTrueに評価された場合に返すオブジェクトを指定します。</param>
    ''' <param name="FalsePart">ExpressionがFalseに評価された場合に返すオブジェクトを指定します。</param>
    ''' <returns>ExpressionがTrueに評価された場合はTruePartを返します。それ以外の場合はFalsePartを返します。</returns>
    ''' <remarks>ExpressionがTrueに評価された場合はFalsePartを、Falseに評価された場合はTruePartを評価しません。</remarks>
    Public Shared Function Ternary(Of T)(ByVal Expression As Boolean, ByRef TruePart As T, ByRef FalsePart As T) As T
        If (Expression) Then
            Return TruePart
        End If
        Return FalsePart
    End Function

    ''' <summary>
    ''' 例外をトラップします。
    ''' </summary>
    ''' <param name="ex">トラップする例外を指定します。</param>
    ''' <remarks>この関数を呼び出したメソッドのデバッグログ用文字列が自動的に取得されます。</remarks>
    Public Overloads Shared Sub ExceptionCatch(ByVal ex As Exception)
        ExceptionCatch(ex, GetDebugLogString(3))
    End Sub

    ''' <summary>
    ''' 例外をトラップします。
    ''' </summary>
    ''' <param name="ex">トラップする例外を指定します。</param>
    ''' <param name="Explain">例外に対する説明の文字列を指定します。</param>
    ''' <remarks>Debugビルドのとき、ex.MessageとExplainを、Debug.WriteLineおよびMessageBox.Showを使用して通知します。
    ''' <para>
    ''' exにExecutionEngineException、StackOverflowException、OutOfMemoryExceptionのいずれかが指定されたとき、受け取った例外をそのままスローします。
    ''' exにThreadAbortExceptionが指定されたとき、既定の動作により例外が再度スローされます。</para></remarks>
    Public Overloads Shared Sub ExceptionCatch(ByVal ex As Exception, ByVal Explain As String)
#If DEBUG Then
        Dim Expression As String = "例外 " & ex.GetType().ToString() & " が発生しました。" & vbCrLf & ex.Message
        Debug.WriteLine(Explain & " > " & Expression)
        MessageBox.Show(Expression, Explain)
#End If
        If ((TypeOf ex Is ExecutionEngineException) OrElse _
            (TypeOf ex Is StackOverflowException) OrElse _
            (TypeOf ex Is OutOfMemoryException)) Then
            Throw ex
        End If
    End Sub

    ''' <summary>
    ''' デバッグログ用文字列を取得します。
    ''' </summary>
    ''' <returns>生成したデバッグログ用の文字列を返します。</returns>
    ''' <remarks></remarks>
    Public Overloads Shared Function GetDebugLogString() As String
        Return GetDebugLogString(2)
    End Function

    ''' <summary>
    ''' デバッグログ用文字列を取得します。
    ''' </summary>
    ''' <param name="Explain">追加の説明の文字列を指定します。</param>
    ''' <returns>生成したデバッグログ用の文字列を返します。</returns>
    ''' <remarks></remarks>
    Public Overloads Shared Function GetDebugLogString(ByVal Explain As String) As String
        Return GetDebugLogString(2, Explain)
    End Function

    ''' <summary>
    ''' デバッグログ用文字列を取得します。
    ''' </summary>
    ''' <param name="FramePosition">デバッグログ用文字列を取得するスタックフレームの位置を指定します。この関数を呼び出す関数を2とし、それらを呼び出した関数をさかのぼるごとに1ずつ増やした値を使用します。</param>
    ''' <returns>生成したデバッグログ用の文字列を返します。</returns>
    ''' <remarks></remarks>
    Public Overloads Shared Function GetDebugLogString(ByVal FramePosition As Integer) As String
        Return GetDebugLogString(FramePosition, Nothing)
    End Function

    ''' <summary>
    ''' デバッグログ用文字列を取得します。
    ''' </summary>
    ''' <param name="FramePosition">デバッグログ用文字列を取得するスタックフレームの位置を指定します。この関数を呼び出す関数を1とし、それらを呼び出した関数をさかのぼるごとに1ずつ増やした値を使用します。</param>
    ''' <param name="Explain">追加の説明の文字列を指定します。</param>
    ''' <returns>生成したデバッグログ用の文字列を返します。</returns>
    ''' <remarks>生成される文字列は、この関数を実行した時刻、指定したスタックフレーム位置の関数の名前および引数、Explainに指定した文字列を連結したものです。</remarks>
    Public Overloads Shared Function GetDebugLogString(ByVal FramePosition As Integer, ByVal Explain As String) As String
        Dim st As New StackTrace
        Dim sf As StackFrame = st.GetFrame(FramePosition)
        Dim mb As Reflection.MethodBase = sf.GetMethod()
        Dim ClassName As String
        Dim MethodName As New System.Text.StringBuilder()

        ClassName = mb.DeclaringType.ToString()
        MethodName.Append(mb.Name & "(")
        Dim pi As Reflection.ParameterInfo
        For i As Integer = 0 To mb.GetParameters().Length - 1
            pi = mb.GetParameters(i)
            If (i <> 0) Then MethodName.Append(", ")
            MethodName.Append(pi.ParameterType.ToString() & " " & pi.Name)
        Next
        MethodName.Append(")")
        Return Format(Now, "yyyy/MM/dd_HH:mm:ss.fff") & vbTab & ClassName & "." & MethodName.ToString() & _
            Ternary(Of String)(Explain IsNot Nothing, Explain, Nothing)
    End Function

#Region "ファイルバージョン取得"
    <DllImport("kernel32.dll", CharSet:=CharSet.Ansi, exactspelling:=True)> _
    Private Shared Function LoadLibraryA(ByVal lpFileName As String) As IntPtr
    End Function
    <DllImport("kernel32.dll", CharSet:=CharSet.Ansi, exactspelling:=True)> _
    Private Shared Function FreeLibrary(ByVal hModule As IntPtr) As Integer
    End Function
    <DllImport("kernel32.dll", CharSet:=CharSet.Ansi, exactspelling:=True)> _
    Private Shared Function GetModuleFileNameA( _
        ByVal hModule As IntPtr, _
        ByVal lpFileName As System.Text.StringBuilder, _
        ByVal nSize As Integer) As Integer
    End Function

    ''' <summary>
    ''' ファイルのバージョン情報を取得します。
    ''' </summary>
    ''' <returns>ファイルのバージョン情報を格納したFileVersionInfoを返します。</returns>
    ''' <remarks></remarks>
    Public Shared Function GetFileVersion(ByVal FileName As String) As FileVersionInfo
        Dim hModule As IntPtr
        Dim DllFilePath As New System.Text.StringBuilder(255)
        Dim Length As Integer
        Try
            hModule = LoadLibraryA(FileName)
            Length = GetModuleFileNameA(hModule, DllFilePath, DllFilePath.Capacity)
        Catch ex As Exception
            BaseLib.ExceptionCatch(ex)
        Finally
            FreeLibrary(hModule)
        End Try

        Return FileVersionInfo.GetVersionInfo(DllFilePath.ToString)
    End Function
#End Region '"ファイルバージョン取得"
#End Region '"メソッド定義"

End Class
