"Тайны и секреты компьютера" - читать интересную книгу автора (Орлов Антон)

Глава 5.Советы и секреты программирования Что такое API?

Для того, чтобы облегчить труд своих коллег и обеспечить всем программам для Windows универсальный интерфейс, программисты Microsoft создали такую вещь, как API — "Application Programming Interface".

Это — набор функций и процедур, которые могут наиболее часто использоваться программами: отображение дерева каталогов, поиск файлов, отображение стандартного окна с кнопками закрытия, минимизации и развертывания на весь экран и многих других. В итоге разработчик, создающий программу для Windows, не должен продумывать и разрабатывать специальные подпрограммы для отображения окна программы, окна для выбора папки и остальных подобных элементарных операций, — ему достаточно просто вызвать из библиотек kernel32.dll или user32.dll, содержащих функции и процедуры API, нужную ему функцию, а она уже все сделает за него сама. Таких функций и процедур много — порядка 600.

В операционной системе MS-DOS такого понятия, как API, не было, — тот, кто брался писать программу для этой операционной системы, обязан был сам, от начала до конца, продумать и реализовать способы выдачи на экран изображения, получения данных от пользователя, путешествия по файловой системе, рисования графики, если таковая возможность была необходимой.[8] Это делало процесс разработки программ с удобным для пользователя интерфейсом весьма трудоемким процессом, зачастую затраты времени и сил на создание приемлемого графического интерфейса программы превосходили затраты на реализацию собственного алгоритма программы, ради которого она и создавалась. Недаром были очень распространены так называемые «консольные» приложения, то есть программы, работающие только из командной строки, без интерфейса, — ввод данных происходил в той же командной строке или производился из указанного в ней файла, а вывод результатов шел в простом текстовом режиме.

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

В языке Visual Basic for Applications (VBA) многие функции и процедуры API вызываются сами при выполнении программы интерпретатором, так что использовать их для отображения окон ввода и вывода текста, рисования на экране геометрических фигур и других простых действий совершенно нет необходимости, — их VBA вызывает по мере надобности, а программе на нем достаточно использовать соответствующие функции этого языка. Однако иногда возникает необходимость в некоторых действиях, для которых либо нет аналогов во встроенных функциях VBA, либо они работают нерационально или слишком медленно. Например, окно выбора папки с изображением дерева каталогов (рис. 5.1) или программа поиска файлов (аналог на функциях VBA — объект "Application.FileSearch" — работает слишком медленно при больших количествах файлов). Для таких случаев в VBA предусмотрена возможность вызова функций API.



Рис. 5.1. Это окно вызывается функцией API.


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

В подавляющем большинстве случаев при программировании для Office можно обойтись без использования API, но иногда только вызов API-функции может привести к достижению нужного результата. Скажем, вам надо обеспечить вызов разных макросов при простом нажатии мышью кнопки на какой-либо панели инструментов Word и в случае одновременного нажатия этой кнопки и клавиши Shift или Control. Вот фрагмент кода, делающего это:

Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal kState As Long) As Integer

Sub Program()

GetAsyncKeyState (vbKeyShift Or vbKeyControl)

If GetAsyncKeyState(vbKeyShift) Then

Call macro1: Exit Sub

ElseIf GetAsyncKeyState(vbKeyControl) Then

Call macro2: Exit Sub

End If

Call macro3

End Sub

Первая строчка — это как бы «резервирование» функции API для использования в программе на VBA. Видно, что вызывается функция GetAsyncKeyState из библиотеки (файла, содержащего программы, предназначенные только для использования другими программами) user32.dll, причем в эту функцию передается номер клавиши, а возвращает она целое число (а именно — 0, если клавиша с соответствующим номером не нажата, и -32767 или 1, если нажата). Любую функцию или процедуру, вызываемую из библиотек, не относящихся к VBA, необходимо так резервировать с помощью команды Declare.

Фраза vbKeyShift в команде — это заменитель кода клавиши Shift (его значение — 16), а vbKeyControl, как нетрудно понять — заменитель кода клавиши Control. Структура инструкций "If…Then", думается, ясна,[9] а если нет — посмотрите в справке VBA. Команда Call перед именем макроса, как вы помните, означает его запуск.

В Интернете есть русские сайты, посвященные API.[10] Посетите их, чтобы узнать больше об этом наборе функций.


