🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の CreateObject — 遅延バインディング、GetObject、そして Outlook が開いたままになる理由

|

Excel VBA の CreateObject — 遅延バインディング、GetObject、そして Outlook が開いたままになる理由

TL;DRCreateObject("ProgID") は、名前で任意の COM アプリを起動します — Scripting.FileSystemObjectOutlook.ApplicationWScript.Shell。オブジェクトが文字列で 名指しされるため、コンパイラはそれを検査できません。間違った ProgID は実行時に error 429 で 失敗します。CreateObject はつねに新しいインスタンスを起動し(実行中のものにつなぐには GetObject)、起動したものは何であれ解放しなければなりません — アプリを .Quit し、 Set obj = Nothing する — さもないとヘッドレスなプロセスが動いたまま残ります。

Sub CreateObjectDemo()
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")   ' 遅延バインディング:文字列で名指し
    Debug.Print fso.FileExists("C:\data.txt")

    Set fso = Nothing                                      ' 作ったものを解放する
End Sub

CreateObject は、VBA を Excel の言語から Windows 自動化の言語へと変える動詞です。ProgID — COM コンポーネントの登録名 — を渡せば、そのコンポーネントを起動し、あなたが操れるオブジェクトを 手渡します。Scripting.FileSystemObject でファイルを読む、Outlook.Application でメールを送る、 WScript.Shell でコマンドを実行する。これは言語の中で最も強力な、Excel の外へ手を伸ばす道具であり、 その見返りに最も慎重さを求めます。それが渡すもの何に対しても、コンパイラが切られているからです。

