VBA для тех кто любит думать

         

Открытый и закрытый коды


Наверняка все слышали такие фразы: "Шифрование с открытым ключом", "Шифрование с закрытым ключом", "Публичный ключ". О том, что они означают, можно писать большие книги, однако стоит вкратце описать ситуацию для полноты изложения. 

При шифровании с закрытым ключом для кодирования и расшифровки используется одна и та же последовательность символов в качестве пароля - ключа. Пример - тот, что описан выше. При шифровании же с открытым ключом используются две последовательности символов, причем зашифрованное с помощью первой последовательности можно расшифровать только с помощью второй, и наоборот. Обе последовательности связаны между собой по определенному закону, при этом из второй последовательности можно получить первую, но из первой вторую не узнаешь, - обратное преобразование невозможно.

Сгенерировав специальной программой пару таких последовательностей (называемых ключами), можно первую из них сообщить тому, от кого ждешь секретных посланий ("сообщить ему публичный ключ"), а вторую оставить себе и хранить как зеницу ока ("оставить себе секретный ключ"). То, что будет зашифровано отправителем этим публичным ключом, даже сам отправитель расшифровать не сможет. Это сможет сделать только обладатель секретного ключа.

Другое применение шифрования с открытым ключом - это электронная подпись, назначение которой - подтверждать неизменность электронного текста при пересылке или хранении. При ее использовании рассчитывается контрольная сумма (скажем, сумма всех кодов букв) сообщения, а затем она шифруется секретным ключом. Любой, у кого есть второй (публичный) ключ из этой пары, может расшифровать ее и, рассчитав самостоятельно контрольную сумму пришедшего сообщения, сравнить полученную величину с расшифрованной. При несовпадении этих двух величин можно думать о несанкционированном изменении текста сообщения в процессе пересылки.

Именно на таком принципе работает механизм шифрования PGP.

*       *       *

Ответы на вопросы


Эта книга написана по мотивам цикла статей "Начала программирования на VBA", публиковавшегося в журнале "Мир ПК" в 2000-2001 годы. После публикации статей цикла мне пришло немало писем с различными вопросами о программировании. Ниже представлены ответы на наиболее интересные из них.

1.

"В документе я хочу защитить от изменений пользователем только рисунок. Могу ли я это сделать? Метод Protect, похоже, этого сделать не дает."

Нет. Microsoft Word делать это не позволяет.

Впрочем, можно пойти на хитрость. Создайте документ Doc1.doc и вставьте в него рисунок. Затем сохраните документ с рисунком, задав ему пароли на открытие и на изменения. Создайте документ Doc2.doc. В том месте, где должен быть рисунок, вызовите окно Вставка-Обьект-Создание из файла и укажите в пути файл doc1.doc, отметив предварительно пункт "Связь с файлом". Введите пароль на открытие - и рисунок в Вашем документе. Сохраните его.



Теперь при открытии файла doc2.doc рисунок будет виден, но при попытке изменить его будет запрашиваться пароль на открытие файла doc1.doc. Проблема остается в том, что оба файла - и с рисунком, и с текстом - должны присутствовать, причем в тех местах, где они были изначально. То есть вся эта конструкция труднопереносима.

2.

"Возможно ли в Word проводить сравнение двух документов по словам..."

Да, разумеется. Откройте один из сравниваемых документов, выберите пункт меню "Сервис"-"Исправления"-"Сравнить версии" и выберите в открывшемся диалоговом окне второй файл для сравнения. Все разночтения будут выделены, в зависимости от их характера - зачеркиванием, цветом и др.

3.

"Как можно узнать количество страниц в Word2000  из макроса?"

С помощью команды

p = ActiveDocument.ComputeStatistics(wdStatisticPages)

где в переменную p запишется количество страниц в активном документе.

4.

"Сделал документацию на свою VBA-программу в Word 97 в doc-файле.


Включил в нее screenshot'ы, на которые наложил автофигуры Word - выноски, стрелки, скобки, надписи и проч., что разъясняло бы назначение частей рисунков. Теперь хочется поставлять документацию в формате HTML, но... при конвертации Word начисто игнорирует свои же автофигуры, оставляя в итоговых gif-файлах чистый рисунок. Как цивилизовано выйти из ситуации?"

