3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(.Net)SQL Server でバックアップ時(復元時)の進行状況を取得しプログレスバーに表示する(ソース編)

(.Net)SQL Server でバックアップ時(復元時)の進行状況を取得しプログレスバーに表示する(説明編)の続きとういより、文字数オーバーで載せれなかったコードです。

(なお、プログレスバーを貼り付けているフォームクラスのコードは面倒なので掲載してません。

クラス名は Progress で、プログレスバーコントロール名は ProgressBar です。)

Public Class TestBackup

 

'''

''' SQL Server のバックアップを行う(バックアップファイル名は日時.bak)

''' エラー時、成功時ともに、イベントビュアーにログを残す

'''

''' True:正常 False:異常

Public Function BackupNow() As Boolean

'コネクションオブジェクト作成

Dim conn As SqlConnection = Me.GetDbConnection()

'プログレスバー表示クラス生成

prg = New ProgressBarControl()

 

Try

conn.Open()

'コマンドオブジェクト生成

Dim cmd As New SqlCommand()

cmd.Connection = conn

'STATS = 1 なので1秒おきに進捗率を通知

cmd.CommandText = "BACKUP DATABASE [testdatabase] TO DISK = N'C:\test.bak' WITH NOFORMAT, INIT, NAME = N'テスト', SKIP, NOREWIND, NOUNLOAD, STATS = 1"

'復元時だとこういうコードになります。

'cmd.CommandText = "RESTORE DATABASE [testdatabase] FROM DISK = N'C:\test.bak' WITH FILE = 1, NOUNLOAD, REPLACE , STATS = 1"

'これをTrueしないとInfoMessageがまとめて発行されてしまう(ただし、TrueにするとSQLクエリ実行中に例外発生してもスローしないので注意!)

conn.FireInfoMessageEventOnUserErrors = True

'進捗情報取得のためのイベントハンドラを追加

AddHandler conn.InfoMessage, New SqlInfoMessageEventHandler(AddressOf SqlConnect_InfoMassage)

'プログレスバー表示(別スレッド)

prg.Show()

'バックアップクエリ実行

cmd.ExecuteNonQuery()

Catch ex As Exception

'エラー処理のコードがここに入る(ログに残すとかメッセージボックスとか)

Return False

Finally

conn.Close()

If prg IsNot Nothing Then

'プログレスバー表示用別スレッドを停止。プレブレスバー表示フォームを閉じる。

prg.Close()

End If

End Try

Return True

End Function

 

 

'''

''' 進行状況ダイアログのプログレスバーに進捗を表示する。

''' SqlConnection.InfoMessageのイベントハンドラ

'''

Private Sub SqlConnect_InfoMassage(ByVal sender As Object, ByVal e As System.Data.SqlClient.SqlInfoMessageEventArgs)

Dim conn As SqlConnection = DirectCast(sender, SqlConnection)

For Each sqlErr As SqlError In e.Errors

'エラーの重要度が10より大きいなら例外発生させ処理停止

If sqlErr.Class > 10 Then

'Falseにすることで、次回より例外がスローされるようになる

conn.FireInfoMessageEventOnUserErrors = False

'エラーを ApplicationExceptionとして例外生成(しかし、この例外はスローされないっぽい。この次の例外からスローされる)

Dim ex As New ApplicationException(sqlErr.ToString())

'この下のThrowでは実際にはThrowされないようなので、ここでイベントビュアーにエラー出力

'エラー処理のコードがここに入る(ログに残すとかメッセージボックスとか)

Throw ex

End If

Next

'メッセージを分解し、intに変換

Dim idx As Integer = e.Message.LastIndexOf(" パーセント処理されました。")

If idx < 1 Then

Return

End If

'パーセント

Dim intPer As Integer

Try

intPer = CType(e.Message.Substring(0, idx), Integer)

Catch ex As Exception

Return

End Try

'プログレスバー表示更新

If prg IsNot Nothing Then

prg.ValuePercent = intPer

End If

End Sub

End Class

 

 

'''

''' プログレスバーフォームを別スレッドで表示さすためのラッパクラス

'''

Public Class ProgressBarControl

 

'進行状況表示クラス(このクラスのコードは省略。ただフォームにプログレスバーを乗せてるだけ)

Private m_statusForm As Progress

'現在のプログレスバーの値

Private m_ValuePercent As Integer

 

'''

''' プログレスバーの値を設定、取得するプロパティ

'''

Public Property ValuePercent() As Integer

Get

Return m_ValuePercent

End Get

Set(ByVal value As Integer)

m_ValuePercent = value

If m_statusForm IsNot Nothing Then

'm_statusFormのインスタンスを持っているスレッドで、SetProgressValuePercentメソッドを処理させる

m_statusForm.Invoke(New MethodInvoker(AddressOf SetProgressValuePercent))

End If

End Set

End Property

 

'''

''' プログレスバーを閉じる。(と同時にプログレスバー表示スレッドも自然と消える)

'''

Public Sub Close()

If m_statusForm IsNot Nothing Then

'm_statusFormのインスタンスを持っているスレッドで、ProgressCloseメソッドを処理させる

m_statusForm.Invoke(New MethodInvoker(AddressOf ProgressClose))

End If

End Sub

 

 

'''

''' プログレスバーを表示する。プログレスバー表示クラスを別スレッドで作成し、表示。

'''

Public Sub Show()

Dim thread As Threading.Thread = New Threading.Thread(AddressOf Run)

thread.Start()

End Sub

 

'''

''' 別スレッドで動くメソッド。プログレスバー表示クラスのインスタンスを作成し、ShowDialog する。

'''

Private Sub Run()

m_statusForm = New Progress()

m_statusForm.ShowDialog()

m_statusForm.Dispose()

End Sub

 

 

'''

''' プログレスバーの値を更新する(MethodInvoker デリゲートから呼ばれる)

'''

Private Sub SetProgressValuePercent()

m_statusForm.ProgressBar.Value = m_ValuePercent

End Sub

 

'''

''' プログレスバーを閉じる(MethodInvoker デリゲートから呼ばれる)

'''

Private Sub ProgressClose()

m_statusForm.Close()

End Sub

 

End Class