【ExcelVBA・マクロ】GetObjectとCreateObjectの違い|Outlook・Excelの多重起動を防ぐ方法【コピペOK】

ExcelVBA

ExcelVBAからOutlookやWordなど他のアプリケーションを操作するとき、CreateObjectをそのまま使うと、実行するたびにアプリが新しく起動し、タスクマネージャーにプロセスが何個も残ってしまうことがあります。これはCreateObjectGetObjectの違いを理解せずに使ってしまうことが原因の一つです。

この記事では、CreateObjectGetObjectそれぞれの役割の違いと、すでに起動しているアプリケーションを取得して多重起動を防ぐ具体的なコードを解説します。

スポンサーリンク
スポンサーリンク

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を呼ばないのが原則です。

まとめ

CreateObjectGetObjectは似ているようで役割が異なり、使い分けを誤るとアプリの多重起動やプロセス残留につながります。

  • CreateObject:常に新しいインスタンスを作成する。使い終わったらQuitで必ず終了させる
  • GetObject(, ProgID):起動中のインスタンスを取得する。見つからなければエラー429になるためOn Errorで対処する
  • GetObject(ファイルパス):指定したファイルを開いた状態のオブジェクトを取得する
  • GetObjectで取得したインスタンスは、他の用途で使われている可能性があるためQuitしない

「起動中のものを使うか、新しく作るか」を意識してコードを書くことで、Outlookやその他アプリの多重起動によるトラブルを防げます。

スポンサーリンク
スポンサーリンク
ExcelVBA
シェアする
いがぴをフォローする

コメント

タイトルとURLをコピーしました