PDA

Показать полную графическую версию : [решено] Сохранение контактов Outlook 2010


DaffiSmik
22-01-2014, 09:57
Доброго дня!!!
Используем в компании скрипт для формирования адресной книги. На всех клиентах отрабатывает нормально, но на Windows 8 в сочетании с Outlook 2010 (на быстром железе) проявилась проблема. Либо контакты записываются не полностью либо, либо вообще не записываются.
Весь скрипт выкладывать не буду, он большой и часть его здесь будет совершенно лишней, поэтому вкратце о скрипте:
Данный скрипт подключается к Outlook, удаляет папки с контактами подразделений, создает новые папки с подразделениями, подключается к файлику в формате csv и из него производит добавление адресов сотрудников в соответствующие подразделениям папки. Ну и собственно сам скрипт:
Сам текст:

'Блок 3.2. Работа с MS Outlook
'Если профиль по умолчанию Outlook обнаружен начинаем работу
If InMot = 1 Then
msb = "Производиться обновление адресных книг Microsoft Outlook" & vbLf _
& "В процесссе обновления программа Microsoft Outlook будет закрыта"
MsPop msb, 1, 2, "Обновление адресных книг Microsoft Outlook", 0, 0
MotOpen = StartStop(0, 1)
'On Error Resume Next
WScript.Sleep 1000 ' Это засыпание скрипта очень важно! Без него объект Outlooka не успевает выгрузится и новый объект не создается
Set objOutlook = CreateObject("Outlook.Application")
Set objNameSpace = objOutlook.GetNamespace("MAPI")
Set ContOlFolder = objNameSpace.GetDefaultFolder(10)
Set OlDelFolder = objNameSpace.GetDefaultFolder(3)
ContDel 0
WScript.Sleep 1000
FoldAdd 0
WScript.Sleep 1000
ContAdd 0
End If
Используемые функции:
'Функция работы с почтовым клиентом,
'производит закрытие, открытие почтовых клиентов по ходу процессa обновления
'передаваемые параметры:
'st - параметр закрытия открытия (0-закрыть, 1-открыть, 2-закрыть без уведомлений);
'tp - тип клиента (0 - Mozilla Thunderbird, 1 - MS Outlook)
'в зависимости от передаваемого параметра st, возвращает:
' True - если программа была открыта и st = 0
' False - если программа была закрыта и st = 0
' "" - если st = 1
Function StartStop(st, tp)
If tp = 0 Then
ClName = "Mozilla Thunderbird"
Stname = "thunderbird.exe"
ElseIf tp = 1 Then
ClName = "Microsoft Outlook"
Stname = "outlook.exe"
End If
strFind = "SELECT * FROM Win32_Process WHERE Name = '" & Stname & "'"
If st = 0 Or st = 2 Then
'Проверяем открыта ли программа
OpenProg = 0
For Each objProc In objService.ExecQuery(strFind)
OpenProg = 1
Next
'Если открыта закрываем согласно заданного параметра StopClient
If OpenProg = 1 Then
If st = 0 Then
zok = "Программа " & ClName & " закрывается"
ms1 = "Выполняется обновление адресных книг. Программа " & ClName & " будет "
ms2 = "Для продолжения операции обновления нажмите кнопку ''Ok''. Для отмены закрытия" _
& " программы нажмите кнопку ''Отмена'', при этом операция обновления будет отменена."
If StopClient = 2 Then 'автоматически закрывающееся окно
msb = ms1 & "автоматически закрыта через " & Otvet & " сек." & VbLf & ms2
mscl = objShell.Popup(msb, Otvet, zok, vbOkCancel+vbQuestion+VbSystemModal)
ElseIf StopClient = 3 Then 'окно с ожиданием ответа пользователя
msb = ms1 & "закрыта." & VbLf & ms2
mscl = MsgBox(msb, vbOkCancel+vbQuestion+VbSystemModal, zok)
End If
If LogFile < 3 Then 'записываем данное событие в лог, если задано и параметр лога расширенный
If DebugLog = 1 Then AllMsg = AllMsg & msb & VbLf
End If
End If
If (mscl <= 1) or (StopClient = 1) Then
For Each objProc In objService.ExecQuery(strFind)
If tp = 1 Then 'если Outlook - завершаем корректно
If OsInf > 61 Then 'Если версия Windows 8.0 и выше срубаем Outlook
objProc.Terminate
Else
Set objOutlook = CreateObject("Outlook.Application")
objOutlook.Quit
'Set objOutlook = Nothing
End If
ElseIf tp = 0 Then 'если Mozilla - просто закрываем
objProc.Terminate
End If
Next
StartStop = True
Exit Function
ElseIf mscl > 1 Then 'пользователь отказался от обновления
msb = "Процесс обновления отменен, скрипт останавливается."
MsPop msb, 1, 3, "Отмена обновления", 2, 0
GoodBye
End If
Else 'если закрыта то и не надо
StartStop = False
Exit Function
End If
ElseIf st = 1 Then
StartProg = 0
'в зависимости от параметра StartClient определяем потребность в запуске
If StartClient = 2 Then
If tp = 0 Then
If MztOpen Then StartProg = 1
ElseIf tp = 1 Then
If MotOpen Then StartProg = 1
End If
ElseIf StartClient = 1 Then
StartProg = 1
End If
'запускаем программу
If StartProg = 1 Then
Strt = 0
If tp = 0 Then 'определяем путь к thunderbird.exe
'если Thunderbird был ранее найден в реестре проверим путь запуска
If InTbr = 1 And objFSO.FileExists(PthTnb) Then Strt = 1
If Not Strt = 1 Then 'если не был найден в реестре попробуем по стандартному пути
PthTnb = SpecFolder("PROGRAM_FILES") & "\" & ClName & "\" & Stname 'для 32bit
If Not objFSO.FileExists(PthTnb) Then 'для 64-bit другой путь
PthTnb = SpecFolder("PROGRAM_FILESX86") & "\" & ClName & "\" & Stname
If Not objFSO.FileExists(PthTnb) Then 'Thunderbird вероятно установлен в другую папку
msb = "Файл запуска " & ClName & " в стандартной папке не обнаружен." _
& VbLf & "Запустите " & ClName & " с помощью ярлыка, самостоятельно"
MsPop msb, 1, 2, "Невозможно запустить Mozilla Thunderbird автоматически", 0, 0
Exit Function
Else
Strt = 1
End If
Else
Strt = 1
End If
End If
End If
If Strt = 1 Or tp = 1 Then
msb = "Процесс обновления адресных книг завершен, запускаем " & ClName & "."
MsPop msb, 1, 2, "Запуск " & ClName, 0, 0
OpenProg = 0
While OpenProg = 0
If tp = 0 Then objShell.Exec(PthTnb)
If tp = 1 Then objShell.Run ("cmd /c start outlook")
WScript.Sleep 1000
For Each objProc In objService.ExecQuery(strFind)
OpenProg = 1
Next
Wend
End If
End If
End If
End Function
Используемые процедуры:
'Данная процедура удаляет папки Подразделений в папке Контакты Outlook
'Первый For задает количество проходов для удаления папок. Я хз... почему но с
'первого прохода все папки не удаляются, поэтому процедура загнана в цикл
'передаваемые параметры:
'filtip - тип файла адресных книг (0-подразделения, 1-контрагенты)
Sub ContDel(filtip)
DelFol = 1
Stp = 0
While DelFol = 1
DelFol = 0
For Each objOlFolders In ContOlFolder.Folders
'Перемещаем папки подразделений в корзину
MyFolder = objOlFolders.Name
If DeptName (MyFolder,"Ft",filtip) Then
MsPop "Удаляем папку " & MyFolder & "(проход " & Stp & ").", 1, 1, "Удаление папок контактов в Outlook", 0, 1
objOlFolders.ShowAsOutlookAB = False
Set OldContactsFoder = ContOlFolder.Folders(MyFolder)
On Error Resume Next
OldContactsFoder.MoveTo OlDelFolder
'в Outlook версиях старше 2007 наблюдается глюк удаления папок.
'если таковое наблюдается на данной машине производим очистку корзины
If Err.Number <> 0 Then
zok = "Требуется очистка корзины!!!"
msb = "Для корректного обновления адресных книг требуется очистить папку ''Удаленные''." & vbLf _
& "Нажмите ''Ok'' для выполнения очистки в автоматическом режиме. Для очистки в ручном режиме " _
& "нажмите кнопку ''Oтмена'' (при этом операция обновления будет отменена). Данное окно " _
& "закроется автоматически через " & Otvet & " сек. (будет выполнена очистка в автоматическом режиме)."
mscl = objShell.Popup(msb, Otvet, zok, vbOkCancel+vbQuestion+VbSystemModal)
If mscl <= 1 Then
Set nsp = objOutlook.Session
Set oDeletedItems = nsp.GetDefaultFolder(olFolderDeletedItems)
Set oItems = oDeletedItems.Items
'ниже закомментирован код удаления элементов
'For i = oItems.Count To 1 Step -1
' oItems.Item(i).Delete
'Next
Set oFolders = oDeletedItems.Folders
For i = oFolders.Count To 1 Step -1
oFolders.Item(i).Delete
Next
Set nsp = Nothing
Set oDeletedItems = Nothing
Set oItems = Nothing
ElseIf mscl > 1 Then 'пользователь выбрал вариант ручной очистки корзины
msb = "Выбран вариант ручной очистки корзины. Очистите корзину вручную, перезапустите процесс обновления."
MsPop msb, 1, 3, "Отмена обновления", 2, 0
GoodBye
End If
End If
DelFol = 1
End If
Next
Set OldContactsFoder = Nothing
'Если версия Outlook меньше 2010 необходимо производить очистку корзины, иначе удаленная папка с
'контактами отображается в общем списке контактов
If Mof <=12 Then
For Each objOlFolders In OlDelFolder.Folders
'При перемещении папок в корзину к имени файла могут добавляться цифры
'поэтому процедуру удаления папок из корзины делаем отдельно
MyFoldOr = objOlFolders.Name
MyFoldTr = Left (MyFoldOr, Len(MyFoldOr) - 1)
If DeptName (MyFoldOr,"Ft",filtip) Or DeptName (MyFoldTr,"Ft",filtip) Then
Set OldContactsFoder = OlDelFolder.Folders(MyFoldOr)
'On Error Resume Next
OldContactsFoder.Delete
MsPop "Папка " & MyFoldOr & " удалена из корзины.", 1, 1, "Очистка корзины Outlook", 0, 1
DelFol = 1
Set OldContactsFoder = Nothing
End If
Next
End If
Stp = Stp + 1
Wend
'Проверяем корректность удаления папок
If FoldTest (0,"") Then
msb = "Обнаружена неудаленная папка: " & MyFolder & "Скрипт останавливается."
MsPop msb, 0, 0, "Оутглюк", 2, 0
GoodBye
End If
End Sub

