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

VBA CreateObject in Excel — Late Binding, GetObject, and Why Outlook Stays Open

|

VBA CreateObject in Excel — Late Binding, GetObject, and Why Outlook Stays Open

TL;DRCreateObject("ProgID") starts any COM app by name — Scripting.FileSystemObject, Outlook.Application, WScript.Shell. Because the object is named by a string, the compiler cannot check it: a wrong ProgID fails at runtime with error 429. CreateObject always starts a new instance (use GetObject to attach to a running one), and anything you start you must release.Quit the app and Set obj = Nothing — or you leave a headless process running.

Sub CreateObjectDemo()
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")   ' late binding: named by string
    Debug.Print fso.FileExists("C:\data.txt")

    Set fso = Nothing                                      ' release what you created
End Sub

CreateObject is the verb that turns VBA from an Excel language into a Windows automation language. Give it a ProgID — the registered name of a COM component — and it starts that component and hands you an object you can drive: read files with Scripting.FileSystemObject, send mail with Outlook.Application, run commands with WScript.Shell. It is the most powerful reach-outside-Excel tool in the language, and it asks for the most care in return, because the compiler is switched off for whatever it gives you.

What you'll learn

  • The mental model — CreateObject is a door keyed by a string (a ProgID), resolved at runtime
  • The real decision: late binding (CreateObject) vs early binding (a reference + New)
  • Why CreateObject always makes a new instance, and when to use GetObject instead
  • Why a headless Outlook/Excel process is left running, and how to release it properly
  • What error 429 means and the handful of things that cause it
  • When to prefer each style — develop early, ship late

The mental model: a door keyed by a string

Every automatable Windows component registers a ProgID — a text name like Scripting.Dictionary or Word.Application. CreateObject takes that string, looks it up in the Windows registry at runtime, starts the component, and returns a reference to it:

Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")   ' registry lookup by name -> a live object

The important word is runtime. The object is named by a string, so nothing about it is known while you type or when the project compiles — VBA finds out what dict is only when that line actually runs. That single fact — an object identified by a string instead of a declared type — is what "late binding" means, and it drives every trade-off and trap below.

Late binding vs early binding — the real decision

There are two ways to reach a COM object, and choosing between them is the heart of this topic.

Late binding is CreateObject with an Object variable. No reference, no declared type:

Dim ol As Object
Set ol = CreateObject("Outlook.Application")   ' late: a string, an Object
Dim mail As Object
Set mail = ol.CreateItem(0)                    ' 0 = olMailItem — the constant name isn't available

Early binding is a checked reference (Tools → References → Microsoft Outlook Library) plus a declared type and New:

Dim ol As New Outlook.Application              ' early: a real type
Dim mail As Outlook.MailItem
Set mail = ol.CreateItem(olMailItem)           ' named constants like olMailItem now exist

They compile to nearly the same thing; the difference is when the object is understood and what you get for it:

  • Late (CreateObject) — portable: no reference to set, survives version differences, ships to any machine that has the app. But no IntelliSense, named constants (olMailItem) do not exist so you hardcode their numbers or declare your own Const, and every typo surfaces only when the line runs.
  • Early (New + reference) — IntelliSense as you type, the compiler catches misspelled members, and named constants work. But the reference is tied to a specific library version and can break on another machine or a different Office build.

The practical rule most professionals follow: develop with early binding for the IntelliSense and compile checks, then switch to late binding to ship — change the Dim types to Object, replace New with CreateObject, define any constants you used, and remove the reference. You get the comfortable authoring experience and the portable deliverable.

CreateObject makes a new instance; GetObject attaches

CreateObject always starts a fresh instance of the component. For a stateless helper like the FileSystemObject that is exactly right. For an application the user may already have open, it is a trap:

Set xl = CreateObject("Excel.Application")   ' starts a SECOND, invisible Excel — even if one is open

Now there are two Excels, and the invisible one holds resources the user cannot see. When you mean the one already running, use GetObject with no path and the ProgID:

Dim ol As Object
On Error Resume Next
Set ol = GetObject(, "Outlook.Application")      ' attach to a running Outlook, if any
If ol Is Nothing Then Set ol = CreateObject("Outlook.Application")   ' else start one
On Error GoTo 0

This "attach if running, otherwise start" pattern is the correct way to automate a user-facing app like Outlook or Excel without spawning duplicates. GetObject has a second form too — GetObject(path) — which opens a file's object directly (for example a workbook) without going through the application's Open method. The distinction to hold: CreateObject = new, GetObject(, progID) = existing, GetObject(path) = a file as an object.

Why Outlook stays open: release what you start

Here is the failure everyone hits once. You automate Outlook or a second Excel, the macro finishes, and a OUTLOOK.EXE or EXCEL.EXE process keeps running in Task Manager with no window — invisible, holding memory and sometimes a file lock. The cause: you started an application object and never told it to close.

An object you CreateObject does not go away when your variable goes out of scope if the app keeps itself alive. You must quit the application and release the reference, ideally in cleanup that runs even on error:

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

Cleanup:
    If Not ol Is Nothing Then
        ol.Quit               ' tell the app to close
        Set ol = Nothing      ' release the reference
    End If