Настройка вызова программы. Последние штрихи

Когда программа написана и отлажена, необходимо придать ей "товарный вид", — убрать лишние команды и модули, сделать способ вызова программы — кнопку или пункт меню, может быть, создать панель инструментов для кнопок. Без этого даже с очень хорошо написанной программой сможет работать лишь ее создатель, да и то не всегда. К тому же красивая обложка всегда радует глаз.

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

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

Потом необходимо создать документ с программой. Для этого создается пустой документ необходимого формата — шаблон или простой файл Word, а затем с помощью диалогового окна Word «Организатор» ("Сервис — Макрос — Макросы — Организатор" или "Сервис — Шаблоны и надстройки-Организатор") в него копируются все готовые компоненты программы из шаблона или документа, где велась разработка. Документ сохраняется под каким-нибудь красивым именем.

И, наконец, делается способ вызова программы. Можно с помощью диалогового окна "Сервис — Настройка — Команды — Макросы" назначить макросу пункт меню или кнопку на стандартной панели путем простого перетаскивания. Можно там же назначить ему комбинацию клавиш для вызова. А можно, что считается лучшим вариантом, создать новую панель инструментов и уже на ней поместить кнопки для вызова макросов. Надо только сохранить все изменения именно в документе с макросами, а не в своем Normal.dot или где-нибудь еще.

В окне "Сервис — Настройка — Команды — Макросы" название каждого макроса отображается так: сначала пишется имя проекта (его можно посмотреть и изменить в Окне свойств редактора VBA, выделив мышью название нужного проекта), затем — имя его модуля (тоже можно изменить в окне свойств, выделив мышью название модуля), а затем — собственно имя макроса (то, что стоит после команды начала программы Sub).

Назначить кнопку или сочетание клавиш для вызова формы невозможно. Необходимо вставить команду вызова формы ("ИмяФормы. Show") в текст программы в модуле, и уже затем назначить кнопку или сочетание клавиш для вызова именно этой программы.

Для вызова программы очень удобно использовать кнопки с иконками. Для этого нужно всего лишь перетащить название нужного макроса из окна «Настройка» на какую-нибудь (лучше специально созданную) панель инструментов, а затем выбрать значок для кнопки и задать стиль отображения — лучше всего без текста, "Основной стиль".

Можно также оставить на кнопке текст с названием макроса, однако тогда этот текст стоит соответственно отредактировать. Стоит помнить, что при подведении курсора мыши к кнопке, вызывающей макрос, отображается всплывающая подсказка с названием макроса (берется название макроса после команды начала программы Sub), поэтому макросам неплохо давать осмысленные имена. Однако если макрос назван по-русски, то в нелокализованных версиях Word он не будет вызываться кнопкой, созданной в русской версии.

Всплывающие подсказки кнопок можно задать самостоятельно с помощью команды "CommandBars("Имя панели"). Controls("Номер иконки на панели"). TooltipText = "Текст подсказки"". К сожалению, через диалоговое окно настройки панелей и кнопок сделать это не удастся, поэтому для ввода этой команды придется использовать отдельный модуль или Окно отладки.

Вам может не понравиться весьма ограниченный выбор значков для кнопок, предлагаемый Word'ом. Этот набор, вызываемый из меню "Выбрать значок для кнопки" в режиме настройки панелей, действительно, маловат. Но никто не мешает с помощью других команд того же меню скопировать значок с любой другой кнопки на любой другой панели или создать его самому во встроенном редакторе изображений на кнопках. Кроме того, красивые значки можно извлечь из «недр» Office, — а он содержит в себе около двух тысяч разнообразных значков! Для этого достаточно ввести в Окне отладки команду

CommandBars("имя существующей панели инструментов"). Controls.Add(Type:=msoControlButton, ID:=797). FaceId = x

где х — любое число от 1 до 3000. Тогда на указанной в команде панели будет создана кнопка со значком, который можно скопировать на свою кнопку. Не для всех кодов существуют значки, поэтому иногда созданная таким образом кнопка будет пустой, — попробуйте еще раз с другим х.[11]

