Событие Закрытия Документа Word

Тема в разделе "Lotus - Программирование", создана пользователем Bob84, 23 дек 2013.

  1. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    Здравствуйте.
    Задача поставлена такая - открываем из клиента вордовский документ (по шаблону), при его закрытии спрашиваем пользователя нужно ли сохранить, если да то нужно в клиенте его определенным образом приатачить.
    На закрытии документа вызвать какой-то код не проблема (как например описано тут http://word.mvps.org/faqs/macrosvba/documentevents.htm ), но не знаю как в лотусе поймать событие закрытия документа в ворде.
    Пробовал писать что-то вроде
    Код (LotusScript):
    On Event Document_Close From worddoc Call test
    получаю сообщение об ошибке.
    Сделать на закрытии документа создание какого-то файла, по которому понять, что исходный был успешно сохранен, а в лотусе используя класс таймера ждать пока это не произойдет?
    Заранее спасибо.
     
  2. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.073
    Симпатии:
    299
    не используйте в Нотусе технологии от МС.
    или не используйте Нотус :D
    Для общего понимания:
    -то что вызывается из нотуса - это некий интерфейс к ворду
    -события кот. генерит ворд не обязаны транслироваться в Нотус
    -события лотусскрипта никак не связаны с системой от МС! (а именно их вы пытаетесь задейстовать)
    Интерактивная связка с МС инструментами сама по себе работает неустойчиво, а в случае интеграции - отвратительно

    Теперь вопрос по существу - зачем позволять пользователю взаимодействовать с вордом, иначе как распечатать?
    Существуют различные варианты вставки информации из Нотуса в ворд (или создания файлов др. формата - что более правильно)
     
  3. duchan

    duchan Well-Known Member

    Регистрация:
    20 сен 2006
    Сообщения:
    105
    Симпатии:
    2
    Для Bob84:
    On Event - применим ТОЛЬКО для встроенных классов Notes, так что применить для событий COM\OLE\свой_класс не получится... :(

    В качестве варианта попробуйте отслеживать дату\время изменения файла, как только файл меняется (будет сохранени) вы сможете это отследить.
    Остается вопрос с отслеживание завершения редактирования (закрытия) документа\приложения - тут без WinAPI уже не обойтись. :( Варианты - это отслеживать по PID процесса (сложно и не всегда корректно) или по заголовку окна (получать список всех окон и перебирая их искать в их заголовках имя Вашего файла). Если открываете через COM\OLE (CreateObject) то можно попробывать отслеживать "жизнь" этого объекта, если документ\приложение закроется то доступа к свойствам уже не будет и вы получите ошибку которую можно перехватить (данный вариант не пробывал сам, но выглядит жизнеспособно, проверять\эксперементировать надо) (учтите что в MS Excel, по крайней мере в "ранних" версиях до 2003 было что если ячейка активна\редактируется, то через COM объект становился не доступен - как сейчас не в курсе)

    В качестве примеров куски из "живого кода", так что учтите это (что кроме приведенного кода есть еще что-то) :)
    запуск приложения и получения его PID:
    Код (Text):
        Private Sub ShellAndWait ( Byval RunProg As String, AutoSave As Variant, Blocked As Variant )
    Dim StartInf As STARTUPINFO
    StartInf.cb = Len ( StartInf )
    RetVal = CreateProcessA ( 0&, RunProg , 0& , 0& , 1&, NORMAL_PRIORITY_CLASS , 0& , 0& , StartInf , ProcessInfo )
    PID = ProcessInfo.dwProcessId
    End Sub
    Код (Text):
    ' Проверка по PID'у
    tmpPID&=OpenProcess(PROCESS_QUERY_INFORMATION, 0&, PID)
    If tmpPID& <> 0& Then
    'приложение запущено
    Else
    'нет приложения
    End If
    Call CloseHandle(tmpPID&)
    End Function
    Код (Text):
    ' проверка по WindowCaption
    hWnd& = fEnumWindows(apiGetDesktopWindow(), Strleftback(Me.ppFileName, "."))
    If hWnd&<>0 Then
    'приложение запущено
    Else
    'нет приложения
    End If
    Код (Text):
        Private Function fEnumWindows(PhWnd As Long, Find As String) As Long
    Dim hWnd As Long, hWndLen As Long
    Dim hWndStyle As Long, strCaption As String

    hWnd = apiGetWindow(PhWnd, mcGWCHILD)
    Do While Not hWnd = 0
    strCaption = fGetCaption(hWnd)
    If Len(strCaption) > 0 Then
    hWndStyle = apiGetWindowLong(hWnd, mcGWLSTYLE)
    If hWndStyle And mcWSVISIBLE Then
    Capt$ = Ucase(fGetCaption(hWnd))
    If Instr(Capt$, Ucase(Find)) <> 0 Then
    Code%=0
    For i%=0 To hWndCount-1
    If hWndOld(i%)=hWnd Then Code%=1
    Next
    If Code%=0 Then fEnumWindows = hWnd
    End If
    End If
    End If
    ChildEnumWindow& = fEnumWindows(hWnd, Find)
    If ChildEnumWindow& <>0 Then fEnumWindows = ChildEnumWindow&
    hWnd = apiGetWindow(hWnd, mcGWHWNDNEXT)
    Loop
    End Function
    '----------------------------------------------------------------------------------------------
    Private Function fGetCaption(Hwnd As Long)
    Dim strBuffer As String
    Dim intCount As Integer
    strBuffer = String$(mconMAXLEN - 1, 0)
    intCount = apiGetWindowText(Hwnd, strBuffer, mconMAXLEN)
    If intCount > 0 Then
    fGetCaption = Left$(strBuffer, intCount)
    End If
    End Function
    '----------------------------------------------------------------------------------------------
    Private Function fGetClassName(Hwnd As Long)
    Dim strBuffer As String
    Dim intCount As Integer
    strBuffer = String$(mconMAXLEN - 1, 0)
    intCount = apiGetClassName(Hwnd, strBuffer, mconMAXLEN)
    If intCount > 0 Then
    fGetClassName = Left$(strBuffer, intCount)
    End If
    End Function
    ну и декларации с константами (может что и пропущу у меня там много констант)
    Код (Text):
    Private Const mcGWCHILD = 5
    Private Const mcGWHWNDNEXT = 2
    Private Const mcGWLSTYLE = (-16)
    Private Const mcWSVISIBLE = &H10000000
    Private Const mconMAXLEN = 255


    Type STARTUPINFO
    cb As Long
    lpReserved As String
    lpDesktop As String
    lpTitle As String
    dwX As Long
    dwY As Long
    dwXSize As Long
    dwYSize As Long
    dwXCountChars As Long
    dwYCountChars As Long
    dwFillAttribute As Long
    dwFlags As Long
    wShowWindow As Integer
    cbReserved2 As Integer
    lpReserved2 As Long
    hStdInput As Long
    hStdOutput As Long
    hStdError As Long
    End Type

    Type PROCESS_INFORMATION
    hProcess As Long
    hThread As Long
    dwProcessID As Long
    dwThreadID As Long
    End Type


    Declare Function RegCloseKey Lib "advapi32.dll" (Byval hKey As Long) As Long
    Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (Byval hKey As Long, Byval lpSubKey As String, phkResult As Long) As Long
    Declare Function RegOpenKeyEx Lib "advapi32" Alias "RegOpenKeyExA" (Byval hKey As Long, Byval lpSubKey As String, Byval ulOptions As Long, Byval samDesired As Long, phkResult As Long) As Long
    Declare Function RegQueryValueEx Lib "advapi32" Alias "RegQueryValueExA" (Byval hKey As Long, Byval lpValueName As String, Byval lpReserved As Long, lpType As Long, Byval lpData As String, lpcbData As Long) As Long

    Declare Function WaitForSingleObject Lib "kernel32" (Byval hHandle As Long, Byval dwMilliseconds As Long) As Long
    Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (Byval hwnd As Long, Byval lpOperation As String, Byval lpFile As String, Byval lpParameters As String, Byval lpDirectory As String, Byval nShowCmd As Long) As Long
    Declare Function CreateProcessA Lib "kernel32" (Byval lpApplicationName As Long, Byval lpCommandLine As String, Byval lpProcessAttributes As Long, Byval lpThreadAttributes As Long, Byval bInheritHandles As Long, Byval dwCreationFlags As Long, _
    Byval lpEnvironment As Long, Byval lpCurrentDirectory As Long, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
    Declare Function CloseHandle Lib "kernel32" (Byval hObject As Long) As Long
    Declare Function OpenProcess Lib "kernel32" (Byval dwDesiredAccess As Long, Byval bInheritHandle As Long,Byval dwProcessId As Long) As Long


    Declare Function apiGetClassName Lib "user32" Alias "GetClassNameA" (Byval Hwnd As Long, Byval lpClassname As String, Byval nMaxCount As Long) As Long
    Declare Function apiGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Long
    Declare Function apiGetWindow Lib "user32" Alias "GetWindow" (Byval Hwnd As Long, Byval wCmd As Long) As Long
    Declare Function apiGetWindowLong Lib "user32" Alias "GetWindowLongA" (Byval Hwnd As Long, Byval nIndex As Long) As Long
    Declare Function apiGetWindowText Lib "user32" Alias "GetWindowTextA" (Byval Hwnd As Long, Byval lpString As String, Byval aint As Long) As Long
    Declare Function ShowWindow Lib "user32" (Byval hwnd As Long, Byval nCmdShow As Long) As Long
    Declare Function BringWindowToTop Lib "user32" (Byval hwnd As Long) As Long

    P.S. для lmike: использовать или не использовать, глючит или не глючит - это холивар. Хотя, да согласен что применение сторонних приложений\модулей\технологий накладывает существенные ограничения как на реализацию, так и на мультиплотформенность. Но всегда необходимо исходить из релей задачи, анализируя потери, затраты и получаемый профит.
     
  4. garrick

    garrick Lotus team
    Lotus team

    Регистрация:
    26 окт 2009
    Сообщения:
    773
    Симпатии:
    50
    Если вы кликаете на приаттаченный файл MS Office, Lotus Notes вас спрашивает "Open", "Edit", etc. Если вы выбираете "Edit", то при закрытии файла Lotus Notes сам спрашивает надо ли сохранить изменённый аттачмент. Версия 8.5 с различными вариациями.
     
  5. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.073
    Симпатии:
    299
    DuChan искать инстанс можно и по имени файла, например так http://codeby.net/forum/threads/51696.html
    о целях/задачах - да, бывают разные, но сразу кидаться в "пучину" тоже не стоит :(
    у меня нет уверенности, что кусок из задачи, кот. описан выше, необходимо решать именно так, как описывает автор...
    вернее есть уверенность - что так не нужно :)
    если в результате нужно получить документ по шаблону - совершенно не обязательно предоставлять пользователю возможность корячить текст в ворде, ибо прозвучало слово шаблон
    как уже не раз описывалось (и не только здесь) - можно просто вставить куски текста из нотуса в шаблон ворда (если на выходе нужен именно ворд), этим - максимально отстранить пользователя от использования 2-ух инструментов одновременно (что само по себе "чревато")
     
  6. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    Спасибо за ответы.
    Для lmike - к несчатью именно так задача и поставлена, ждать пока пользователь не завершит работу с документом.
     
  7. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    DuChan
    т.е. проверку по PID или WindowCaption нужно загонять в цикл и ждать пока не закроется. Таким образом клиент будет висеть все это время. Может тогда лучше использовать таймер?
     
  8. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.073
    Симпатии:
    299
    Bob84 повторюсь - задача не корректна
    нельзя комфортно работать в 2-ух связанных приложениях, причем одно из них (нотус) из основного становится подчиненным!
    Зачем так делать?
    это просто хотелки начальства?
     
  9. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    Это даже не хотелки. Это ТЗ.
     
  10. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.051
    Симпатии:
    146
    Bob84
    Так в чем проблема тогда? garrick, все верно сказал.
    Если просто на поле расположить RT-поле, то в нем можно хранить файлы.
    При открытии будет спрашивать в каком режиме открывать, если файл будет изменен и пользователь скажет сохранить на диалог лотуса, он будет перезаписан в документ сам.

    Этот подход не подойдет - если у вас хранилище файлов отдельное.
     
  11. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    Хранилище отдельное, поэтому я больше склоняюсь к варианту DuChan.
     
  12. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.051
    Симпатии:
    146
    Bob84
    Печаль...
    Так как это отдельное хранилище, скорее всего и было сделано для того, чтобы отслеживать изменения файлов.
    Наверняка там есть фамилия автора, дата добавления и краткое описание.
    Следовательно надо будет это менять после сохранения. Еще наверняка не на каждом статусе при согласовании надо давать редактировать документ, а то вся целостность к чертям... Я конечно утрирую, но всякое бывает.
     
  13. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.073
    Симпатии:
    299
    Bob84 а огласить ТЗ можно?
    чета там очень мутно - непонятно зачем Нотус в это связке?
     
  14. erdi

    erdi Well-Known Member

    Регистрация:
    20 авг 2008
    Сообщения:
    261
    Симпатии:
    36
    в копилку бредовых идей....как-то возникала, но так в качестве одного из вариантов и осталась
    при открытии документа - модифицировать его, т.е. добавлять ему макрос на закрытие
    в этом макросе, опять же, все через тот же ком дергать лотус-документ и модифицировать его. т.к. макрос будешь добавлять через код, то и соответственно в код уже программно заложишь uid документа, который необходимо модифицировать. в случаи если лотус открыт - пароль не потребуется вводить
    но это грабли, грабли и еще раз грабли - Программирование как секс. Одна ошибка - и ты должен поддерживать её всю оставшуюся жизнь
     
  15. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.073
    Симпатии:
    299
    savl следуя нормальной логике...
    -откуда заполняется шаблон - если из Нотуса, то зачем интерактив
    -если конечный док кладется в Нотус - то зачем еще и хранилище

    Добавлено: я до сих пор не пойму - что мешает вести документооборот в Нотусе, а результат, коли это так надо, рендерить в ворд, по шаблону?
     
  16. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.051
    Симпатии:
    146
    Это не баг - это фича :)

    lmike
    Я только сейчас понял что речь про шаблоны.
    Это кстати, действительно глупо... Можно тянуть все в word из формы, это факт и потом сразу крепить.
    Это если он кладется в лотус, хранилище лотусовое именно.
    Но видимо "эффективные менеджеры" решили, что это долго и написать "костыль", чтобы док крепился сам - проще и быстрее.
    А вот дает подозрение, что хранилище не лотусовое.
    В лотусе док содержит meta-ссылку, отображается этот док во встроенном представлении.
    При открытии идет обработка ссылки через технологию хранилища и открывается док, который сохраняется в temp.
    Я такое видел, на прошлом месте, там исторически сложилось + большой объем документов, свыше 1 млн действующих договор с дополнениями, актами, протоколами и так далее.
     
  17. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    Хранилище лотусовое, постановка из ТЗ
    При нажатии на кнопку для формирования соответствующего документа, открывается файл формата MS Word, заполненный автоматически данными из текущего документа. Пользователь может внести изменения в файл.
    Затем при закрытии сформированного файла выдается сообщение "Сохранить файл в системе?" с вариантами ответа "Да"/"Нет". При выборе ответа "Да", сформированный документ сохраняется в БД Хранилище эл. образов и отображается в списке вложений текущего документа. При выборе варианта "Нет" файл не сохраняется в системе.
     
  18. Bob84

    Bob84 Active Member

    Регистрация:
    16 май 2012
    Сообщения:
    38
    Симпатии:
    0
    Через COM разве не на бэкенде только можно работать с лотусом? А в моем случае нужно с фронтэндом работать.
     
  19. erdi

    erdi Well-Known Member

    Регистрация:
    20 авг 2008
    Сообщения:
    261
    Симпатии:
    36
    в макросе, допустим создание документа по форме и заполнением поля uid документа, который должен быть открыт(из которого открыли word документ). В форме на postopen по этому полу получение uidoc открытого документа
    Set notesUIDocument = notesUIWorkspace.EditDocument( [editMode] , [notesDocument] , [notesDocumentReadOnly] , [documentAnchor$] , [returnNotesUIDocument] , [newInstance] ) - newInstance=true тогда если док открыт - ты получишь этот объект и тогда уже можешь делать с ним что хочешь

    посмотри базу Microsoft Office Library (doclbm7.ntf) может ее тебе будет достаточно или хотя бы принцип работы позаимствуешь
     
  20. erdi

    erdi Well-Known Member

    Регистрация:
    20 авг 2008
    Сообщения:
    261
    Симпатии:
    36
    а вообще задача какая-то карявая....
    данные хранятся в лотус - формируется word из шаблона - правится инфа в word и надо уже не данные измененные вложить, а некий файл...а как же данные, которые в лотус?
    не проще ли после сформированного word файла(желательно сохранить не в формате doc, а в rtf, т.к. rtf всеже текст, а не бинарный формат) и потом импортировать этот документ в лотус
    Код (LotusScript):
        Dim ws As New NotesUIWorkspace
    Dim uidoc As NotesUIDocument
    Set uidoc = ws.CurrentDocument
    Call uidoc.GotoField("Body")
    Call uidoc.Import("Microsoft RTF", "c:\123.rtf")
    тем-самым получишь правильно заполненный формат документа, который можно редактировать, но при этом все это уже лежит он в лотус, а на close документа можешь уже повторно выгружать данные в файл и атачить куда угодно в хранилище
    в такой связке даже ком не потребуется....все можно сделать на сервере
     
Загрузка...
Похожие Темы - Событие Закрытия Документа
  1. NickProstoNick
    Ответов:
    2
    Просмотров:
    649
  2. vadpetr
    Ответов:
    0
    Просмотров:
    1.144
  3. Мыш
    Ответов:
    1
    Просмотров:
    1.094
  4. Num2
    Ответов:
    0
    Просмотров:
    1.305
  5. programmer8329
    Ответов:
    4
    Просмотров:
    2.330

Поделиться этой страницей