Да, автофигуры Word97 при конвертации в HTML игнорируются. Для реализации желаемой Вами задачи выделите все автофигуры рисунка вместе с самим рисунком (инструментом "Выделение обьектов" панели "Рисование"), сгруппируйте их, вырежьте в Буфер обмена, а затем вставьте то, что в буфере, на то место, где был исходный рисунок, с помощью команды "Правка"-"Специальная вставка", используя в качестве формата вставляемого изображения "Точечный рисунок" или "Метафайл Windows", т.е. что угодно, кроме "рисунка MS Office". После этого у Вас в документе появится рисунок с всеми вставленными автофигурами, который, однако, спокойно конвертируется в GIF-формат при конвертации всего документа в HTML. Так следует поступить со всеми рисунками в документе. В Word2000 и Word2002 такой проблемы нет – там автофигуры сохраняются в самой генерируемой web-странице, но при просмотре ее в старых браузерах могут быть не видны.

5.

"Можно ли Word 2000 убрать автоматический запуск панели "Буфер обмена"?"

Вообще говоря, там встроен "интеллектуальный" механизм, который больше не отображает панель после того, как пользователь ее закроет несколько раз. Сделать так, как Вы желаете, можно, если использовать макросы.

Макрос для полного скрытия панели:

Sub clipboard_hide()

CommandBars("Clipboard").Enabled = False

End Sub

Макрос для показа панели:

Sub clipboard_show()

CommandBars("Clipboard").Enabled = True

CommandBars("Clipboard").Visible = True

End Sub

Назначьте этим макросам кнопки и используйте их.



К счастью, в Word XP эта рекомендация уже неактуальна - там Область задач с вкладкой "Буфер обмена" вызывается только тогда, когда дважды нажата комбинация клавиш Ctrl+C.

6.

"Как определить с помощью макроса в документе Word текущий номер страницы, где произошло при поиске вхожение заданной подстроки."

Существуют функции Selection.Information(wdActiveEndPageNumber), которая возвращает номер страницы по счету, на которой располагается конец выделения, и функция Selection.Information(wdActiveEndAdjustedPageNumber), которая возвращает присвоенный номер страницы, на которой располагается выделенный фрагмент. Вторую функцию следует использовать тогда, когда необходимо получить тот номер страницы, который указан на ней непосредственно (т.е. с учетом ручных установок нумерации), а первую - если номер необходим абсолютный. Описание обеих команд можно получить в Справке VBA по слову Information.

При работе подпрограммы поиска каждое вхождение выделяется. Вот, к примеру, фрагмент кода макроса, который отображает в диалоговом окне номера страниц, на которых найден текст "text".

Selection.HomeKey Unit:=wdStory

Dim a As String

a = ""

Selection.Find.ClearFormatting

Selection.Find.Replacement.ClearFormatting

With Selection.Find

.Text = "text"

.Forward = True

.Wrap = wdFindStop

End With

While Selection.Find.Execute = True

a = a + " " + Str(Selection.Information(wdActiveEndPageNumber))

Wend

MsgBox a

7.

"Открыт документ Word, хочу запустить в нем макрос, который в свою очередь запускает макрос Excel, обрабатывающий Excel-таблицу. После этого через Clipboard из Excel макрос пересылает в Word-документ заданную прямоугольную область таблицы. Макрос Word обрабатывает эту область и начинает в требуемой последовательности копировать в Word-документ через Clipboard фрагменты Excel-таблицы. По окончании копирования Word закрывает все ненужные макросы, включая макрос Excel.


Как все это сделать, чтобы работало?"

Для работы из одного приложения Office с другим лучше всего использовать технологию ActiveX. Она основана на имеющейся в Office возможности представлять одну программу в другой как некий обьект, с которым можно работать теми же командами, что используются при непосредственной работе с этой программой.

Так, чтобы можно было из Word'ового макроса работать с Excel'ем, следует создать обьект Excel.Sheet (здесь "es" - простое наименование переменной, у вас может быть любым).

Dim es As Object

Set es = CreateObject("Excel.Sheet")