'Процедура создания папок
'передаваемые параметры:
'filtip - тип файла адресных книг (0-подразделения, 1-контрагенты)
Sub FoldAdd(filtip)
'Создаем массив для подсчета добавленных контактов в каждом подразделении
KCount = DeptName("","Dl",filtip) - 1'подсчитываем количество подразделений
ReDim arrContExp(KCount, 1)
'Создаем пустые папки с именами заводов и ставим галочку чтобы они отображались в адресах,
'заодно заполняем массив значениями кода региона
'подключаем файл со списком подразделений как массив
'CSV:Код региона(0); Наименование региона(1);
y = 0
If Filtip = 0 Then
DeptFile = OrgDeptFile
Else
DeptFile = KonDeptFile
End If
Set FoldDeptCsv = objFSO.OpenTextFile(DeptFile)
Do While not FoldDeptCsv.AtEndOfStream
arrFoldDeptCsv = Split(FoldDeptCsv.Readline, ";")
Set NewFolder = ContOlFolder.Folders.Add(arrFoldDeptCsv(1))
NewFolder.ShowAsOutlookAB = True
MsPop "Создаем пустую папку " & NewFolder.Name, 1, 1, "Создание папок контактов в Outlook", 0, 1
'Проверяем создалась ли папка
WScript.Sleep 1000
If Not (FoldTest (1, NewFolder.Name)) Then
msb = "Не обнаружена созданная папка: " & NewFolder.Name & ". Скрипт останавливается."
MsPop msb, 0, 0, "Оутглюк", 2, 0
GoodBye
End If
arrContExp(y, 0) = arrFoldDeptCsv(0)
y = y + 1
Loop
FoldDeptCsv.Close
Set NewFolder = Nothing
Set FoldDeptCsv = Nothing
End Sub

