How to do late binding in VBA? - vba

I have a function that creates an email via VBA.
I made this through Excel 2016. When some of my colleagues try to use it there an error of missing references (Outlook Library 16.0).
I looked in the internet for solutions and found the best is Late Binding. I have read about it but I don't understand how to make it work in the following example code.
Sub EscalateCase(what_address As String, subject_line As String, email_body As String)
Dim olApp As Outlook.Application
Set olApp = CreateObject("Outlook.Application")
Dim olMail As Outlook.MailItem
Set olMail = olApp.CreateItem(olMailItem)
olMail.To = what_address
olMail.Subject = subject_line
olMail.BodyFormat = olFormatHTML
olMail.HTMLBody = email_body
olMail.Send
End Sub

This is early binding:
Dim olApp As Outlook.Application
Set olApp = New Outlook.Application
And this is late binding:
Dim olApp As Object
Set olApp = CreateObject("Outlook.Application")
Late binding does not require a reference to Outlook Library 16.0 whereas early binding does. However, note that late binding is a bit slower and you won't get intellisense for that object.

As Callum pointed out, late binding involves changing your application reference to an object and not setting a reference to the library.
Without a reference Excel doesn't know anything about Outlook until runtime. This also means that not only will intellisense not work, the constant names for values in Outlook won't work either.
e.g. In Outlooks Immediate window if you type Application.CreateItem( you'll get a whole load of item types pop up to choose from. olContactItem for instance.
Excel hasn't a clue what olContactItem means - it's an Outlook constant that only Outlook or an application with a reference to Outlook understands.
In Outlooks immediate window type ?olContactItem and it will return 2. That's the number you need to use instead of the constant name.
So your code changes from
Application.CreateItem(olContactItem) to olApp.CreateItem(2)
You need to do this throughout your code.

In that situation I generally define the constant globally in a module like this, that way you preserve the descriptive value of the variable.
Public Const olFormatHTML = 2

Related

Create email, based on Outlook template, from a Word menu

This is the code for other Word templates on the menu.
Private Sub "button name_Click()
Unload ####Menu
End Sub
This is code I've seen to create an Outlook item from Word.
Sub CreateFromTemplate()
Dim MyItem As Outlook.MailItem
Set MyItem = Application.CreateItemFromTemplate("C:\statusrep.oft")
MyItem.Display
End Sub
Sub CreateTemplate()
Dim MyItem As Outlook.MailItem
Set MyItem = Application.CreateItem(olMailItem)
MyItem.Subject = "Status Report"
MyItem.To = "Dan Wilson"
MyItem.Display
MyItem.SaveAs "C:\statusrep.oft", OlSaveAsType.olTemplate
End Sub
How do I combine these?
It seems you just need to automate Outlook from Word VBA. To start an Outlook Automation session, you can use either early or late binding. Late binding uses either the Visual Basic GetObject function or the CreateObject function to initialize Outlook. For example, the following code sets an object variable to the Outlook Application object, which is the highest-level object in the Outlook object model. All Automation code must first define an Outlook Application object to be able to access any other Outlook objects.
Dim objOL as Object
Set objOL = CreateObject("Outlook.Application")
To use early binding, you first need to set a reference to the Outlook object library. Use the Reference command on the Visual Basic for Applications (VBA) Tools menu to set a reference to Microsoft Outlook xx.x Object Library, where xx.x represents the version of Outlook that you are working with. You can then use the following syntax to start an Outlook session.
Dim objOL as Outlook.Application
Set objOL = New Outlook.Application
Most programming solutions interact with the data stored in Outlook. Outlook stores all of its information as items in folders. Folders are contained in one or more stores. After you set an object variable to the Outlook Application object, you will commonly set a NameSpace object to refer to MAPI, as shown in the following example.
Set objOL = New Outlook.Application
Set objNS = objOL.GetNameSpace("MAPI")
Set objFolder = objNS.GetDefaultFolder(olFolderContacts)
Once you have set an object variable to reference the folder that contains the items you wish to work with, you use appropriate code to accomplish your task, as shown in the following example.
Sub CreateNewOutlookMail()
Dim objOLApp As Outlook.Application
Dim NewMail As Outlook.MailItem
' Set the Application object
Set objOLApp = New Outlook.Application
' You can only use CreateItem for default items
Set NewMail = objOLApp.CreateItem(olMailItem)
' Display the new mail form so the user can fill it out
NewMail.Display
End Sub
See Automating Outlook from a Visual Basic Application for more information.

Late binding creating object VBA

I would like to use late binding to use the following reference :
Name : "Microsoft Windows Common Controls 6.0 (SP6)"
Filepath : "C:\Windows\System32\MSCOMCTL.OCX"
GUID : "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}"
I understood thanks to this topic the difference between early and late binding:
This is early binding: Dim olApp As Outlook.Application Set olApp =
New Outlook.Application
And this is late binding: Dim olApp As Object Set olApp =
CreateObject("Outlook.Application")
However, I do not know how to find my object name (see bold quoted text above). Every example on the internet uses Powerpoint or Outlook.application.
Any help? Thanks

VBA in Outlook: "microsoft outlook has stopped working" message

I try to write a VBA script which replys automatically on mails which are in the inbox of a shared mailbox. At the moment it's just a test, later on I want to reply on new incoming mails.
However, so far if I try to run the code, Outlook crashes with the error "microsoft outlook has stopped working" and I have to restart Outlook.
fyi: I'm using a German Outlook Version 2007.
Sub ReplyMail()
Dim myOutApp As Object
Dim myNameSpace As Object
Dim myMailFolder As Object
Dim myRecipient As Outlook.Recipient
boxName = "sharedmailbox#host.de" 'configure mailbox address here
'Get Mailbox folder
Set myOutApp = CreateObject("Outlook.application")
Set myNameSpace = myOutApp.GetNamespace("MAPI")
Set myRecipient = myNameSpace.CreateRecipient(boxName)
myRecipient.Resolve 'convert mail address into mailbox name
Set myMailFolder = myNameSpace.GetSharedDefaultFolder(myRecipient, olFolderInbox)
Dim Item As Object
Set Item = myMailFolder.Items(1)
Dim oMail As Outlook.MailItem
Set oMail = Item.Reply
With oMail
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML>This is a test mail.</HTML>"
.Send
End With
End Sub
If use ".display" instead of ".send" the mail pops up correctly and I'm able to send the mail manually.
I really don't know how to solve this error, pls help!
Thank you!
Michael
Very strange!
Unless it's an exceptional bug, I don't see it.
Small remark: Declare your objects as Outlook objects:
Dim myOutapp as outlook.application
Dim myNameSpace as outlook.namespace
Dim myMailFolder as Mapifolder
This for general performance (Object is the general type) but it will almost certainly not solve your problem.
If I were in your situation, I'd try to entirely quit Outlook from memory, repair or reinstall Outlook/Office. I don't think that something is terribly wrong with your code; Since the .display works, I'm very surprised.
There might be an issue with access rights to
C:\Users\
I had a similar issue with opening certain e-mails starting from a certain point of time. Somehow access rights to that folder had been deconfigured.
So I followed this procedure and everything was fine again:
http://www.addictivetips.com/windows-tips/windows-7-access-denied-permission-ownership/

Outlook Object Library Does Not Switch Between Versions 12 And 14

I have a .dotm template file on a network share. There are macros with references to the Word, Office, and Outlook object libraries. We use two different platforms, Windows XP and Windows 7, along with Microsoft Office 2007 and Office 2010. When users open the template file the references for Word and Office adjust automatic and accordingly (that is, they’re set to Microsoft Word 12 Object Library or Microsoft Word 14 Object Library as needed), and the macros run without a problem.
Microsoft Outlook Object Library switches properly from version 12 to 14. It does not switch properly from version 14 to 12. In that case, it gives the error that the libary is not found. Is this a bug? Is there a workaround? Something I’m overlooking?
ForEachLoop,
It appears that your question has largely been answered. I will merely add a bit of information for clarity's sake, and to provide this question with an answer. A user on the Microsoft Forums, Ossiemac, noted that LateBinding was the way to go, as has been stated by Siddarth Rout. As implied by Siddarth, that means you do not have to worry about references.
Ossiemac provided some sample code for using the LateBinding in the sending of an email, which I have reformatted and placed here:
Private Sub btnLateBindMethod_Click()
' Variables used for LateBinding
Dim objOutlook As Object 'Outlook.Application
Dim objEmail As Object 'Outlook.MailItem
Dim objNameSpace As Object 'Outlook.NameSpace
Const OutLookMailItem As Long = 0 'For Late Binding
Const OutLookFolderInbox As Long = 6 'For Late Binding
Const OutLookFormatHTML As Long = 2 'For Late Binding
Dim strSubject As String
Dim strAddress As String
On Error Resume Next
Set objOutlook = GetObject(, "Outlook.Application")
On Error GoTo 0
If objOutlook Is Nothing Then
Set objOutlook = CreateObject("Outlook.Application")
Set objNameSpace = objOutlook.GetNamespace("MAPI")
objNameSpace.GetDefaultFolder(OutLookFolderInbox).Display
End If
Set objEmail = objOutlook.CreateItem(OutLookMailItem)
strSubject = "Hello World"
With objEmail
'.To = strToAddress 'Commented to prevent accidental send
.Subject = strSubject
.BodyFormat = OutLookFormatHTML
.Display
'Full Name of window can change depending on Tools -> Options -> Mail Format
'Changing this option for outgoing mail changes the window name.
'However, AppActivate appears not to require entire name but needs up to end
'of - Message which is included in heading following the Subject string
'irrespective of the Mail Format option chosen.
AppActivate (strSubject & " - Message")
End With
End Sub
Jimmy Pena has an article discussing the contrast of EarlyBinding and LateBinding -
~JOL

Determining whether an existing Outlook instance is open

After reading how to use automation to send a message, I'm unclear of whether it's possible to avoid opening a new instance of Outlook if I already have one opened. If so, I'm unsure of how to search for examples determining whether an existing Outlook instance is open.
-----Including the suggestion--------
I have the following snippet, but I found that I can't create the instance properly. I'm basically following this example. I'm either getting this screenshot, or the error of "User-defined type not defined." Any suggestions?
Sub Example()
'Dim w As Outlook.Application
Const ERR_APP_NOTRUNNING As Long = 429
On Error Resume Next
' Handle Microsoft outlook
Set w = GetObject(, "Outlook.Application")
If Err = ERR_APP_NOTRUNNING Then
'Set w = New Outlook.Application
Set w = CreateObject("Outlook.Application")
End If
End Sub
I know this question has been answered, but I thought I'd add that applications like Outlook (and I believe PowerPoint as well) are single-instance applications -- there is no need to determine if Outlook is already open because you can only have one copy of Outlook running.
http://msdn.microsoft.com/en-us/library/aa164542(v=office.10).aspx
If you need to instantiate Outlook, simply use CreateObject to create the instance; if Outlook is already running, your object reference will point to the existing instance. If not, you will create the class. Binding (late or early) is irrelevant.
For example, let's say Outlook isn't running. We can use this code to create the instance:
Sub testOutlook()
Dim olApp As Object ' Outlook.Application
Set olApp = CreateObject("Outlook.Application")
MsgBox (olApp2 Is Nothing)
End Sub
This will print "False" because we created the instance.
Let's say Outlook IS running. We can use this code to verify that using GetObject and CreateObject will refer to the existing instance:
Sub testOutlook()
Dim olApp As Object ' Outlook.Application
Dim olApp2 As Object ' Outlook.Application
Set olApp = GetObject(, "Outlook.Application")
MsgBox (olApp Is Nothing)
Set olApp2 = CreateObject("Outlook.Application")
MsgBox (olApp2 Is Nothing)
MsgBox "Same object? " & (olApp Is olApp2)
End Sub
This will print "False" (existing instance), "False" (our alleged "new instance"), but the last message box is "True" because the new instance is actually the same object as the existing instance.
So what do we do if we don't know if Outlook is running or not? As demonstrated above, CreateObject either created a new instance (if one didn't exist, as in the first example) or hooked the existing instance if Outlook was already open (as in the second example).
I see in your question that you commented out
'Dim w As Outlook.Application
presumably because this gives you the "User-defined type not defined" error.
This is likely because you have not set a reference to the Outlook library in your Excel-VBA project. This is done as follows: Tools > References > check "Microsoft Outlook xx.x Object Library". Then you can write this
Dim w As Outlook.Application
Set w = New Outlook.Application
' or,
'Set w = CreateObject("Outlook.Application")
which, by the way, results in compile-time (or "early") binding. And gives you the Outlook object intellisense.
Alternatively, you can omit setting the reference and declare w as a generic object and let it bind at run-time
Dim w As Object
Set w = CreateObject("Outlook.Application")
but runtime (or "late") binding is less efficient.
Do whatever feels best -- I'm going to go ahead and venture that chances are, you won't notice the difference in efficency. I'm a recent convert to the early-binding thing, really just because of the intellisense.
EDIT So you've created a new Outlook application, but you can't see it. If you look in the Windows task manager, you'll see that the process is there, running -- but it's just not showing on the screen. Unfortunately, some brilliant engineer at Microsoft decided that Outlook shouldn't have a Visible property like Word or Excel do, so we have to use an awkward workaround. Open one of the special folders e.g. the Inbox like this:
Dim w As Outlook.Application
Dim wInbox As Outlook.MAPIFolder
Set w = New Outlook.Application
Set wInbox = w.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
wInbox.Display 'This makes Outlook visible
Set w = GetObject(, "Outlook.Application")
this should get running instance, if none is running catch error and do CreateObject
If you like, use this.
This is not a perfect solution, but you can open Outlook App when it's not be opened.
Function OpenOutlookApp(isSend As Boolean) As Boolean
' If it has opened, return true.
' my office version is 2016.
Dim oApp As Object
On Error GoTo ErrorHandle
On Error Resume Next
Set oApp = GetObject(, "Outlook.Application")
On Error GoTo 0
If oApp Is Nothing Then
Set oApp = CreateObject("Outlook.Application")
oApp.GetNamespace("MAPI").GetDefaultFolder(6).Display
End If
If isSend Then Call SendAndReceiveOutlookMail(False)
OpenOutlookApp = True
GoTo NonErrorHandle
ErrorHandle:
NonErrorHandle:
On Error GoTo 0
End Function
Sub SendAndReceiveOutlookMail(isQuit As Boolean)
Dim oApp As New Outlook.Application
On Error Resume Next
Call oApp.Session.LogOn("Outlook", "")
Call oApp.Session.SendAndReceive(True)
If isQuit Then oApp.Quit
Set oApp = Nothing
On Error GoTo 0
End Sub