Если в качестве способа вызова макроса выбрана панель инструментов с кнопками, то после окончания работы над ней стоит повторить создание нового документа и вновь скопировать все компоненты программы в новый документ вместе с панелью. Такое преобразование позволит существенно сократить размер файла с программой, так как вследствие ошибки в Office при редактировании макросов файл с программой сильно увеличивается в размерах — до полутора-двух раз. Впрочем, в OfficeXP данная рекомендация уже неактуальна.

Не стоит забывать и об информативном руководстве для пользователя, особенно если программа будет распространяться через Интернет. Лучше всего такое руководство оформить в отдельном текстовом файле или, если оно имеет большой объем, в виде набора связанных html-документов.


Полезные советы

· Настройки программы можно сохранять в системном реестре Windows. Для этого служит команда "SaveSetting", с помощью которой можно поместить в системный реестр строку или число. Она имеет формат "SaveSetting "Имя приложения","Имя раздела", «Ключ», "Значение"". Имя приложения, имя раздела и ключ — указатели места, в котором сохраняется Значение. Получить значения из реестра можно командой "GetSetting" с синтаксисом "GetSetting "Имя приложения","Имя раздела", «Ключ», "То значение, которое следует вернуть, если такого ключа, как указанный в предыдущем параметре, в реестре нет"", а удалить — командой "DeleteSetting "Имя приложения","Имя раздела", "Ключ"". Например:

SaveSetting «Макросы», «Макрос1», "Имя папки", "C: \MyPapka"

papka = GetSetting «Макросы», «Макрос1», "Имя папки", "C: \Docs"

· Записать список всех установленных в системе шрифтов в массив можно таким способом:

ReDim shrifti(FontNames.Count) As String

For r = 1 To FontNames.Count

shrifti(r) = FontNames(r)

Next r

WordBasic.SortArray shrifti()

(В массив "shrifti()" размером в количество шрифтов в системе помещается список имен всех установленных в системе шрифтов. Команда "WordBasic.SortArray" сортирует его по алфавиту.)

· Условие "If Selection.Type = wdSelectionIP Then …" выполнится, только если в документе не выделен фрагмент текста.

· Если вы решили хранить какую-нибудь информацию, нужную при работе программы, в отдельном файле, не стоит экспериментировать с командами чтения и открытия файла типа «open», «write» и др. Просто открывайте файл в Word как текстовый с помощью команды "Documents.Open …" и пишите в него обычными средствами записи текста: "Selection.Text = "Мой текст"".

· Посмотрите повнимательнее свойства, объекты и методы таких объектов, как «Application» и «System» (для этого достаточно набрать название объекта и поставить после него точку, — список возможных продолжений отобразится сам). Среди них можно найти немало весьма интересных и полезных, вроде средства задания и получения значений ширины и высоты окна Word, информации о языке данной версии Office, метод чтения данных из произвольного места реестра и многое другое.

· С помощью фрагмента кода

Set MyData = New DataObject

MyData.SetText "Мой текст"

MyData.PutInClipboard

можно поместить текст в буфер обмена, не используя активный документ.

· С помощью команды "Options.DefaultFilePath("константа названия папки")" можно получить пути и имена папок, перечисленных в диалоговом окне Word «Сервис» — «Параметры» — «Расположение». Все константы перечислены в справке VBA по слову «DefaultFilePath», а об их значении можно легко догадаться, переведя название константы с английского.

· Если у одного из элементов формы установить свойство Cancel в True, то нажатие кнопки Esc будет эквивалентно клику мыши на этом элементе.

· Если вы пишете инсталлятор для ваших программ, который помещает шаблоны с макросами в папку автозагружаемых файлов Word,[12] то совсем необязательно требовать перезагрузки редактора, чтобы макросы из помещенного в эту папку шаблона стали доступны. VBA позволяет активизировать такие шаблоны без перезагрузки Microsoft Word — для этого существует специальная команда

AddIns.Add("полное имя шаблона, включая путь к нему и расширение"). Installed = True

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

Предотвратить подобную ситуацию можно, например, с помощью следующей конструкции, — разместите ее после команды копирования шаблона "FileCopy":

a="Имя шаблона в папке автозагрузки с полным указанием пути"

On Error Resume Next

Do

If AddIns(a). Installed Then Exit Do

AddIns(a). Installed = True

Loop[13]

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

· Для удаления шаблона без выгрузки Word можно использовать такой же код:

a="Имя шаблона в папке автозагрузки с указанием пути"