'Процедура добавления контактов Outlook в папки подразделений (контрагентов)
'в процессе добавления производится подсчет числа добавляемых контактов
'передаваемые параметры:
'filtip - тип файла адресных книг (0-подразделения, 1-контрагенты)
Sub ContAdd(filtip)
If Filtip = 0 Then
ContFile = OrgContFile
Else
ContFile = KonContFile
End If
'Подключаем csv файл с контактными данными пользователей как массив
'CSV:Изменение(0);Регион(1);Фамилия(2);Имя(3);Отчество(4);Должность(5);
'Подразделение(6);Организация(7);Телефон(8);Мобильный телефон(9);E-mail(10)
MsPop "Производится запуск процесса добавления контактов.", 1, 1, "Добавление контактов в Outlook", 0, 1
Set ContCsv = objFSO.OpenTextFile(ContFile)
Do While not ContCsv.AtEndOfStream
'Построчно читаем csv в массив значений
arrContCsv = Split(ContCsv.Readline, ";")
Em = Instr(arrContCsv(10),"@")
CodReg = StrEdt(arrContCsv(1))
If Em <> 0 And DeptName(Codreg,"Ct",filtip) Then
Foldreg = DeptName(Codreg,"Cn",filtip)
Set NewContactsFoder = ContOlFolder.Folders(Foldreg)
'Создаем новый контакт
Set NewContact = objOutlook.CreateItem(2)
'проверяем условие:
'если адреса контрагентов - что заполнено организация или ФИО
'если ФИО делаем обычный контакт, если Организация - сокращенный вариант
With NewContact
If filtip = 1 And StrEdt(arrContCsv(2)) = "" Then
.FullName = StrEdt(arrContCsv(7))
ElseIf InStr(StrEdt(arrContCsv(2))," ") > 0 Then
'если поле Фамилия содержит пробелы (т.е. состоит более чем из одного слова)
'так же делаем сокращенный вариант
.FullName = StrEdt(arrContCsv(2))
Else
.FullName = StrEdt(arrContCsv(3)) & " " & StrEdt(arrContCsv(2)) ' & " " & StrEdt(arrContCsv(4))
.FirstName = StrEdt(arrContCsv(2))
'.MiddleName = StrEdt(arrContCsv(4))
.LastName = StrEdt(arrContCsv(3))
End If
MsPop "Добавлем контакт " & NewContact.FullName & " в папку " & NewContactsFoder, 1, 1, NewContact.FullName, 0, 2
.Email1Address = StrEdt(arrContCsv(10))
.JobTitle = StrEdt(arrContCsv(5))
.CompanyName = StrEdt(arrContCsv(6))
.BusinessTelephoneNumber = StrEdt(arrContCsv(8))
If Right(StrEdt(arrContCsv(9)),10) <> "" Then
.MobileTelephoneNumber = "+7 " & Right(StrEdt(arrContCsv(9)),10)
End If
.Move NewContactsFoder
.Save()
End With
Set NewContactsFoder = Nothing
Set NewContact = Nothing
'На версии Windows 8 в сочетании с версией Outlook 2010 требуется больше времени на запись контакта
'Почему? я сам так и не понял. Данная цифра - 200 милисекунд получена экспериментальным путем.
'При данном параметре все отрабатывает хорошо
If OsInf > 61 And Mof > 13 Then
'WScript.Sleep 300
End If
'Считаем добавленный контакт
For z = 0 To KCount
If arrContExp(z, 0) = Codreg Then
x = arrContExp(z, 1)
arrContExp(z, 1) = x + 1
End If
Next
End If
Loop
ContCsv.Close
Set ContCsv = Nothing
StartStop 2, 1
'Подводим итоги
msb = ""
For z = 0 To KCount
Codreg = arrContExp(z, 0)
Kont = arrContExp(z, 1)
If DeptName(Codreg,"Ct",filtip) Then
msb = msb & DeptName(Codreg,"Cn",filtip) & ": добавлено " & Kont & " контакта(ов)"
If z < KCount Then msb = msb & vbLf 'для красивого лога
End If
Next
MsPop "Добавление контактов успешно завершено!" & vbLf & msb, 1, 7, "Контакты добавлены!", 0, 0
End Sub