Если надо сразу открыть какой-либо файл Excel'а, то можно использовать команду GetObject:

Set es= GetObject("Путь к файлу Excel'а")

При желании можно сделать созданный обьект Excel видимым:

es.Application.Visible = True

Теперь можно этому обьекту es (т.е. просто запущенному Excel'у) посылать команды такие же, как и в макросах Excel'а  (предваряя текстом "es.Application." те из команд, которые не требуют прямого указания обьекта, - так как надо дать понять программе, что работа идет именно с Excel'ем). Так, чтобы открыть файл Excel'а, можно также дать команду

es.Application.Workbooks.Open FileName:="Путь к файлу Excel'а"

а чтобы, например, поместить в первую ячейку открытой книги текст, используйте команду

es.Cells(1, 1).Value = "Это столбец A, строка 1"

В принципе я бы вам посоветовал поместить тот макрос, который Вы планировали для Excel'а, именно в исходный Word'овый, переписав его команды в соответствии с принципом связывания (т.е. управления одним приложением из другого - так, как описано выше).

Закрыть Excel можно командой

es.Application.Quit

Set es= Nothing

Если работать с таблицей из Word почему-либо нельзя, и требуется именно вызвать Excel'евский макрос, то для вызова макроса следует использовать команду



es.Application.Run "имя макроса"

Также можно автоматически запустить какой- либо макрос при открытии файла Excel:

es.Application.Workbooks.Open FileName:="Путь к файлу Excel'а!имя макроса" (например, es.Application.Workbooks.Open FileName:="c:\book1.xls!macr1", точно так же, разделяя имя файла и имя макроса восклицательным знаком - и в команде Shell)

В общем, есть простор для творчества. Про работу из Word'а с Excel'ем и т.д. почитайте разделы Справки VBA (для Microsoft Office 97 - по-русски):  "Работа с приложениями", "Функция CreateObject", "Функция GetObject", "Программирование объектов".

8.

"Можно ли в Word при помощи гиперссылки вызвать команду меню, в частности команду "Найти"?"

Непосредственно с помощью гиперссылки - нет. Но можно поместить текст гиперссылки в элемент формы, который уже связать с макросом, вызывающим диалоговое окно. Для реализации данного способа необходимо вывести на экран панель инструментов "Элементы управления", включить кнопкой "Режим Конструктора", добавить элемент "Надпись", в меню правой кнопки мыши выбрать "Свойства", в разделе Caption поместить текст ссылки, оформить шрифт и цвет текста в соответствующем разделе Свойств, затем из меню правой кнопки мыши выбрать "Исходный текст", а в появившийся макрос вписать команду

Private Sub Label1_Click()

On Error Resume Next

Dialogs(wdDialogEditFind).Show

End Sub

или любые другие, какие пожелаете. После того, как Вы отключите Режим конструктора, созданная надпись с гиперссылкой будет работать так, как Вы желаете - при нажатии на нее вызовется окно поиска текста.

"Я сделал так, как Вы сказали, но при вводе в появляющееся окно поиска фрагмента, которого в тексте нет, не отображается сообщение о безрезультатности поиска - как при использовании непосредственно команды "Найти".


Можно ли сделать так, чтобы вызываемое окно работало точь-в-точь так же, как и обычное?"

К сожалению, с командой Dialogs… ничего сделать нельзя - так уж будет себя вести это диалоговое окно.

Однако можно использовать "финт ушами". В VBA есть функция SendKeys, которая передает активному окну нажатия клавиш - как если бы они были нажаты на клавиатуре. (Подробнее - смотрите в Справочной системе VBA.) Поэтому можно ее использовать:

Private Sub Label1_Click()

SendKeys "^f"

End Sub

предполагая, что комбинация клавиш Ctrl+f вызывает окно "Найти", как, впрочем, устанавливается по умолчанию. Список кодов функциональных клавиш - в Справке.

Если Вы используете функцию SendKeys, то вызванное ею окно будет вести себя абсолютно так же, как при ручном вызове. Однако помните, что если пользователь переопределит заложенную Вами в макрос комбинацию клавиш, то Ваша программа начнет работать некорректно.

*       *       *


Содержание раздела