On Error Resume Next

Do

If Not AddIns(a). Installed Then Exit Do

AddIns(a). Installed = False

Loop

AddIns (a). Delete

Kill (a)

· Команда "Kill" выполняет удаление файла.

Команда "On Error Resume Next", встречающаяся в обоих вышеприведенных фрагментах кода — это обработчик ошибок. В случае возникновения ошибки в коде после него (скажем, связанной с обращением к несуществующему объекту) он продолжит выполнение программы с команды, следующей за вызвавшей ошибку. Обработчик ошибок может также иметь вид "On Error GoTo метка", и тогда при ошибке в коде после него произойдет переход к указанной в обработчике метке и выполнение программы продолжится именно с нее.

· Если вы, работая в Word 97, часто сохраняете документы в формате HTML, и вам мешает постоянно появляющийся диалог о выборе кодировки файла (рис. 5.2), то отключите его, установив в системном реестре строковый параметр "HKEY_LOCAL_ MACHINE\Software\Microsoft\Shared Tools\ Text Converters\Export\HTML\Options\Show EncodingDialog" как «No». Установить этот параметр реестра можно и программно с помощью команды "System.PrivateProfileString("", "HKEY_LOCAL_MACHINE\Software\Microsoft\Shared Tools\Text Converters\ Export\HTML\Options", "ShowEncodingDialog") = "No""



Рис. 5.2. Как убрать этот диалог? Читайте справа.


· Если Вы закрыли исходный код Вашей программы на VBA от просмотра паролем, а потом благополучно его забыли — не огорчайтесь: в Интернете, по адресу www.passwords.ru есть программа AVPR, позволяющая восстановить забытый Вами пароль. Ее английская версия требует оплаты и регистрации, а русская — бесплатная. К сожалению, бесплатная версия работает только с файлами, созданными в Word и Excel из Microsoft Office 97.

Чтобы ускорить работу программы, работающей с текстом, поставьте в ее начале команду "Application.ScreenUpdating = False", а в ее конец — команду "Application.ScreenUpdating = True", если

· только в процессе работы программы не требуется визуальный контроль происходящих изменений. Эта команда позволяет системе не тратить время и силы на постоянное обновление экрана и отображение изменений. Для того, чтобы все же обновить экран после отключения обновления экрана, используйте команду "Application.ScreenRefresh".

· Для получения от пользователя определенных данных, кроме создания форм, можно использовать встроенные диалоги VBA — диалоговое окно "Открытие файла", "Свойства документа" и др. Они вызываются командой Dialogs("Название диалога"). Show (показывает диалог и выполняет соответствующие ему действия), Dialogs("Название диалога"). Display (только показывает диалог и позволяет записать в переменные введенные изменения, но не выполняет никаких действий и ничего не изменяет: очень полезно для использования встроенных диалоговых окон в своих целях), Dialogs("Название диалога"). Execute (ничего не отображает на экране, но применяет все те изменения, которые были сделаны ранее с помощью команды With Dialogs("Название диалога") … End With). Для вывода списка возможных диалогов наберите "Dialogs(", и Вам будет выдан их список. К сожалению, описания конкретных диалогов нет в справке — придется просто попробовать отобразить каждый, хотя список возможных параметров каждого диалога в справке есть.

В Microsoft Excel набора встроенных диалогов нет, однако отобразить на экране окна открытия и сохранения файлов все же можно. Для этого служат команды "Application.GetOpenFilename" и "Application.GetSaveAsFilename". В результате выполнения команды "file = Application.GetOpenFilename" будет отображено окно открытия файла, а после выбора имя файла поместится в переменную (здесь — "file"). Команда же "rez = Application.GetSaveAsFilename" отобразит окно сохранения файла, в переменную же (здесь — rez) будет помещено True — если сохранение успешно, и False — если нет. Обе команды докускают указание параметров (например, меняющих заголовки окна и других).

Иногда возникает необходимость вызвать из макроса какое-либо диалоговое окно, но так, чтобы такой вызов ничем не отличался от «ручного», производимого через пункты меню Word. А возможно это не всегда: так, команда "Dialogs(wdDialogEditFind). Show" действительно вызывает окно поиска, но при этом в случае ввода в него фрагмента, которого в тексте нет, не отображается сообщение о безрезультатности поиска.

