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
