Меня попросили устранить неполадки в сценарии VBA, который отправляет электронное письмо из базы данных Access. БД и VBA были разработаны для Access 2010 (данные, хранящиеся в базе данных SQL) и, вероятно, нацелены на Outlook 2010.
В настоящее время мы используем Outlook 2013 и 2016.
Когда мой сценарий (указанный ниже) запускается, в объявлении Outlook.Application генерируется ошибка: Тип данных, определяемый пользователем, не определен.
Это начало сценария, в котором мы определяем типы данных.
Option Compare Database
Option Explicit
' InitOutlook sets up outlookApp and outlookNamespace.
Private outlookApp As Outlook.Application
Private outlookNamespace As Outlook.NameSpace
Остальная часть сценария ниже. Он запускается кнопкой формы, которая напрямую вызывает SendEmail () и передает адрес электронной почты в качестве переменной.
Private Sub InitOutlook()
' Initialize a session in Outlook
Set outlookApp = New Outlook.Application
'Return a reference to the MAPI layer
Set outlookNamespace = outlookApp.GetNamespace("MAPI")
'Let the user logon to Outlook with the
'Outlook Profile dialog box
'and then create a new session
outlookNamespace.Logon , , True, False
End Sub
Public Sub SendEmail(varTo As Variant)
Dim mailItem As Outlook.mailItem
InitOutlook
Set mailItem = outlookApp.CreateItem(olMailItem)
mailItem.To = varTo & ""
mailItem.Subject = "subject text"
mailItem.Body = "Body text"
mailItem.Display
Set mailItem = Nothing
CleanUp
End Sub
Я не очень хорошо знаком с VBA / Access, но я работал с VB.NET и с самого начала был достаточно уверен, что это был простой вопрос: «отсутствует инструкция импорта или ссылка».
Немного покопавшись в этом, я обнаружил в сети здесь, что для использования этой функции вы должны добавить ссылку в библиотеке объектов Microsoft Outlook XX.X.
Я еще не видел ссылок, которые есть в этой базе данных (сейчас работаю над тем, чтобы добраться туда), так как у меня ограниченный доступ к этой базе данных доступа, поскольку она содержит много конфиденциальной информации, и при ее просмотре я должен находиться под наблюдением.
Однако, учитывая, что мы использовали Outlook 2010, когда писали этот сценарий, и теперь разделены между Outlook 2013 и 2016, я считаю, что нам нужно обновить эту ссылку на более новую.
Я обсуждал это с коллегой здесь, и он задал мне важный вопрос:
Can we reference more than one version of the Microsoft Outlook Object Library?
Если мы нацелимся на самую последнюю версию библиотеки, например, Outlook 2016, не будет ли сценарий работать для пользователей Outlook 2013?
Update: I found out through testing that if we used the MS Outlook 16.0 object library, Outlook 2013 would not recognize the reference, and would throw errors that the reference was missing.
If we used the MS Outlook 15.0 library, the script worked on machines with either version of outlook.
Как я уже упоминал, здесь, вы можете избежать всего этого, если будете просто использовать позднее связывание вместо раннего. Если вы настаиваете на раннем связывании и должны быть независимыми от версии, вам, вероятно, придется пойти по пути использования Условная компиляция. Раннее связывание будет намного проще :)
@DavidZemens Я попытался переключиться на позднюю привязку, и ваш пост очень помог в этом, но во время тестирования понял, что есть много несвязанных разделов нашего кода, которые также необходимо изменить, которые также использовали раннее связывание. Я не знаком с другими областями, которые необходимо обновить, и поэтому не могу надежно протестировать изменения на других страницах, чтобы убедиться, что они будут работать для всех пользователей. В итоге я обратился к библиотеке объектов MS Outlook 15.0, и это устранило проблему для пользователей Outlook 2013 и 2016.
Причина, по которой я спрашивал о ссылках, заключалась в том, что поздняя привязка не сработала, поскольку это не то, что я практиковал раньше, и у меня не было ресурсов для ее устранения, если у меня возникли проблемы с этим, поскольку это не моя основная должностная функция
это тоже сработает. просто включите самую раннюю поддерживаемую ссылку, и она позаботится о себе сама. очень немногие вещи не имеют обратной совместимости. ваше здоровье
Не имеет прямого отношения к вашему вопросу, но убедитесь, что у вас есть права на распространение библиотек Outlook, если вы планируете связать их со своим приложением.
Нет, если вы используете предыдущую ссылку, КОГДА вы делаете эту ссылку, вы замечаете, что это жестко заданное имя пути. BEYOND SILLY, чтобы предположить, что более ранняя привязка волшебным образом будет работать с более поздними версиями. Если вы пишете на VB6, FoxPro, C++, .net и т. д., И вы ссылаетесь на конкретную библиотеку, то такой код будет НАСТОЯЩИМ ПЕРЕПАДОМ! Такие ссылки представляют собой жестко запрограммированное имя пути. ЕДИНСТВЕННАЯ причина, по которой доступ "может" работать, заключается в том, что при запуске он пытается изменить ссылки, но на самом деле вы уже нарушили код.
Изменение позднего связывания ОЧЕНЬ незначительно. Если все сделано правильно, необходимо изменить только объект create - остальной код обычно работает как «есть», но некоторые константы должны быть установлены, поскольку компилятор не будет использовать константы, предоставленные указанной библиотекой, на которую вы больше не ссылаетесь.
Краткий (-новатый) ответ: Да, можно.
И по вашему второму вопросу; ссылка на библиотеку не должна иметь какого-либо неблагоприятного воздействия, подобного описанному. Я бы сказал, что лучший способ проверить наверняка - это проверить проблему.
Длинный ответ: зачем вам это нужно? IIRC; новая ссылка должна содержать все, что делала старая, с дополнительной библиотечной информацией. Однако, если это почему-то не так и новая ссылка не охватывает проблему, добавление новой ссылки, вероятно, решит проблему, но добавление ссылок на библиотеки волей-неволей не всегда является лучшей практикой.
Я предполагаю, что единственная ссылка на библиотеку Outlook в любом случае решит вашу проблему.
Так следует ли мне просто выбрать последнюю версию библиотеки Outlook? Или мне лучше попробовать перейти на позднюю привязку?
Просто используйте поздние привязки. Он решает подобные проблемы. Преобразование в поздние привязки должно быть очень простым.
Более новая библиотека должна содержать все, что делала старая (обычно). Но более новая библиотека не будет доступна в более старой версии приложения, что является проблемой OP. ЕСЛИ вы должны прикрепить ссылку (а не просто использовать ссылки на объекты с поздней привязкой), я думаю, вам нужно прикрепить версию, поддерживаемую самый ранний.
@DavidZemens был прав в этом отношении; Я испытал это вчера через некоторое тестирование. Обновили оп.
Если вам нужно использовать раннее связывание, добавьте ТОЛЬКО самую раннюю поддерживаемую ссылку (т. Е. Нет необходимости добавлять ссылку на Outlook 2003, если вы собираетесь поддерживать только 2013+), и он сам позаботится о себе. Очень немногие вещи не имеют обратной совместимости
В противном случае используйте позднее связывание. Это требует использования функции CreateObject
вместо ключевого слова New
для любого Outlook.__object__
.
Примечание, что вам нужно явно объявить константы Outlook, такие как olMailItem
, иначе они вызовут ошибки компиляции (при условии, что вы используете Option Explicit
):
Option Compare Database
Option Explicit
' InitOutlook sets up outlookApp and outlookNamespace.
Private outlookApp As Object ' Outlook.Application
Private outlookNamespace As Object ' Outlook.NameSpace
А затем небольшие изменения в теле вашего кода:
Const olMailItem As Long = 0 '## You need to add this enumeration!
Private Sub InitOutlook()
' Initialize a session in Outlook
Set outlookApp = CreateObject("Outlook.Application")
'Return a reference to the MAPI layer
Set outlookNamespace = outlookApp.GetNamespace("MAPI")
'Let the user logon to Outlook with the
'Outlook Profile dialog box
'and then create a new session
outlookNamespace.Logon , , True, False
End Sub
Public Sub SendEmail(varTo As Variant)
Dim mailItem As Object ' Outlook.mailItem
InitOutlook
Set mailItem = outlookApp.CreateItem(olMailItem)
mailItem.To = varTo & ""
mailItem.Subject = "subject text"
mailItem.Body = "Body text"
mailItem.Display
Set mailItem = Nothing
CleanUp
End Sub
Вы можете использовать позднее связывание вместо раннего, и он сам определит, какую версию использовать.