Тем не менее вызвать из макроса данное окно так, чтобы оно работало точь-в-точь так же, как и «обычное», можно — для этого следует использовать имеющуюся в VBA функцию SendKeys, которая передает активному окну нажатия клавиш — как если бы они были нажаты на клавиатуре. Подробнее об этой функции вы можете прочитать в Справке по VBA, а использовать ее для вызова диалогового окна можно, к примеру, так:

Sub prog()

SendKeys "^f"

End Sub

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

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

· Помимо привычных кнопок и выпадающих меню в Word существует еще несколько типов элементов вызова команд и программ — поля ввода и выпадающие меню выбора. К примеру, элемент "Выпадающее меню с полем ввода" используется для указания масштаба просмотра документа на панели «Стандартная» или для ввода вопроса к справочной системе в OfficeXP.

Создать такое поле можно только программно — через окно настройки это сделать нельзя (как, впрочем, и удалить их впоследствии). Для этого следует в окне отладки или в отдельном модуле выполнить команду

CommandBars(x). Controls.Add Type:=y

где «х» — номер панели (можно узнать, просто перебрав их все с помощью команды "MsgBox CommandBars(номер). Name" и выяснив, какой номер имеет панель инструментов с нужным названием), а «y» — одна из констант: "msoControlEdit", "msoControlDropdown", "msoControlComboBox", создающие соответственно поле ввода текста, выпадающее меню и выпадающее меню с возможностью ввода текста.

Управлять созданными полями, добавляя, к примеру, в них текст, можно стандартными командами работы с панелями инструментов. Так, чтобы поместить какой-либо текст в поле ввода, следует использовать команду

CommandBars(x). Controls(y). Text = "текст в поле ввода"

где «х» — номер панели, «y» — номер по счету слева направо данного поля среди кнопок этой панели. Таким образом можно использовать эти элементы для отображения нужной пользователю информации. Точно так же — командой "a=CommandBars(x). Controls(y). Text" можно считать информацию из данного поля и использовать ее в работе программы. Следует лишь внимательно следить за соответствием номеров кнопок их реальному расположению, — при изменении порядка кнопок программа может работать неверно. Назначить макрос кнопке, меню или полю ввода можно командой "CommandBars(x). Controls(y). OnAction = "Имя модуля. Имя программы"".

· Для работы из одного приложения Office с другим можно использовать технологию ActiveX. Она основана на имеющейся в Office возможности представлять одну программу в другой как некий объект, с которым можно работать теми же командами, что используются при непосредственной работе с этой программой. Так, чтобы можно было из Word'овского макроса работать с Excel'ем, следует создать объект "Excel.Sheet":

·

Dim es As Object

Set es = CreateObject("Excel.Sheet")

Здесь «es» — простое наименование переменной, может быть любым.