В процедуре добавления контактов есть блочок:

If OsInf > 61 And Mof > 13 Then
'WScript.Sleep 300
End If


Если я ставлю WScript.Sleep значение 700 то в принципе все отрабатывает и контакты добавляются, но у меня больше 300 контактов сотрудников и процедура занимает несколько минут. При том что у меня на ХР с 2003 офисом и полудохлым компом все пролетает за 30 сек. Первоначально на 8 возникали проблемы с подключением к объекту Outlook, вставил паузу вроде стало отрабатывать, тут эта проблема появилась...
Вообще я в программировании не очень силен, поэтому сразу извиняюсь если где косяк увидите...

Iska
22-01-2014, 10:09
Я хз... почему но с 'первого прохода все папки не удаляются, поэтому процедура загнана в цикл »
Попробуйте поменять:
For Each objOlFolders In ContOlFolder.Folders
на нечто наподобие:
For i = ContOlFolder.Folders.Count - 1 To 0 Step -1

DaffiSmik
22-01-2014, 10:35
Iska, Спасибо, учту, на всякий пожарный выкладываю весь скрипт целиком, если это поможет решению вопроса было бы здорово. В конечном итоге по большому счету все работает, кроме некоторых нюансов, все равно думал публиковать это решение с подробным описанием, вдруг кому пригодится, да все руки не доходят никак...
Да, еще пробовал ставить счетчик контактов, потом завершать скрипт по записи определенного количества контактов (50,100,150) при этом полностью убрал паузы после записи контакта, получилось что 114 записей производится без вопросов, а дальше не пишется, хотя подсчет контактов идет верный и в массив они пишутся и запоминаются. Попробовал вставлять увеличенную паузу по записи определенного количества контактов (25, 50, 100), слабо помогло часть контактов все равно не записалась, хоть время работы скрипта и сократил... Такое ощущение что сам Outlook не успевает их сохранять.

