Макрос для конвертирования calc документа в pdf, защищенный паролем

Автор Mika_89, 28 марта 2011, 23:38

0 Пользователи и 1 гость просматривают эту тему.

Mika_89

Здравствуйте! нужен макрос, который будет конвертировать документ calc в pdf, причем pdf должен получатся защищенным паролем, и не случайным, а заранее заданным. Пожалуйста подскажите где взять или как примерно написать.

JohnSUN

Привет!
Сам макросы уже пишешь? Я не подкалываю, просто уточняю насколько подробно нужно ответить:
1. Если не пишешь, то нужно написать код и рассказать "что в нём как"
2. Если просто не знаешь названия параметров фильтра для ExportToPDF (EncryptFile и DocumentOpenPassword), то достаточно правильной ссылки на Вики
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Mika_89

Нет, не пишу еще.. вот только недавно дали такое задание, надо разбираться

JohnSUN

А, тогда рассказываю пошагово... В моем рассказе будет попадаться явная ерунда, но это станет понятно только когда всё будет сделано.
1. Открываем офис и создаем пустую электронную таблицу. В клетке A1 пишем хоть что-нибудь (совсем пустую книгу экспортировать в PDF сложно  ;D). Я, например, написал три единички - 111
2. Если работаем с LibreOffice... Хотя нет! В любом случае сначала лезем в Параметры и убеждаемся, что возможность записи макросов включена (подробности - здесь).
3. Выбираем из меню Сервис - Макросы - Записать макрос. Панелька Запись макроса с единственной кнопкой Завершить запись обычно повисает в удобном месте, чтобы не мешать. Если мешает, то просто оттаскиваем в сторону (не за край экрана), но не закрываем! Закроем позже.
4. Выбираем из меню Файл - Экспорт в PDF. Можно попробовать задавать здесь параметры экспорта, но не обязательно - всё-равно все они автоматически в макрос не попадут, придется руками дописывать. Нажимаем кнопку Экспорт, подтверждаем, что "Без имени 2" - нормальное имя для нашего PDF... Само собой, цифра может быть другой. (Просто у меня в "Без имени 1" набирается текст этого сообщения и других открытых документов нет)
5. Вот теперь можно нажимать Завершить запись и сохранять нашу заготовку макроса.
6. Сам процесс сохранения не сложен, самое трудное в нем - выбрать правильное место для записи. Ну, и имя макроса придумать.
Правильным местом для макроса будет библиотека Standard. Трудность в том, что этих самых Standard'ов мы видим в дереве библиотек как минимум два и важно выбрать тот, который Мои макросы - Standard, а не Без имени 2 - Standard. Документ мы сейчас закроем, а макрос сохранится в библиотеке офиса, не пропадет.
Правильное имя для макроса мало того что должно быть короткое и ёмкое (чтобы не сразу забыть, что этот макрос делает), так еще и латинскими буквами. Например, PDFvsPWD. Или ExportToPDFwithPassword? Мне первый вариант больше нравиться, меньше писать.
И еще один момент. Макрос пишется не прямо в библиотеку Standard, а в модуль внутри этой библиотеки. Я стараюсь для каждого нового проекта создавать отдельный модуль - меньше потом приходится листать код вверх-вниз разбираясь где наш новый макрос, а где какой-то старый код.
Нажимаем Новый модуль (в справке его назвали Создать модуль, но это не повод справку не читать), вводим имя модуля... Говоришь, "недавно дали такое задание"? Так модуль и обзовем - Zadanie. Ну и имя макроса в поле вверху слева вписываем, вместо Main
7. Самое сложное позади, осталась сущая ерунда! Жмем Alt+F11, выбираем наш макрос PDFvcPWD и нажимаем Редактировать. Приводить здесь полный текст того что получилось не буду - он у нас должен быть одинаковым: начинаться с sub PDFvcPWD, заканчиваться end sub, а между ними строк двадцать невменяемого кода и непонятных комментариев.
8. Начнем с упрощения кракозябр. Первая строка непонятных символов должна начинаться со слов args1(0).Value = "file:///... Нашел? Это так задается путь к Мои документы (или куда ты там сохранял наш почти пустой PDF?) и его имя в URL-нотации (читай в Справке в разделе Глоссарий терминов Интернета в самом низу). Меняем эту длинную строку на простую и понятную:
args1(0).Value = ConvertToURL(fName) и сразу же дописываем этот fName в заголовок процедуры
sub PDFvcPWD(fName As String)
8. В самом начале модуля у нас должна сейчас быть пустая процедура Main. Уже удалил? Не страшно, напишем новую:

