VBAのWithステートメントにオブジェクトを指定したときの話です。
指定したオブジェクトが事前バインディングされている場合、実行時バインディングされている場合、で挙動が変わる事例があったため、備忘録として残します。
確認環境
Windows 10 Pro 64bit
Microsoft Excel 2016 64bit
サンプル
動作としては、一時ファイルを作成、TextStream
として開き、その後削除するコードです。
事前バインディングの場合
TextStream
を明示的にClose()
していませんが、End With
のステートメント実行時に参照が解放され、ファイルを削除できます。
実行にはMicrosoft Scripting Runtime
の参照設定が必要です。
'require Microsoft Scripting Runtime
Private Sub SampleEarlyBinding()
Dim fso As Scripting.FileSystemObject
Set fso = VBA.CreateObject("Scripting.FileSystemObject")
Dim tempFilePath As String
tempFilePath = fso.BuildPath(VBA.Environ$("TEMP"), fso.GetTempName())
With fso.CreateTextFile(tempFilePath)
'ファイルを開いているので削除できない
'Call fso.DeleteFile(tempFilePath, Force:=True)
End With
'事前バインディングなら削除できる
Call fso.DeleteFile(tempFilePath, Force:=True)
End Sub
実行時バインディングの場合
基本的には先ほどのコードのfso
の型宣言をObject
に変更しただけです。
このコードを実行すると、コメントアウトされていない
Call fso.DeleteFile(tempFilePath, Force:=True)
の行でエラーが発生します(ファイルへの参照を解放できていない)。
この時、このプロシージャ内で参照を解放する方法はなさそうです。
プロシージャを抜ければ問題なく削除できるようになります(参照が解放される)。
Private Sub SampleLateBinding()
Dim fso As Object 'As Scripting.FileSystemObject
Set fso = VBA.CreateObject("Scripting.FileSystemObject")
Dim tempFilePath As String
tempFilePath = fso.BuildPath(VBA.Environ$("TEMP"), fso.GetTempName())
With fso.CreateTextFile(tempFilePath)
'ファイルを開いているので削除できない
'Call fso.DeleteFile(tempFilePath, Force:=True)
End With
'遅延バインディングではエラーになる
Call fso.DeleteFile(tempFilePath, Force:=True)
'手動削除用(デバッグ時にCtrl+F9で実行行を変更可能)
Call VBA.Shell("explorer.exe /select," & tempFilePath, vbNormalFocus)
End Sub
参考:With
を使用しない場合
実行時バインディングでも、以下のように一行で記述した場合は問題なく参照を解放できます。
Call fso.CreateTextFile(tempFilePath).Write("Hello!")
Private Sub NoUseWith()
Dim fso As Object 'As Scripting.FileSystemObject
Set fso = VBA.CreateObject("Scripting.FileSystemObject")
Dim tempFilePath As String
tempFilePath = fso.BuildPath(VBA.Environ$("TEMP"), fso.GetTempName())
Call fso.CreateTextFile(tempFilePath).Write("Hello!")
Stop 'BreakPoint ファイル存在確認用
Call fso.DeleteFile(tempFilePath, Force:=True)
End Sub