この記事で学べること

  • 考え方の軸 — CreateObject文字列を鍵にした扉(ProgID)で、実行時に解決される
  • 本当の選択:遅延バインディングCreateObject)対事前バインディング(参照 + New
  • CreateObject がつねに新しいインスタンスを作る理由と、代わりに GetObject を使う場面
  • ヘッドレスな Outlook/Excel プロセスが取り残される理由と、正しく解放する方法
  • error 429 の意味と、それを引き起こすわずかな原因
  • どちらのスタイルをいつ選ぶか — 開発は事前、出荷は遅延

考え方の軸:文字列を鍵にした扉

自動化できる Windows コンポーネントはどれも、ProgIDScripting.DictionaryWord.Application のようなテキストの名前 — を登録しています。CreateObject はその文字列を取り、実行時に Windows レジストリで引き、コンポーネントを起動し、それへの参照を返します。

Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")   ' 名前でレジストリを引く -> 生きたオブジェクト

大事な言葉は実行時です。オブジェクトは文字列で名指しされるので、あなたがタイプしている間も、 プロジェクトがコンパイルされるときも、それについては何も分かりません — VBA が dict の正体を知るのは、 その行が実際に走ったときだけです。そのたった一つの事実 — 宣言された型ではなく文字列で識別される オブジェクト — が遅延バインディングの意味であり、以下のあらゆるトレードオフと罠を動かしています。

遅延バインディング対事前バインディング — 本当の選択

COM オブジェクトに到達する方法は 2 つあり、そのどちらを選ぶかがこのテーマの核心です。

遅延バインディングは、Object 変数を伴う CreateObject です。参照もなし、宣言された型もなし。

Dim ol As Object
Set ol = CreateObject("Outlook.Application")   ' 遅延:文字列と Object
Dim mail As Object
Set mail = ol.CreateItem(0)                    ' 0 = olMailItem — 定数名は使えない

事前バインディングは、検査された参照(ツール → 参照設定 → Microsoft Outlook Library)に、 宣言された型と New を加えたものです。

Dim ol As New Outlook.Application              ' 事前:本物の型
Dim mail As Outlook.MailItem
Set mail = ol.CreateItem(olMailItem)           ' olMailItem のような名前付き定数がここでは存在する

両者はほぼ同じものにコンパイルされます。違いは、オブジェクトがいつ理解されるか、そしてその見返りに 何が得られるかです。

  • 遅延(CreateObject — 可搬:設定する参照がなく、バージョンの違いを乗り越え、アプリを持つ どのマシンにも配れる。ただし IntelliSense はなく、名前付き定数(olMailItem)が存在しないので その数値をハードコードするか自前の Const を宣言することになり、あらゆるタイプミスはその行が 走ったときにしか表に出ない。
  • 事前(New + 参照) — タイプするそばから IntelliSense が効き、コンパイラが綴りを間違えた メンバーを捕まえ、名前付き定数も働く。ただし参照は特定のライブラリバージョンに結びつき、別の マシンや違う Office ビルドでは壊れることがある。

多くのプロが従う実践的なルール:開発は IntelliSense とコンパイルチェックのために事前バインディング で、出荷は遅延バインディングに切り替えるDim の型を Object に変え、NewCreateObject に 置き換え、使った定数を定義し、参照を外す。快適な作成体験と、可搬な成果物の両方が手に入ります。

CreateObject は新規インスタンスを作り、GetObject は既存につなぐ

CreateObject はつねにコンポーネントの新しいインスタンスを起動します。FileSystemObject のような 状態を持たないヘルパーには、それがまさに正しい。ユーザーがすでに開いているかもしれないアプリケーション には、それは罠です。

Set xl = CreateObject("Excel.Application")   ' 2 つ目の、見えない Excel を起動する — すでに開いていても

これで Excel が 2 つになり、見えないほうはユーザーには見えないリソースを抱えます。すでに実行中の ものを指したいなら、パスなしで ProgID を渡す GetObject を使います。

Dim ol As Object
On Error Resume Next
Set ol = GetObject(, "Outlook.Application")      ' 実行中の Outlook があれば、それにつなぐ
If ol Is Nothing Then Set ol = CreateObject("Outlook.Application")   ' なければ起動する
On Error GoTo 0

この「実行中ならつなぎ、そうでなければ起動する」パターンが、Outlook や Excel のようなユーザー向け アプリを、重複を生まずに自動化する正しいやり方です。GetObject にはもう一つの形もあります — GetObject(path) — これはアプリケーションの Open メソッドを通さずに、ファイルのオブジェクト (たとえばブック)を直接開きます。押さえるべき区別:CreateObject = 新規GetObject(, progID) = 既存GetObject(path) = オブジェクトとしてのファイル

Outlook が開いたままになる理由:起動したものは解放する

誰もが一度はぶつかる失敗がこれです。Outlook や 2 つ目の Excel を自動化し、マクロが終わり、そして OUTLOOK.EXEEXCEL.EXE のプロセスが、ウィンドウもなくタスクマネージャーで動き続けます — 見えず、 メモリを抱え、ときにはファイルロックも抱えて。原因は、アプリケーションオブジェクトを起動したのに、 閉じるよう一度も言わなかったことです。

CreateObject したオブジェクトは、アプリが自分自身を生かし続けている場合、変数がスコープを外れても 消えません。アプリケーションを終了し、参照を解放しなければなりません — 理想的には、エラー時にも 走るクリーンアップの中で。

Dim ol As Object
On Error GoTo Cleanup
Set ol = CreateObject("Outlook.Application")
' ... ol を使う ...

Cleanup:
    If Not ol Is Nothing Then
        ol.Quit               ' アプリに閉じるよう伝える
        Set ol = Nothing      ' 参照を解放する
    End If

漏れを防ぐ習慣は 2 つです。終える前にアプリの .Quit(ブックや文書なら .Close)を呼ぶこと、そして 作ったオブジェクトはすべて Set obj = Nothing すること。両方をエラーハンドラーに置きましょう — VBA のエラー処理を参照 — マクロ途中のクラッシュでも後始末されるように。 Scripting.Dictionary や FileSystemObject のような軽量なオブジェクトはプロセスを生まないので .Quit は不要ですが、Nothing にしておくのはやはりきれいです。

ぶつかるエラー:実行時の 429

ProgID はコンパイラが決して検査しない文字列なので、CreateObject の典型的な失敗は、その行が走った ときにしか現れません:error 429、「ActiveX component can't create object」。原因のリストは短い です。

  • 綴りを間違えた ProgIDCreateObject("Scripting.FileSystemObjectt")。文字列にコンパイル時の スペルチェックはありません。
  • アプリケーションがインストールされていない — Outlook のないマシンでの CreateObject("Outlook.Application")。遅延バインディングはどこへでも配れますが、対象のアプリは 実際に存在していなければなりません。
  • ビット数や登録の問題 — 64 ビット Office 上の 32 ビットコンポーネント、あるいは正しく登録され なかったコンポーネント。

実行時エラーなので、呼び出しをエラー処理でガードし、生の 429 ではなく 分かりやすいメッセージ(「Outlook がインストールされていません」)をユーザーに見せましょう。この 実行時にしか出ない失敗は遅延バインディングの代償であり、多くの開発者がまず事前バインディングで 書く理由でもあります。コンパイラなら、そのタイプミスを捕まえていたはずなのです。

率直な結論:コンパイラを切った、Windows への玄関

CreateObject は、Excel の外へ手を伸ばす動詞の中で単独で最も能力が高い — ファイル、メール、シェル、 データベース、そして他のあらゆる Office アプリへの扉です。その力と危うさは同じもの:文字列で名指し され、走るまで検査されないオブジェクトです。4 つのルールが安全に保ちます。

  • 文字列による遅延バインディングである → ProgID は実行時に解決される。タイプミスや欠けている アプリは、その行が走ったときに error 429 で失敗し、コンパイル時には決して失敗しない。
  • 遅延か事前かを意識して選ぶ → 開発中は IntelliSense とコンパイルチェックのために事前(New + 参照)、可搬なファイルを出荷するには遅延(CreateObject)。
  • CreateObject は新規、GetObject は既存 → ユーザー向けアプリには「実行中ならつなぎ、 なければ作る」パターンを使い、見えない重複を決して生まない。
  • 起動したものは解放する → アプリを .Quit し、Set obj = Nothing を、エラーハンドラーの中で。 さもないと、メモリとファイルロックを抱えたヘッドレスなプロセスが残る。

ここまでのすべては、Excel 自身のオブジェクトモデルの中に生きていました — 呼び出しは次の行の前に 終わり、間違いは大きな音を立ててエラーを上げる世界です。ShellEnvironCreateObject は、その 安全の外へ踏み出します — そして CreateObject が最も遠くまで踏み出し、コンパイラが一度も見なかった オブジェクトをあなたに手渡します。4 つのルールを尊重すれば、それは地雷原ではなく、玄関になります。

ExcelMaster の活用

本当に時間を奪う CreateObject のバグは、見えないものです。取り残された 2 つ目のヘッドレスな Excel、 一度も終了しなかった Outlook プロセス、アプリのないマシンでの実行時 429、間違った数値にハードコード された遅延バインディングの定数。どれも、文字列で名指しされたオブジェクトに対してコンパイラが切られて いるところから生まれます。

ExcelMaster は、自動化の 接着剤を正しく書きます。やりたいことを説明すれば — 「この範囲を Outlook のメールとして送って」、 あるいは「FileSystemObject でテキストファイルを読んで」 — 適切なバインディング(遅延、だからどこへでも 配れる)を生み出し、そう意図したときには GetObject で実行中のアプリにつなぎ、遅延バインディングに 欠けている定数を定義し、起動したオブジェクトはすべてエラーハンドラーの中で後始末します。あなたは どのアプリを操るかを説明するだけ。それを操り、何も宙ぶらりんにしないコードを書くのは、それがやります。

よくある質問

VBA の CreateObject と New の違いは何ですか?

New(事前バインディング)は、コンポーネントのライブラリへの検査された参照と、宣言された型 — Dim ol As New Outlook.Application — を必要とし、IntelliSense、コンパイル時のチェック、名前付き定数を くれます。CreateObject("Outlook.Application")(遅延バインディング)は、コンポーネントを ProgID 文字列で名指しし、参照を必要とせず、バージョンやマシンをまたいで動きますが、IntelliSense はなく、 名前が間違っていれば実行時にしか失敗しません。ツールのために New で開発し、可搬性のために CreateObject で出荷しましょう。

VBA の遅延バインディングと事前バインディングとは何ですか?

事前バインディングは、オブジェクトを特定の型(As Outlook.Application)として宣言し、ツール → 参照設定のエントリで裏打ちするので、コンパイラはオブジェクトを知り、IntelliSense と名前付き定数を 提供します。遅延バインディングは、それを汎用の Object として宣言し、CreateObject("ProgID") で 作るので、オブジェクトは実行時に文字列で解決され、コンパイラは何も知りません。事前バインディングは 作成に向き、遅延バインディングは出荷に向きます。特定のライブラリ参照が存在することに依存しないから です。

error 429「ActiveX component can't create object」を直すには?

error 429 は、CreateObject が渡された ProgID を起動できなかったことを意味します。3 つを確認 しましょう。ProgID の綴りが正しいこと(Scripting.FileSystemObject であって、その変種ではない)、 アプリケーションがそのマシンに実際にインストールされていること(遅延バインディングはどこへでも配れる が、対象のアプリは存在していなければならない)、そしてビット数の不一致がないこと(64 ビット Office 下の 32 ビットコンポーネント)。呼び出しをエラー処理で包み、ユーザーが生の 429 ではなく分かりやすい メッセージを見るようにしましょう。

すでに開いているアプリケーションで CreateObject を使うには?

CreateObject はつねに新しいインスタンスを起動するので、ユーザーがすでに開いているかもしれない アプリには、代わりに GetObject を使います:Set ol = GetObject(, "Outlook.Application") は実行中の Outlook につなぎます。安全なパターンは「実行中ならつなぎ、そうでなければ作る」です。 On Error Resume Next の下で GetObject を試し、オブジェクトが Is Nothing なら CreateObject に フォールバックします。これで、2 つ目の見えない Excel、Outlook、Word のコピーを生むのを避けられます。

マクロが終わったあとに Excel や Outlook が開いたままになるのはなぜですか?

アプリケーションオブジェクトを作ったのに、解放しなかったからです。自動化されたアプリは、.Quit を 呼んで参照を Nothing に設定するまで、自分のプロセスを生かし続けます。マクロが — あるいはクラッシュ が — その両方をせずに終われば、EXCEL.EXEOUTLOOK.EXE のプロセスがタスクマネージャーに見えない まま居残り、メモリとときにはファイルロックを抱えます。obj.Quit : Set obj = Nothing を、エラー ハンドラーから到達するクリーンアップ区間につねに置いて、何かが失敗したときにも走るようにしましょう。

検証環境

検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-30。

関連ガイド: VBA Shell — 外部プログラムを起動する · VBA Environ — 環境変数を読む · VBA FileSystemObject — ファイル操作 · VBA Dictionary — 連想配列 · VBA Outlook 自動化