Sub Main
    PDFvcPWD("C:\TestPDF.pdf")
End Sub

Путь к тестовому PDF лучше, конечно, в корень системного раздела не направлять - мало ли какую ошибку в макросе допустить можем! Замучаемся систему восстанавливать. Создадим отдельную папку для тестовых файлов и укажем путь до нее...
9. Alt+Tab - переключаемся в нашу почти пустую книгу "Без имени 2". Alt+F11 - выбираем макрос Main, жмем Выполнить. Проверяем, что PDF с колонтитулами и тремя единичками создался нормально. О! Первая победа! Это можно было и не делать, но если по ходу конструирования макроса не запускать его время от времени и не радоваться, что он делает всё больше и больше и делает это правильно, то какой смысл вообще программировать?

(Упс... Вынужден прерваться на некоторое время.
Поэтому конспективно: следующие шаги это - просмотреть длиннющую строчку args1(2).Value = Array(Array("UseLosslessCompression", обращая внимание на слова в кавычках и находя их в Вики, пока не доберешься до "DocumentOpenPassword",0,"". Потом ставишь несколько экспериментов с заменой нуля и пустых кавычек, дополняешь список параметров процедуры параметром sPWD и добавляешь его в вызов процедуры из Main. Сдаешь работу и возвращаешься на форум, чтобы начинать консультировать новичков в программировании на бэйсике)
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Mika_89

Спасибо огромное за консультацию)) теперь знаю с чего начать) ну что, займусь делом)))

Mika_89

Кажется это получилось) еще раз спасибо!
Но к сожалению это еще не всё.. в общем такая проблема:
Мне надо вызвать этот макрос из приложения (из агента Lotus Notes), т.е. я с помощью этого агента открываю openoffice calc, формирую отчет в формате с названием Отчет_2011.02.xls, сохраняю его на диск (вот эта часть сделана) а дальше уже надо конвертировать его в pdf, с таким же названием. Как же вызвать макрос, который конвертирует в pdf?    

Вот так я создаю и сохраняю calc документ :
Dim SM As Variant
Dim Desktop As Variant
Dim calApplication As Variant
Dim worksheet As Variant
Dim args() As Variant

   Set SM = CreateObject("com.sun.star.ServiceManager")
   Set Desktop = SM.createInstance("com.sun.star.frame.Desktop")      
   Set calApplication =Desktop.loadComponentFromURL("file:///"+strOutputFN, "_blank" , 0 ,args)
   Set worksheet = calApplication.Sheets.getByIndex(0)

       ....
      'далее заполняю ячейки данными
      'strOutputFN - это путь сохранения на диске
       ...

    CalApplication.Store   
    Desktop.Terminate

Mika_89

Попытки написать что-то похожее на:

Set oDisp = createUnoService("com.sun.star.frame.DispatchHelper")
sMacroURL = "macro:///Standart.Zadanie.PFDvsPSW"
oDisp.executeDispatch(StarDesktop, sMacroURL, "", 0, mNoArgs())
   