Iska
22-01-2014, 11:14
DaffiSmik, ну, я лично — пас, поскольку:
На версии Windows 8 в сочетании с версией Outlook 2010
ни того, ни другого нет в наличии.

DaffiSmik
22-01-2014, 11:39
:) просто уже который день гуглю, на мсдн была информация что много поменялось в работе с объектами Outlook начиная с 2010, а все примеры на vb.net и С++ но так как не программист то это для меня вообще темный лес и у меня есть подозрение что я неправильно работаю с объектом Outlook потому у ерунда такая получается...
у меня же была более старая версия этого скрипта, которая отрабатывала замечательно, но была беда в том что по заданию планировщика сама 8-ка не давала прав на работу с объектом оутлок, ну и соответственно скрипт запускаемый по расписанию не отрабатывал... О, пока писал, идея появилась... в голове, сейчас сравню скрипты...
Попробовал, действительно секунд за 20 выполнилось и все контакты на месте... так полез копать в чем беда... горе от ума...

DaffiSmik
22-01-2014, 12:48
Ага нашел проблему:
во всех операционных системах до 8.
перед началом работы с Outlook, он закрывался следующей командой:
Set objOutlook = CreateObject("Outlook.Application")
objOutlook.Quit
после чего объект создавался вновь командами:
Set objOutlook = CreateObject("Outlook.Application")
Set objNameSpace = objOutlook.GetNamespace("MAPI")
Set ContOlFolder = objNameSpace.GetDefaultFolder(10)
Set OlDelFolder = objNameSpace.GetDefaultFolder(3)
и производилось обновление контактов.
в 8-ке, если Outlook был запущен, команда выхода приведенная выше не отрабатывала (при условии что задание обновления запускается из планировщика, если запускать скрипт вручную то все отрабатывает нормально)
соответственно следующая команда создания объекта приводила к ошибке и скрипт не выполнялся.
Тогда я добавил блок:
If OsInf > 61 Then 'Если версия Windows 8.0 и выше срубаем Outlook
objProc.Terminate
Else ....
при таком раскладе объект создается но как следствие возникает проблема с записью контактов.
Соответственно вопрос: как в 8-ке корректно закрыть работающий Outlook?
Если Outlook работает при выполнении команды Set objOutlook = CreateObject("Outlook.Application") скрипт вываливается по ошибке.
Есть еще какие-то варианты корректного закрытия Outlook?

DaffiSmik
23-01-2014, 13:05
Спасибо всем кто принимал участие :) разобрался окончательно и решил проблему.
Действительно проблема была в неправильном закрытии Outlook'a - как следствие добавленные контакты и не сохранялись, что абсолютно логично (странно что сам этот момент не сразу понял). Решил проблему следующим способом - непосредственно перед запуском процедуры закрытия вставил счетчик, поправил скрипт в процедуре закрытия:
If OsInf > 61 And NumStart = 0 Then 'Если версия Windows 8.0 и это первый запуск, срубаем Outlook
objProc.Terminate
NumStart = NumStart + 1
WScript.Sleep 10000
Else
Set objOutlook = CreateObject("Outlook.Application")
objOutlook.Quit
End If
Теперь получается если Outlook был открыт, первый раз он просто срубается, а в последующем создаваемый объект работает уже корректно и закрывается корректно, все записи сохраняются. Если был закрыт то создание объекта ошибок не вызывает.

Вопрос еще такой интересен ли сам скрипт кому-нибудь и имеет ли смысл его выкладывать и описывать?

zhuk09
07-04-2017, 14:56
интересен ли сам скрипт кому-нибудь и имеет ли смысл его выкладывать и описывать? »
Понимаю что топику уже более 3-х лет, но может все таки выложите сюда полный скрипт с описание??!))
За ранее благодарен..




© OSzone.net 2001-2012