(Если надо сразу открыть какой-либо файл 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 можно командой

es.Application.Quit

Set es = Nothing

Можно даже вызвать на исполнение макрос, содержащийся в книге Excel. Для этого следует использовать команду

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

Так что есть простор для творчества.


ProgressBar в ваших программах

Во многих программах для Windows используется такой элемент, как ProgressBar — индикатор, показывающий, на сколько продвинулся тот или иной процесс. В частности, он есть практически во всех программах-инсталляторах. К сожалению, в VBA этот элемент отсутствует, но его можно сделать самостоятельно!

Выглядеть он будет, например, так, как на рис. 5.3.

А делается он следующим образом (предполагается, что у нас есть часть программы, в которой выполняется длинный и долгий цикл: то есть известное нам количество множество однотипных операций, и которую надо снабдить ProgressBar'ом):

1. Создаем небольшую форму и помещаем на нее: надпись с пояснительным текстом (например, "Label1") и две другие надписи, (скажем, «Label2» и "Label3"), низкие и широкие, которые расположим одну над другой (рис. 5.4).

К примеру, их координаты и размеры:

Label2: Top — 45, Left — 15, Height — 15, Width — 250

Label3: Top — 45, Left — 15, Height — 15, Width — 0

Зададим в качестве фонового цвета для «Label2» — серый, а для «Label3» — зеленый (свойство «BackColor», вкладка "Палитра").



Рис. 5.3. ProgressBar в программе на VBA



Рис. 5.4. А вот как он сделан


2. Для того, чтобы форма появилась на экране, но могла быть модифицируема программно все время своего отображения, в ее код нужно поместить следующий текст:

Private Sub UserForm_Activate()

… остальной текст программы, которая должна выполняться во время отображения ProgressBar'а …

Unload Me

End Sub

Все, что находится в теле этого обработчика, будет выполняться, в то время как форма будет находиться на экране. По окончании выполнения программы форма будет выгружена (хотя выгружать ее не обязательно, если после окончания программы в обработчике предполагается продолжение работы с формой). Однако никакие другие события формой обрабатываться в это время не будут.

3. Идея такова. Ширину третьей надписи «Label3» можно изменять программно. Поэтому для отображения ProgressBar'а надо вставить в код строки, изменяющие ширину этой надписи. К примеру, цикл в программе выполняется n раз. Тогда ширина надписи «Label3» будет определяться командой в теле цикла по формуле "Label3.Width = (scet / n) * 250", где "scet" — это счетчик цикла, а 250 — ширина надписи Label2.

После каждой такой команды надо вставлять инструкцию "Me.Repaint", чтобы перерисовать форму с учетом новых параметров третьей надписи, — автоматической перерисовки до полного отображения формы (которое произойдет, когда кончится обработка события "UserForm_Activate()"и форма не будет выгружена) не происходит. Если форма с ProgressBar'ом должна долго находится на экране без изменений, то рекомендуется почаще использовать команду "Me.Repaint", так как без перерисовки внешний вид формы может быть легко испорчен окнами других приложений, когда пользователь решит воспользоваться ими во время работы макроса.

Итак, код для формы с ProgressBar'ом должен иметь такой вид ("n" — количество необходимых выполнений цикла):

Private Sub UserForm_Activate()

Me.Repaint

For t=1 to n

… … … … необходимые команды программы в цикле … … … …

Label3.Width = ((t / n) * 250)

Me.Repaint

Next t

Unload Me

End Sub

Разумеется, в нем возможны изменения и улучшения. Можно несколько раз использовать ProgressBar в одной форме, каждый раз обнуляя ширину третьей надписи. Можно поместить на одну форму несколько ProgressBar'ов, где один, например, показывает выполнение всего задания, а другой — его текущей части.


Хранение скрытой информации в документе

Иногда автору программы необходимо записать в документ информацию "для внутреннего пользования": например, чтобы при следующей обработке документа программой использовать определенные предыдущие данные.

Можно, конечно, использовать Свойства документа (объект "Dialogs(wdDialogFileSummaryInfo). Comments"), но лучше сделать такую запись с помощью добавления специальной переменной прямо в документ Word:

ActiveDocument.Variables.Add Name:="x1", Value:="Текст"

ActiveDocument.Variables.Add Name:="x2", Value:=12

Прочитать эти переменные можно будет с помощью похожей функции:

y1 = ActiveDocument.Variables("x1"). Value

y2 = ActiveDocument.Variables("x2"). Value

Кроме как с помощью этой функции, значения заданных в документе переменных узнать нельзя никак! Таким способом можно помещать в документ служебную информацию для макросов: сохраненные параметры, скрытые комментарии и и.д. Но не думайте, что для надежного сокрытия секретной информации достаточно поместить ее в переменные документа — с помощью функции

For Each per In ActiveDocument.Variables

Debug.Print per.Name + " " + per.Value

Next per

абсолютно все переменные будут благополучно помещены в окно отладки, где их легко и просто можно просмотреть.


Немного о панелях, шаблонах и макросах

Панель инструментов Microsoft Word 97/2000/XP — то есть ее название, набор кнопок, расположенных на ней, связь этих кнопок с командами и макросами — может храниться либо в шаблоне Microsoft Word 97/2000/XP (*.dot), либо в документе Word (*.doc). При этом имеет место быть следующее:

1. Если панель инструментов сохранена в Normal.dot, то она доступна всегда, когда открыт Word.

2. Если панель инструментов сохранена в шаблоне, который загружен как глобальный — то есть помещен в папку автозагружаемых файлов Word, то она также доступна всегда, когда открыт Word, но ее можно убрать, выгрузив шаблон с помощью диалогового окна "Сервис-Шаблоны и надстройки".

3. Если панель инструментов сохранена в шаблоне, на котором основаны документы, например, в одном из шаблонов, находящихся в папке шаблонов пользователя Word[14] и ее подпапках, то она доступна тогда, когда этот шаблон присутствует на компьютере и активен документ, созданный на его основе.

4. Если панель инструментов сохранена в каком-либо документе, то она доступна тогда, когда активен этот документ.

Панели инструментов можно копировать из одного шаблона или документа в другой с помощью диалогового окна «Организатор» (Сервис — Шаблоны и надстройки — Организатор).

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

Каждой кнопке панели инструментов, вызывающей макрос, ставится в соответствие имя вызываемого ею макроса, которое состоит из имени модуля, содержащего этот макрос, и имени макроса в модуле.

Узнать имена модуля и макроса в модуле можно в редакторе VBA. При изменении любого компонента имени кнопка становится неработоспособной.

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

Если при запуске Word в папке Шаблоны не оказывается шаблона Normal.dot, то он создается Word'ом на основании стандартов по умолчанию. В него помещается изначальный набор панелей инструментов.

Поиск модуля и имени макроса при нажатии кнопки (при этом не имеет значения, где панель сохранена) идет в следующем порядке: "Активный документ" — "Шаблон, на котором основан документ" — "Normal.dot" — "Шаблон, загруженный глобально через папку автозагружаемых файлов Word или окно "Шаблоны и надстройки".

Кнопки с панелей можно свободно перемещать с панели на панель, при этом их связь с макросами сохраняется вне зависимости от того, где макрос находится. Если макрос недоступен (скажем, удален глобальный шаблон с ним), то кнопка просто не работает.


Немного о паролировании и шифровании

Защита доступа с помощью пароля — самый распространенный способ хранения всяческих секретов на компьютере. Однако о принципах такой защиты большинству пользователей известно плохо. В чем же ее основы? И как можно преодолеть такую защиту? Ниже рассказывается об этом.

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

Среди математических логических функций, таких, как И, Или и других, есть весьма примечательная функция Xor. Команда, выполняющая эту функцию, есть практически во всех языках программирования. Ее действие отражено в следующей таблице:



Иными словами, это некое подобие функции Или,[15] которая в отличие от настоящей Или возвращает 0, если на входы было подано сразу две единицы.

А теперь — приглядитесь повнимательнее и обратите внимание на интереснейшую вещь: если на вход функции Xor подать значение 1 входа и результат, то получится значение 2-го входа! И то же самое — со значением 2 входа и результатом: получается значение 1-го входа. Следовательно, зная итог функции Xor и значение на любом из входов, можно получить значение на другом входе, то есть функция Xor обратима.

А отсюда вытекает и принцип парольного шифрования. Берем некий текст, который должен быть зашифрован и некое слово, служащее паролем. Любой текст — это последовательность букв-байтов, а любой байт равен восьми битам, что позволяет представить текст как последовательность битов — нулей и единиц:

11010101010110101001101010111110101010111110101010001…

Представляем так же пароль:

10010101010011

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

11010101010110101001101010111110101010111110101010001…

10010101010011100101010100111001010101001110010101010…

И теперь — шифруем: применяем к этим двум последовательностям функцию Xor:

01000000000101001100111110000111111111110000111111011…

Все — шифрование закончено! Полученную последовательность можно хранить в качестве зашифрованного паролем файла. Ну, а когда потребуется расшифровка, то будет необходимо просто применить ту же самую функцию Xor к этой последовательности вместе с паролем, и тогда в результате получится исходный текст. Преобразовать же последовательность нулей и единиц обратно в текст труда не составит.

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

Функция Xor, разумеется, присутствует и в VBA. Вот пример кода, реализующего возможности шифрования с ее помощью.

Sub encrypt()

Dim a, b, c, d As String

Исходный текст для шифрования — запрашивается от пользователя, к примеру:

a = "secret text from kgb agent from newyork rezidentura…"

Пароль: может запрашиваться от пользователя:

b = «password»

Итог шифрования:

c = ""

Узнаем длины каждой из строк — пароля и исходного текста:

lentext = Len(a)

lenpass = Len(b)

Собственно шифрование:

For cn = 1 To lentext

В этой строке попробуйте разобраться самостоятельно. Здесь выполняется функция Xor с каждым символом исходной строки и соответствующим символом пароля, как бы «повторенным» на всю длину исходного текста. Mid берет из середины строки символ, Asc — превращает его в ASCII-код, Str — превращает число в строку, Trim — удаляет пробелы:

d = Trim(Str(Asc(Mid(a, cn, 1)) Xor Asc(Mid(b, ((cn — 1) Mod lenpass) + 1, 1))))

А теперь сделаем так, чтобы каждый символ занимал ровно три позиции, вне зависимости от величины его ASCII-кода. А иначе как потом при расшифровке разбивать строку на символы?

Select Case Val(d)

Case 0 To 9

d = «00» + d

Case 10 To 99

d = «0» + d

End Select

c = c + d

Ну вот и все, и так — с каждым символом из исходной строки:

Next cn

Теперь в переменной с — шифрованная строка, каждой исходной букве соответствует 3 символа. Ее можно записать, например, в документ:

Selection.TypeText Text:=c

End Sub

А теперь — программа расшифровки данных. Точно так же разберем ее по строкам.

Sub decrypt()

Dim a, b, c, d As String

Строка для расшифровки:

c = "003004016001018027082016021025007083017029029009"

Пароль:

b = "password"

Итог расшифровывания:

a = ""

Узнаем длины каждой из строк:

lentext = Len(c)

lenpass = Len(b)

Собственно расшифровывание (попробуйте разобраться самостоятельно в структуре команды — это не так сложно):

For cn = 1 To lentext Step 3

a = a + Chr(Val(Mid(c, cn, 3)) Xor Asc(Mid(b, (Int(cn / 3) Mod lenpass) + 1, 1)))

Next cn

В итоге в переменной a — расшифрованная строка, ее можно записать в любое место — в документ, к примеру:

Selection.TypeText Text:=a

End Sub

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


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

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

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

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

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

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


Отличия новых версий Office

Отличия VBA в новых версиях Office в основном заключаются в добавлении новых функций, процедур и объектов. Однако есть некоторые тонкости.

В Office2000 изменилась система защиты от вирусов в макросах. Так, в Word2000 для того, чтобы иметь возможность запускать макросы, необходимо, чтобы в диалоговом окне "Сервис — Макросы — Безопасность" был установлен «Средний» или «Низкий» уровень защиты от макросов (лучше «Средний» — тогда при открытии документов с макросами пользователю будет выдан запрос о необходимости разрешения исполнения макросов). Также в Word2000 для того, чтобы пользователь имел возможность запускать макросы из шаблонов, установленных в папку автозагружаемых файлов Word, необходимо на вкладке "Надежные источники" диалогового окна "Сервис — Макросы — Безопасность" установить отметку в пункте "Доверять всем установленным надстройкам и шаблонам". Обо всем этом следует упомянуть в документации к разрабатываемой вами программе.

То же самое верно и для Office XP, однако отличия есть и здесь. Во-первых, по умолчанию компоненты Office XP, отвечающие за запуск макросов, на жесткий диск не ставятся — таким образом, похоже, Microsoft пытается защитить наиболее неразумных пользователей от макровирусов. По большому счету, подобные ее действия обычно приносят больше вреда, чем пользы, для авторов же программ на VBA из этого следует, что в справочных файлах к своим программам им следует упоминать о необходимости доустановки компонентов Office перед началом использования макросов. Во-вторых, для того, чтобы иметь возможность программно копировать модули и формы макросы между документами и шаблонами, необходимо, чтобы в диалоговом окне "Сервис — Макросы — Безопасность", на вкладке "Надежные источники" имелась отметка в пункте “Доверять доступ к Visual Basic Project”. Об этом тоже следует упомянуть в справке к программе.

В OfficeXP скопировать файл из одной папки в другую или удалить его посредством программного кода можно только при отключенной Службе индексирования (cсылка “Параметры поиска” на панели “Обычный поиск", рис. 5.5). К сожалению, по умолчанию эта Служба включена, а программно ее отключить невозможно. Поэтому, несмотря на декларируемую полную "совместимость сверху вниз" версий Office, автору программ на VBA настоятельно рекомендуется тестировать свои программы во всех версиях Office и отлаживать их при необходимости.



Рис. 5.5. Если в OfficeXP вы хотите копировать и удалять файлы с помощью VBA — выключите здесь “Службу индексирования”.