не увенчались успехом (((

JohnSUN

Не спеши! Я же предупреждал, что большая часть моих советов в конце концов окажется сущей ерундой и потребует переосмысления... Или тебя сроки поджимают?

strOutputFN вижу. Покажи еще и переменную с паролем
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Mika_89

А переменная с паролем используется в макросе, в коде агента она не применялась... или я не понимаю чего...
а сроки пока не сильно поджимают) есть время поразбираться

Рыбка Рио

Отсюда:
(пароль permission)

REM  *****  BASIC  *****
Dim oExpFilterOptions

Sub Main
CheckPDFFilterProperties
DoExport
End Sub

Function MkPropVal( Optional cName As String, Optional uValue ) As com.sun.star.beans.PropertyValue
       Dim oPropertyValue As New com.sun.star.beans.PropertyValue
       If Not IsMissing( cName ) Then
               oPropertyValue.Name = cName
       EndIf
       If Not IsMissing( uValue ) Then
               oPropertyValue.Value = uValue
       EndIf
       MkPropVal() = oPropertyValue
End Function

Sub DoExport
' now export it
       oExpOptions = Array(_
                       MkPropVal( "FilterName", "calc_pdf_Export" ),_
                       MkPropVal( "FilterData",  oExpFilterOptions )_
                       )

       oDoc = ThisComponent
       aURL = oDoc.getLocation()
       aURL = aURL + "-macro.pdf" ' add a pdf file type
' Save the document in the new destination format.
       oDoc.storeToURL( aURL, oExpOptions )
end sub

Sub CheckPDFFilterProperties()
' test the filter properties, using the current document as document
' to export
' prepare export filter options, specify only the different from default
' if the options is not specified the application default will be used
' if no filter option is given (e.g. no FilterData property), the last user setting will be used
' see spec for details
' to test: get the name from the specification (or manual ?)
' from their name build a property array
' check the value of any of them and see in acro reader how they behave
' the following is a test setting
       oExpFilterOptions = Array(_
               MkPropVal( "InitialView", 0 ),_
               MkPropVal( "PageLayout",  0 ),_
               MkPropVal( "UseTaggedPDF",  False ),_
               MkPropVal( "EncryptFile",  True ),_
               MkPropVal( "DocumentOpenPassword",  "open" ),_
               MkPropVal( "RestrictPermissions", True ),_
               MkPropVal( "PermissionPassword",  "permission" ),_
               MkPropVal( "Printing",  24 ),_
               MkPropVal( "Changes", 4  ),_
               MkPropVal( "EnableCopyingOfContent",  True ),_
               MkPropVal( "EnableTextAccessForAccessibilityTools", True  )_
               )
       DoExport
End Sub
ubuntu 12.04 + LibO3.6.0

Mika_89

И вам большое спасибо за код!
только как все-таки его программно вызвать из другого приложения ???

JohnSUN

Цитироватьа сроки пока не сильно поджимают) есть время поразбираться

Ты даже представить не можешь, как меня этим порадовала! Просто ненавижу прописную истину: "Никогда нет времени, чтобы сделать хорошо с первого раза, но всегда найдется время, чтобы восемь раз переделать" ("Законы Мерфи", переврано по памяти)

В таком случае можем перейти к следующему шагу - наплевать и забить забыть.
Что я имею в виду? То что было проделано вчера и сегодня утром - это только первый подготовительный шаг. Когда опыт программирования накопится, его можно будет быстренько прокручивать в уме и ничего не делать руками. Но без него дальнейшая работа над макросом не имеет смысла. Главное, чего мы достигли - убедились, что задача имеет решение, что оно будет простым, что сделать требуемое будет не сложно. Без этой уверенности писать код совершено бесполезно - вдохновение не придет. А без вдохновения будет рожден уродец, которым никто не захочет пользоваться.
А так у нас есть уверенность, что будущей программе обеспечена долгая и плодотворная жизнь. И чтобы эта жизнь была правильной, открываем редактор макросов, переходим в модуль Zadanie, и жмем волшебную кнопку (см. рисунок). Дело в том, что сейчас от первоначального варианта мало что останется, а возможность вернуться каждый обеспечивает себе сам ("Программисты делятся на две категории: на тех, кто никогда не делает резервных копий, и на тех, кто уже делает...")
И приступаешь к медитации.
Прямо с первой строки модуля начинаешь писать:
REM  *****  BASIC  *****
REM ConvertSpreadsheetToPDF - макрос, сохраняющий содержимое электронной таблицы Calc в PDF-файл
REM © Имя фамилия aka Mika_89, город, страна, 2011
REM Данная библиотека является свободным программным обеспечением.
REM Вы вправе распространять ее и/или модифицировать в соответствии
REM с условиями версии 3 либо по вашему выбору с условиями более
REM поздней версии Стандартной Общественной Лицензии Ограниченного
REM Применения GNU, опубликованной Free Software Foundation.
REM
REM Эта программа распространяется в надежде, что она будет полезной,
REM однако БЕЗ ПРЕДОСТАВЛЕНИЯ КАКИХ-ЛИБО ГАРАНТИЙ, в
REM том числе ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ.
REM Для получения более подробной информации ознакомьтесь со Стандартной
REM Общественной Лицензией Ограниченного Применений GNU.
REM Вместе с данной библиотекой вы должны были получить экземпляр Стандартной
REM Общественной Лицензии Ограниченного Применения GNU. Если вы его не получили,
REM то можете получить текст по адресу http://www.gnu.org/licenses/
REM

Дальше желательно то же самое на английском. И нечего ухмыляться! Не пройдет и двух лет, а твой код уже будут читать где-нибудь в Австралии.
Потом добавляешь строчку
REM mailto:mashunya.89@bk.ru
(Надо же! Только на этом месте я полез в твой профиль и понял, что говорю не с Михаилом, а с Марией!)
ЭТО НУЖНО ДЕЛАТЬ ОБЯЗАТЕЛЬНО! Ты же не хочешь, чтобы строгие дяденьки со стальными глазами наехали на тему "Вы пользуетесь не лицензионным ПО!"?
Потом крайне желательно вписать две строки:

Option Explicit ' Все переменные объявляются явно через "Dim".
Option Base 0 ' Индексация каждого массива начинается с нуля

Вообще-то явных массивов у нас не предвидится, то что потребуется опишем через вызов Array(). Но эти строчки дисциплинируют, ограничивают возможности написать плохой код.
А теперь самый важный этап медитации. Если весь предыдущий текст еще можно копипастить из модуля в модуль с небольшими изменениями, то то что начнется сейчас - уникально:

REM Модуль открывает в OOo Calc файл любого доступного формата (ODF, Excel и др.)
REM и помещает его содержимое в PDF-файл с тем же именем и по тому же пути.
REM Файл при необходимости защищается паролем.

Тут в чем фишка? Пока ты всё это пишешь, подсознание продолжает утрясать подробности задачи, а руки набирают темп. Опять же, когда излагаешь решаемую задачу, она становится яснее и понятнее.
Например, по ходу описания понимаешь, что один и тот же макрос может использоваться и для парольных PDF, и для "беспарольных"... Достаточно будет в параметрах указать, что sPWD это параметр Optional. Следующее озарение - путь и имя файла тоже не обязательные! Можно же вызвать этот макрос на выполнение и прямо из открытого документа... И т.д.

И опять - Упс! Клио уже дал решение...
"Give a man a fish and he will eat for a day. Teach a man to fish and he will eat for the rest of his life..."
Ну, значит прямо от медитации перескакиваем на редактирование макроса - сдираем код и вставляем его вместо наших вчерашних потуг. Возвращаемся к заголовку модуля и вносим Клио в соавторы...
Цитата: Mika_89 от 30 марта 2011, 14:46
А переменная с паролем используется в макросе, в коде агента она не применялась... или я не понимаю чего...
Ну, про это в последнем абзаце про медитацию. По ходу обдумывания задачи понимаем, что паролей может быть три: самое простое - отсутствует, посложнее - наглухо вписан в код макроса и не меняется, самый интересный - каждый раз разный, каким-то образом получается по ходу выполнения макроса... Но это уже, похоже, не имеет значения

[вложение удалено Администратором]
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

JohnSUN

Цитата: Mika_89 от 30 марта 2011, 15:54
только как все-таки его программно вызвать из другого приложения ???
Я с DOSовских времен не трогал Lotus Notes руками. Но не думаю, что за это время из него убрали возможность выполнить команду операционной системы... А дальше - не сложно
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Рыбка Рио

Цитата: Mika_89 от 30 марта 2011, 14:54только как все-таки его программно вызвать из другого приложения
Вы имеете ввиду другое приложение офиса / другая библиотека с макросами? Макрос можно хранить либо Мои макросы, либо Макросы OpenOffice.org (LibreOffice)) (, но не в документе, т.к. в документе всё что указывает на ThisComponent указывает на тот же документ, в котором хранится макрос). Если нужный макрос хранится, к примеру, в библиотеке PasswordPDF, то, наверное, можно так:

Sub Main
Globalscope.BasicLibraries.LoadLibrary( "PasswordPDF" )
PasswordPDF.Module1.Main
End Sub


Если в библиотеке Standard, то строчка
Globalscope.BasicLibraries.LoadLibrary( "Standard" )
не нужна, т.к. эта библиотека загружается автоматически при запуске офиса, поэтому, кажется, можно вызвать так:

Sub Main
'Globalscope.BasicLibraries.LoadLibrary( "Standard" )
Module1.Main
End Sub


upd:
ещё так:
REM  *****  BASIC  *****

Sub Main
scriptUri = "vnd.sun.star.script:PasswordPDF.Module1.Main?language=Basic&location=application"
scriptProvider = ThisComponent.ScriptProvider
script = scriptProvider.getScript(scriptUri)
script.invoke(array(), array(), array())
End Sub

ЦитироватьSubs and Functions are public in OOoBasic. And you should not have the same name for a Sub or Function in different modules (to avoid ambiguities and bugs).
ubuntu 12.04 + LibO3.6.0

Mika_89

надо вызывать из Lotus Notes (из агента), думаю вариант с командной строкой подойдет. еще раз спасибо за подробные и развернутые ответы))