Part 2 of your question is quite interesting, and it's well worth an extended answer.
This is going to cover three key points:
- Objects and object variables;
- Pitfalls when dismissing objects;
- ...And an important change in reference-counting the Application object in Excel 2013.
"Not all objects are equal".Now read on...
Some objects are created in your Excel session's 'own' memory space, and their memory allocation is controlled by your session; some objects have persistent components that exist after the object variable is dismissed; and some do not:
Set oDict = CreateObject("Scripting.Dictionary")
Set oWShell = CreateObject("Shell.Application")
In both these cases, memory is allocated, the object variables (and their vTable of pointers to methods and properties) are instantiated, and they are yours to command until you dismiss them:
Set oDict = Nothing
Set oWShell = Nothing
And, on dismissal, no trace of them remains.
But this object is persistent:
Dim oWbk as Excel.Workbook
Set oWbk = Application.Workbooks.Add
...You've created a new workbook object and, if you dismiss the object variable with Set oWbk = Nothing
, you will see that the new workbook object still exists as a visible presence in the user interface.
What you actually created was a Workbook object - a workbook window with an active worksheet and the full user interface that goes with that - and a Workbook object variable - a programmer's COM interface, a table of methods and properties for the Workbook object - that you can manipulate in code using the named entity 'oWbk'.
Dismissing the oWbk object variable removes that framework, but the Workbook itself will still exist: you've created a Workbook object, and it's yours to keep.
The object is more than its object variable and dismissing the variable does not destroy the object: it just dismisses an interface, a framework of methods and properties that you can use to manipulate the object in code.
Closing the Workbook, with or without saving a file, should automatically dismiss the object variable and clear up the memory allocated for that interface of properties, methods and attributes:
'try this:
oWbk.Close SaveChanges:=False
' or maybe this:
Application.Workbooks(Application.Workbooks.Count).Close SaveChanges:=False
...That is to say, you would expect both of those commands to call Set oWbk= Nothing
- especially the oWbk.Close
command - but if you try either of them without explicitly dismissing oWbk, you will find that oWbk
still exists as an empty husk, and all calls and requests for information on it (try> Debug.Print> TypeName(oWbk)
) will return 'Automation Error' messages.
Some of the commments in the previous answer mention the UserForm
object which - unlike the Dictionary and the Shell object - is an object with a visible user interface. But this user interface is not a persistent new object in the Excel user interface like a Workbook or a worksheet.
Luckily for you, the object you created is owned by your Excel session, and you can instantiate an object variable again, to get the same framework of methods and properties, and take control of the object again:
Set oWbk = Application.Workbooks(Application.Workbooks.Count)
...Assuming, of course, that you have some way of being sure that you identified the right workbook object: but that's not your question at all.
Where this answer is going is: objects that are not created in your Excel session's 'own' memory.
Set oApp = CreateObject("Excel.Application")
This statement will create an Excel object which, like the new Workbook, has a User Interface (although you'll need to set the .Visible
property True to see it) and and a persistent presence in memory: once again, the object is more than its object variable, and dismising the variable does not destroy the object.
Unlike the new Workbook, it isn't quite yours to command: it's an Excel session in it's own right, it allocates its own memory - oApp's 'footprint' in your current session's memory is just the pointer and the name: the interface (vTable, iDispatch, and all those named methods with pointers to the structures that implement the arcane act of manipulating an Excel session in VBA) exists in the block of memory allocated by this new Excel session.
Here's what happens in Office 2010, and older versions of Excel:
Dismissing the object variable with Set oApp = Nothing
leaves that session up and running, and I would strongly suggest that you make the session visible so that you can close it manually!
Closing that Excel session manually, without explicitly dismissing the oApp object variable, will definitely leave oApp in the 'empty husk' state, and a grim and headless spectre wailing 'The Automation object has disconnected from its clients!' in the dark corners of your code base.
But, in Office 2013 and later versions, Set oApp = Nothing
performs exactly the reference-counting you would expect and the session closes. Try it:
Private Sub Test()
Dim oApp As Excel.Application
Set oApp = New Excel.Application
'Set oApp = CreateObject("Excel.Application")
oApp.Visible = True
Set oApp = Nothing
End Sub
It won't close on Set oApp = Nothing
if another object variable has a reference - and that's not the only entity that gets to increment the reference counter: user activity in the GUI (try creating a new workbook and editing it) keeps the session up and running, too.
For your own amusement, see if oApp.Quit
does actually dismiss oApp and sets it to Nothing
.
Of course, oApp.Quit
will definitely close the session...
...Or will it? If there is something going on in that session - a long calculation, or an 'modal' error message that you have to see and click before the Application object responds to any other input, from the user interface or your VBA - then oApp.Quit
won't close the session.
Lets not go there. All things being equal, oApp.Quit
will definitely close the session in 2010 and earlier versions of Excel.
But in Office 2013, calling 'Quit' from the last object variable merely hides the UI: the object variable still responds to your code - the methods and properties that don't require an active workbook are still accessible via oApp - and a separate instance of Excel.exe is clearly visible in the Processes tab of Task manager.
Likewise, quitting the new session by clicking the 'close' button in the user interface closes the session's windows but, if there's an object variable with a reference to this application object in your code, it's still there, in memory, and 'oApp' can still get at the properties and methods.
So the reference counter works both ways in current versions of Excel: the object exists until the reference count decrements to zero, and the last remaining object variable will not be left 'disconnected' by a quit command or UI action.
Nevertheless, your session doesn't 'own' that new application object: if you've dismissed the last object variable and set it to Nothing
, and there's something else keeping the neww session alive - user activity, or some internal process - there's nothing like the Application.Workbooks() or Worksheets() collection to identify other Excel sessions and instantiate an object variable pointing to a specific instance of an Excel.Application object.
There are ways of getting a specific session using API calls, but they aren't as reliable as you might wish them to be.
...So, all in all, there's quite a lot in that 'part 2'.
Set .. Nothing
(see here) – JimmyPena