После публикации цикла статей о программировании на VBA пришло немало писем с вопросами. Хотя большинство из них было посвящено конкретным техническим решениям, возможно, они все же будут интересны и другим пользователям, поскольку демонстрируют, как на практике применить VBA-программирование. Итак, вот ответы на некоторые типичные вопросы.

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

!К сожалению, нельзя. Редактор Microsoft Word такого не позволяет. Впрочем, можно пойти на хитрость. Создайте документ Doc1.doc и вставьте в него рисунок. Затем сохраните данный документ с рисунком, задав ему пароли на открытие и на изменения. Создайте документ Doc2.doc. В том месте, где должен быть рисунок, укажите «Вставка?Объект?Создание из файла» и задайте в пути файл doc1.doc, включив предварительно функцию «Связь с файлом». Введите пароль на открытие — и рисунок окажется в вашем документе. Сохраните его.

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

?Можно ли в Word сравнивать два документа по словам?

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

?Как узнать с помощью макроса число страниц в Word 2000?

!С помощью команды p = ActiveDocument.ComputeStatistics(wdStatisticPages), где в переменную p запишется число страниц в активном документе.

?Мне необходимо из программы на VBA в Word открыть стандартное диалоговое окно выбора файлов и затем считать результат. Как это сделать, может быть, с помощью API?

!Чтобы выбрать файлы, необязательно использовать именно API. Достаточно стандартных диалоговых окон Word. Их ниспадающий список появится, если набрать в Редакторе VBA фразу Dialogs(«. Найти файл позволяет, например, вызываемое константой wdDialogFileOpen окно. Для его вызова можно применить текст:

With Dialogs(wdDialogFileOpen)
.Display
vibfail = .FileName
End With

Команда .Display отображает диалоговое окно, а следующая строчка записывает в переменную имя выбранного файла. Причем этот файл не открывается (если же надо открыть его, следует команду .Display заменить на .Show). (Подробнее — см. справочную систему VBA по слову Dialogs и раздел Displaying built-in Word dialog boxes.)

В программе Microsoft Excel аналогичное действие выполняется значительно проще — с помощью команды file = Application.GetOpenFilename. В результате будет отображено окно открытия файла, а после выбора имя файла поместится в переменную (здесь — file).

?В Word 97 я сделал документацию на свою VBA-программу в doc-файле. Включил в нее «снимки экрана» и наложил на них автофигуры Word — сноски, стрелки, скобки, надписи и т.п., что разъясняло бы назначение различных частей рисунков. Теперь я хочу поставлять документацию в HTML-формате, но... при конвертации редактор Word игнорирует свои же автофигуры, оставляя в итоговых gif-файлах чистый рисунок. Как найти выход из такой ситуации?

! Да, автофигуры Word 97 при конвертации в HTML игнорируются. Чтобы разрешить эту проблему, выделите все автофигуры вместе с самим рисунком (с помощью инструмента «Выделение объектов» панели «Рисование»), сгруппируйте их и вырежьте, поместив тем самым в Буфер обмена. Затем командой «Правка?Специальная вставка» поместите содержимое Буфера обмена в то место, где был исходный рисунок, используя в качестве формата вставляемого изображения «Точечный рисунок» или «Метафайл Windows». В документе появится рисунок со всеми вставленными автофигурами, который, однако, спокойно конвертируется в GIF-формат при преобразовании всего документа в HTML. Так следует поступить со всеми рисунками в документе. В Word 2000 и Word 2002 подобной проблемы не возникает — там автофигуры сохраняются в самой генерируемой Web-странице, но при просмотре ее в старых браузерах они могут быть не видны.

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

!Вообще говоря, в этом редакторе встроен «интеллектуальный» механизм, позволяющий не отображать панель после того, как пользователь ее несколько раз закроет. Если же применить макросы, можно сделать то, о чем вы спрашиваете.

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

Sub clipboard_hide()
CommandBars("Clipboard").Enabled = False
End Sub

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

Sub clipboard_show()
CommandBars("Clipboard").Enabled = True
CommandBars("Clipboard").Visible = True
End Sub

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

?Как определить с помощью макроса в документе 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

?У меня открыт документ Word, я хочу запустить в нем макрос, который, в свою очередь, открывает макрос Excel, обрабатывающий таблицу. Потом макрос через Clipboard из Excel пересылает в Word-документ заданную прямоугольную область таблицы. Макрос Word обрабатывает ее и начинает в требуемой последовательности копировать фрагменты Excel-таблицы в Word-документ через Clipboard. По окончании копирования 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:ook1.xls!macr1?, точно так же, разделяя имя файла и имя макроса восклицательным знаком, делается и в команде Shell).

В общем, есть простор для творчества. Про работу из Word с Excel и т. д. почитайте разделы справочной системы VBA: «Работа с приложениями», «Функция CreateObject», «Функция GetObject» и «Программирование объектов».

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

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

Private Sub Label1_Click()
On Error Resume Next
Dialogs(wdDialogEditFind).Show
End Sub

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

?Я сделал так, как вы сказали, но при вводе в появляющееся окно поиска фрагмента, которого в тексте нет, не возникает сообщения о безрезультатности поиска, как это происходит при использовании непосредственно команды «Найти». Можно ли будет сделать так, чтобы вызываемое окно работало подобно обычному?

!К сожалению, с командой Dialogs... ничего сделать нельзя. Однако можно воспользоваться одним трюком. В VBA есть функция SendKeys, передающая активному окну «горячие» клавиши таким образом, как будто они были активизированы с клавиатуры. (Подробнее — см. справочную систему.) Так что можно обратиться к ее помощи:

Private Sub Label1_Click()
SendKeys "^f"
End Sub

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

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

Антон Орлов,

http://antorlov.chat.ru, antorlov@inbox.ru