ExcelVBAからOutlookやWordなど他のアプリケーションを操作するとき、CreateObjectをそのまま使うと、実行するたびにアプリが新しく起動し、タスクマネージャーにプロセスが何個も残ってしまうことがあります。これはCreateObjectとGetObjectの違いを理解せずに使ってしまうことが原因の一つです。
この記事では、CreateObjectとGetObjectそれぞれの役割の違いと、すでに起動しているアプリケーションを取得して多重起動を防ぐ具体的なコードを解説します。
CreateObjectとGetObjectの基本的な違い
まず、それぞれの役割を整理します。
- CreateObject:指定したアプリケーションの「新しいインスタンス」を必ず作成する
- GetObject:すでに起動している「既存のインスタンス」を取得する(または、指定したファイルを開いて取得する)
たとえばCreateObject("Outlook.Application")を実行すると、すでにOutlookが開いていても、裏でもう1つOutlookのプロセスが起動することがあります。一方GetObject(, "Outlook.Application")は、起動中のOutlookをそのままつかまえて操作できます。
GetObjectで起動中のアプリを取得する
GetObjectの第1引数を省略し、第2引数にProgIDを指定すると、「すでに起動しているインスタンス」を取得できます。ただし、アプリが1つも起動していない場合は実行時エラー429が発生するため、On Errorで対処する必要があります。
Sub Outlookを取得または起動する()
Dim objOutlook As Object
On Error Resume Next
Set objOutlook = GetObject(, "Outlook.Application")
On Error GoTo 0
If objOutlook Is Nothing Then
' 起動していなければ新規作成
Set objOutlook = CreateObject("Outlook.Application")
MsgBox "Outlookを新規に起動しました。"
Else
MsgBox "起動中のOutlookを取得しました。"
End If
Dim objMail As Object
Set objMail = objOutlook.CreateItem(0) ' 0 = olMailItem
objMail.Subject = "テストメール"
objMail.Display
End Sub
このように「まずGetObjectで既存のインスタンスを探し、見つからなければCreateObjectで新規作成する」という組み合わせが、多重起動を防ぐ定番パターンです。
GetObjectでファイルを開いて取得する
GetObjectにはもう一つの使い方があります。第1引数にファイルパスを指定すると、そのファイルを開いた状態のアプリケーションオブジェクトを取得できます。
Sub 既存のExcelファイルを取得する()
Dim objExcel As Object
Dim filePath As String
filePath = "C:\work\集計表.xlsx"
On Error Resume Next
Set objExcel = GetObject(filePath)
On Error GoTo 0
If objExcel Is Nothing Then
MsgBox "ファイルを開けませんでした。パスを確認してください。"
Exit Sub
End If
MsgBox objExcel.Name & " を取得しました。シート数: " & objExcel.Worksheets.Count
' このブックを閉じずに残す場合は Application オブジェクトを別途取得する
objExcel.Application.Visible = True
End Sub
GetObject(filePath)で取得できるのは「ブック(Workbook相当)」のオブジェクトです。すでにそのファイルが開かれていれば開いている状態を、開かれていなければファイルを新たに開いた状態のオブジェクトを返します。アプリ本体を操作したい場合は、objExcel.ApplicationでExcelアプリケーション自体を取得できます。
CreateObjectで新規作成したインスタンスは必ず終了処理をする
CreateObjectで新規に作成したインスタンスは、処理が終わったら明示的に終了させないと、バックグラウンドにプロセスが残り続けます。特にOutlookのようにウィンドウを表示しない操作をした場合、タスクマネージャーで確認しないと残っていることに気づきにくいので注意が必要です。
Sub Excelを新規作成して確実に終了する()
Dim objExcel As Object
Dim objBook As Object
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
Set objBook = objExcel.Workbooks.Open("C:\work\集計表.xlsx")
' 何らかの処理
Debug.Print objBook.Worksheets(1).Range("A1").Value
objBook.Close SaveChanges:=False
objExcel.Quit
Set objBook = Nothing
Set objExcel = Nothing
End Sub
一方、GetObjectで取得した既存のインスタンスは、他の人(または自分自身)がすでに使っているものです。処理の最後にQuitしてしまうと、相手が作業中のアプリごと閉じてしまうため、GetObjectで取得したオブジェクトに対してはQuitを呼ばないのが原則です。
まとめ
CreateObjectとGetObjectは似ているようで役割が異なり、使い分けを誤るとアプリの多重起動やプロセス残留につながります。
CreateObject:常に新しいインスタンスを作成する。使い終わったらQuitで必ず終了させるGetObject(, ProgID):起動中のインスタンスを取得する。見つからなければエラー429になるためOn Errorで対処するGetObject(ファイルパス):指定したファイルを開いた状態のオブジェクトを取得するGetObjectで取得したインスタンスは、他の用途で使われている可能性があるためQuitしない
「起動中のものを使うか、新しく作るか」を意識してコードを書くことで、Outlookやその他アプリの多重起動によるトラブルを防げます。


コメント