Two habits prevent the leak: call the app's .Quit (or .Close for a workbook/document) before you finish, and Set obj = Nothing every object you created. Put both in an error handler — see VBA error handling — so a mid-macro crash still cleans up. Lightweight objects like Scripting.Dictionary or the FileSystemObject do not spawn a process and need no .Quit, but setting them to Nothing is still tidy.

The error you'll hit: 429, at runtime

Because the ProgID is a string the compiler never checks, the classic CreateObject failure appears only when the line runs: error 429, "ActiveX component can't create object." It has a short list of causes:

  • A misspelled ProgIDCreateObject("Scripting.FileSystemObjectt"). There is no compile-time spell-check for a string.
  • The application is not installedCreateObject("Outlook.Application") on a machine without Outlook. Late binding ships anywhere, but the target app must actually be present.
  • A bitness or registration problem — a 32-bit component on 64-bit Office, or a component that never registered correctly.

Because it is a runtime error, guard the call with error handling and give the user a clear message ("Outlook is not installed") instead of a raw 429. This runtime-only failure is the price of late binding, and the reason many developers author with early binding first: the compiler would have caught the typo.

The honest verdict: the gateway to Windows, with the compiler switched off

CreateObject is the single most capable reach-outside-Excel verb — the door to files, mail, the shell, databases, and every other Office app. Its power and its danger are the same thing: an object named by a string, unchecked until it runs. Four rules keep it safe:

  • It is late binding by string → a ProgID resolved at runtime; a typo or a missing app fails with error 429 when the line runs, never at compile time.
  • Choose late vs early deliberately → early (New + reference) for IntelliSense and compile checks while developing; late (CreateObject) to ship a portable file.
  • CreateObject is new; GetObject is existing → use the "attach if running, else create" pattern for user-facing apps so you never spawn an invisible duplicate.
  • Release what you start.Quit the app and Set obj = Nothing, in an error handler, or you leave a headless process holding memory and file locks.

Everything up to here lived inside Excel's own object model, where a call finishes before the next line and a mistake raises a loud error. Shell, Environ, and CreateObject step outside that safety — and CreateObject steps furthest, handing you an object the compiler never saw. Respect the four rules and it is a gateway, not a minefield.

How ExcelMaster helps

The CreateObject bugs that cost real time are the invisible ones: a second headless Excel left running, an Outlook process that never quit, a runtime 429 on a machine missing the app, a late-binding constant hardcoded to the wrong number. Each comes from the compiler being switched off for objects named by a string.

ExcelMaster writes the automation glue correctly. Describe the job — "send this range as an Outlook email," or "read a text file with the FileSystemObject" — and it produces the right binding (late, so it ships anywhere), attaches to a running app with GetObject when that is what you mean, defines the constants late binding lacks, and cleans up every object it started in an error handler. You describe which app to drive; it writes code that drives it and leaves nothing hanging.

Frequently asked questions

What is the difference between CreateObject and New in VBA?

New (early binding) needs a checked reference to the component's library and a declared type — Dim ol As New Outlook.Application — and gives you IntelliSense, compile-time checking, and named constants. CreateObject("Outlook.Application") (late binding) names the component by a ProgID string, needs no reference, and works across versions and machines, but has no IntelliSense and fails only at runtime if the name is wrong. Develop with New for the tooling, ship with CreateObject for portability.

What is late binding vs early binding in VBA?

Early binding declares an object as a specific type (As Outlook.Application) backed by a Tools → References entry, so the compiler knows the object and offers IntelliSense and named constants. Late binding declares it as generic Object and creates it with CreateObject("ProgID"), so the object is resolved by string at runtime with no compiler knowledge. Early binding is better for authoring; late binding is better for shipping because it does not depend on a specific library reference being present.

How do I fix "ActiveX component can't create object" (error 429)?

Error 429 means CreateObject could not start the ProgID you passed. Check three things: the ProgID is spelled correctly (Scripting.FileSystemObject, not a variant); the application is actually installed on that machine (late binding ships anywhere but the target app must be present); and there is no bitness mismatch (a 32-bit component under 64-bit Office). Wrap the call in error handling so users see a clear message rather than the raw 429.

How do I use CreateObject with an already-open application?

CreateObject always starts a new instance, so for an app the user may already have open, use GetObject instead: Set ol = GetObject(, "Outlook.Application") attaches to a running Outlook. The safe pattern is "attach if running, otherwise create": try GetObject under On Error Resume Next, and if the object Is Nothing, fall back to CreateObject. This avoids spawning a second, invisible copy of Excel, Outlook, or Word.

Why does Excel or Outlook stay open after my macro finishes?

Because you created an application object and never released it. An automated app keeps its process alive until you call .Quit and set the reference to Nothing. If the macro ends — or crashes — without doing both, the EXCEL.EXE or OUTLOOK.EXE process lingers invisibly in Task Manager, holding memory and sometimes a file lock. Always put obj.Quit : Set obj = Nothing in a cleanup section reached by an error handler so it runs even when something fails.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-08-30.

Related guides: VBA Shell · VBA Environ · VBA FileSystemObject · VBA Dictionary · VBA Outlook Automation