Советы тем, кто программирует в Microsoft Office

Виталий Сизов

Оглавление

Совет 1. Используйте листы книги макросов для хранения констант

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

Вместе с тем листы рабочей книги представляют собой удобную среду хранения разнообразной информации с уникальными возможностями. Так, только здесь допускается запись символьных строк с различной кодировкой. Например, одновременно можно использовать кириллицу, латинский и балтийский алфавиты, а также специальные символы. Ни в каких других файлах, кроме непосредственно «рабочей» поверхности документов Excel или Word, подобное невозможно, не говоря уже о текстах программных модулей. Например, русскоязычные пользователи в странах Балтии не могут использовать смесь родного и государственного языка в базах данных Access, формах Outlook, заимствованных элементах управления и программных модулях, предусматривающих указание единственного набора символов.

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

Кроме символьных констант, на листах книги макросов можно хранить справочники, организованные в виде списков, и разного рода внедренные элементы, например держать коллекцию иконок для последующего использования в качестве источников для метода PasteFace в процедурах, создающих динамические кнопки на панелях управления Office.

Совет 2. Используйте скрытую форму

При работе над проектом VBA часто возникает желание использовать элементы управления ActiveX общего назначения, такие как CommonDialog, таймер, MAPI, FTP и др. Чаще всего такие элементы не удается внедрить непосредственно в тело офисного документа, а диалоговые формы интерфейсом разработки могут быть не предусмотрены.

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

В редакторе VBE создадим новую форму и «перетащим» на нее необходимые элементы управления, причем такие, что даже при отображении формы остаются невидимыми. На рис. 1 показан пример подобной формы, на которой расположены CommonDialog, Internet Transfer Control, IETimer и пара элементов MAPI.

Рис. 1. Скрытая форма с «невидимыми» элементами управления

Теперь у нас в проекте появились дополнительные объекты, к которым весьма просто обращаться

Рассмотрим работу со скрытой формой на примере использования CommonDialog для открытия и сохранения текстовых файлов. Напишем пользовательскую функцию, возвращающую имя файла и полный путь, выбранный пользователем в окне стандартного диалога, а также True - в случае успешного завершения операции и False - если пользователь нажмет кнопку Cancel.

Function ComDlgFile(ByRef strName As String, _
                              ByRef strPath As String, _
                              strTitle As String, _
                              blnOpen As Boolean) As Boolean
'-- Show Common Dialog and set FileName & FullPath
   
   Load FormHidden
 
   On Error Resume Next
   With FormHidden
      .CommonDialog.CancelError = True
      .CommonDialog.FileName = strName
      .CommonDialog.DialogTitle = strTitle
      .CommonDialog.Filter = _
         "All Files(*.*)/*.*/Text Files(*.txt)/*.txt"
      If blnOpen Then
         .CommonDialog.ShowOpen
      Else
         .CommonDialog.ShowSave
      End If
      If Err = 0 Then
         On Error GoTo 0
         strName = .CommonDialog.FileTitle
         strPath = .CommonDialog.FileName
         ComDlgFile = True
      Else
         ComDlgFile = False
      End If
   End With
   
   Unload FormHidden

End Function

Обратите внимание, что все действия выполняются с объектом, заключенным в контейнер FormHidden. Это не что иное, как наша скрытая форма, которой присвоено подобающее имя.

Прежде чем обращаться к объектам формы, ее нужно загрузить. Делается это с помощью инструкции Load. При работе с «нормальной» формой в этом месте обычно используется метод Show. В конце функции предусмотрено выполнение инструкции Unload, освобождающей память от формы и ее объектов.

Обращение к функции может быть таким:

Sub DialogSetFile()
'-- Show Common Dialog
   
   Dim strName As String
   Dim strPath As String

   strName = ""
   strPath = ""

   If ComDlgFile(strName, strPath, "Pick Up File", True) Then
      MsgBox "Name:" & Chr(9) & strName & Chr(13) _
                & "Path:" & Chr(9) & strPath, vbExclamation
   Else
      MsgBox "Cancel By User", vbCritical
   End If

End Sub

Использование скрытой формы весьма удобно также и для тиражирования. Элементы управления не привязаны к документам, поэтому всю конструкцию можно экспортировать с помощью команд Импорт и Экспорт файла контекстного меню проекта в редакторе VBE.

Совет 3. Печатайте на матричном принтере

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

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

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

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

Рис. 1. Скрытая форма с «невидимыми» элементами управления

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

 Sub PrePrint()
'-- Копирование формы и удаление элементов оформления

   ActiveSheet.Select
   ActiveSheet.Copy
   ActiveSheet.Unprotect
   Cells.Select

   '-- удаляем заливку
   Selection.Interior.ColorIndex = xlNone

   '-- удаляем рамки
   Selection.Borders(xlDiagonalDown).LineStyle = xlNone
   Selection.Borders(xlDiagonalUp).LineStyle = xlNone
   Selection.Borders(xlEdgeLeft).LineStyle = xlNone
   Selection.Borders(xlEdgeTop).LineStyle = xlNone
   Selection.Borders(xlEdgeBottom).LineStyle = xlNone
   Selection.Borders(xlEdgeRight).LineStyle = xlNone
   Selection.Borders(xlInsideVertical).LineStyle = xlNone
   Selection.Borders(xlInsideHorizontal).LineStyle = xlNone

   '-- удаляем графические элементы (надписи, линии и пр.)
   If ActiveSheet.Shapes.Count > 0 Then
      ActiveSheet.Shapes.SelectAll
      Selection.ShapeRange.Delete
   End If

   ActiveSheet.Range("A1").Select

End Sub

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

Совет 4. Полезный шаблон для Word

Очень часто приходится слышать сетования пользователей на громоздкие коды HTML-документов, которые генерирует Microsoft Word. Однако это можно существенно поправить, даже не прибегая к специальным разработкам. Первое, что необходимо сделать при использовании Word в качестве инструмента для подготовки HTML-документов, это правильно подобрать шаблон. Идея заключается в том, чтобы ограничиться только стандартными стилями, присущими HTML-документу, и не переопределять их в Word. Тогда результирующий код не будет содержать многих «лишних» тэгов, а надлежащее форматирование можно будет применить потом, с помощью CSS ( Cascading Style Sheets - каскадные таблицы стилей. - Прим.ред.)

Для изготовления «нормального» шаблона HTML-документа достаточно иметь чистую HTML-страницу с минимумом информации, например создать новую страницу с помощью FrontPage:

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>FrontPage</title>
</head>

<body>
</body>
</html>

Если такую страницу открыть в Word, то список доступных стилей пополнится стандартным набором стилей HTML, так, как это показано на рис. 3.

Рис. 3. Стандартные стили HTML-документа

Теперь остается сохранить страницу в качестве шаблона документа и использовать ее всегда, когда предполагается формирование документа HTML. Целесообразно даже сохранить такую страницу в качестве шаблона Normal, чтобы привыкнуть к работе со стандартными стилями современных документов. Единственная неприятность заключается в наличии трех стандартных стилей Word: Заголовок 1, 2 и 3. Поскольку эти стили являются системными, их нельзя удалить из шаблона. Остается только запомнить, что в HTML-документе для выделения заголовков следует использовать стили H1-H6, а стили Заголовок 1, Заголовок 2 и др. вообще лучше не применять.

Совет 5. Автоматизируйте вставку закладок

Иногда в документах Word требуется задавать большое количество закладок (bookmarks), особенно если готовится обширный документ HTML, в котором закладки будут играть роль объектов Anchor - элементов для организации системы перекрестных ссылок.

В подобных случаях использование стандартной команды Вставка/Закладка… достаточно утомительно, поскольку требует придумывания имен, к тому же удовлетворяющих правилам именования подобных объектов.

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

 Sub SetBookmark()
'-- Вставка закладки для выделенного текста

   Dim sName As String
   sName = LCase(Trim(Selection.Text))
   If Len(sName) < 1 Then
      MsgBox "Bookmark not valid", vbCritical
      Exit Sub
   End If
   '-- замена недопустимых символов
   sName = ConvertName(sName)

   With ActiveDocument.Bookmarks
      '-- проверка на первую цифру, что недопустимо
      If IsNumeric(Left(sName, 1)) Then sName = "a_" & sName
      .Add Range:=Selection.Range, Name:=sName
      .DefaultSorting = wdSortByName
      .ShowHidden = False
   End With

End Sub

В приведенном макросе над выделенным текстом производятся некоторые преобразования. Во-первых, с помощью функции ConvertName недопустимые в имени пробелы, знаки препинания, специальные символы заменяются символом «подчеркивание»:

 Private Function ConvertName(sName As String)
'-- Замена недопустимых символов

   Dim sRes As String
   Dim sChar As String
   Dim i As Integer
   sRes = ""
   For i = 1 To Len(sName)
      sChar = Mid(sName, i, 1)
      Select Case sChar
      Case " ", ".", "-", ",", ";", ":", "'", "!", "?", """"
         sRes = sRes & "_"
      Case Else
         sRes = sRes & sChar
      End Select
   Next
   ConvertName = sRes

End Function

А во-вторых, проверяется, не является ли первый символ цифрой, что также недопустимо для имени закладки, однако это часто происходит, например при необходимости вставить закладки для пронумерованных разделов документа. Если подобное имеет место, то к имени закладки слева добавляются символы «a» (от слова Anchor). Если придерживаться единых правил формирования имен как функции от контекста, то также легко можно будет автоматизировать и формирование гиперссылок на основе оглавления. Можно придумать и другое правило именования, например: имя документа плюс последовательный номер закладки в коллекции.

Совет 6. Макросы для работы со списками

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

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

Логичным выходом в данной ситуации является применение специальных макросов, выполняющих добавление и удаление строк-записей. Как показывает опыт разработки многочисленных приложений со списками, целесообразно иметь три подобных макроса: один будет добавлять «чистую» запись ниже строки, на которой находится курсор ввода (в произвольной колонке), второй будет удалять целиком несколько строк, задаваемых произвольным выделением, третий, подобно первому, будет добавлять запись, но при этом копировать содержимое предыдущей записи. Это оправданно, поскольку часто в потоке ввода следуют записи, имеющие одинаковые значения нескольких реквизитов.

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

Сами по себе макросы довольно просты и «программируются» в основном с помощью «макрорекордера». Естественно, перед записью макросов необходимо строкам-прототипам присвоить имена диапазонов:

 Sub InsertCopy()
'-- Вставка копии текущей строки

   Dim strSelAddr As String      '-- позиция курсора
   Dim objCurRange As Range      '-- текущий объект Range

   ActiveCell.Select
   strSelAddr = Selection.Address(ReferenceStyle:=xlR1C1, _
      RowAbsolute:=False, _
      ColumnAbsolute:=False, _
      RelativeTo:=Cells(2, 1))

   '-- проверка на допустимость операции
   If InStr(1, strSelAddr, "-", vbTextCompare) Then
      MsgBox "This Selection Not Valid", vbCritical
   Else
      Set objCurRange = Selection
      objCurRange.EntireRow.Select
      Selection.Copy
      Selection.Range("A2").Select
      Selection.Insert Shift:=xlDown
      Application.CutCopyMode = False

      '-- рекомендуемая позиция ввода
      Selection.Range("A1").Select
   End If

End Sub
   
   Sub DeleteRows()
   '-- Удаление строк

   Dim strSelAddr As String      '-- позиция курсора
   Dim intAns As Integer          '-- ответ пользователя

   Selection.Select
   strSelAddr = Selection.Address(ReferenceStyle:=xlR1C1, _
      RowAbsolute:=False, _
      ColumnAbsolute:=False, _
      RelativeTo:=Cells(2, 1))

   '-- проверка на допустимость операции
   If InStr(1, strSelAddr, "-", vbTextCompare) Then
      MsgBox "This Selection Not Valid", vbCritical
      Exit Sub
   End If
   intAns = MsgBox("Delete Selection" & Chr(13) _
                        & "Are You Sure", vbQuestion + vbOKCancel)
   If intAns = vbOK Then Selection.EntireRow.Delete

End Sub

   Sub InsertRow()
   '-- Вставка строки Item

   Dim strSelAddr As String      '-- позиция курсора
   Dim objCurRange As Range      '-- текущий объект Range
   Dim strSheetName As String   '-- имя активного листа
   Dim varSection As Variant    '-- номер раздела

   ActiveCell.Select
   strSelAddr = Selection.Address(ReferenceStyle:=xlR1C1, _
      RowAbsolute:=False, _
      ColumnAbsolute:=False, _
      RelativeTo:=Cells(1, 1))

   '-- проверка на допустимость операции
   If InStr(1, strSelAddr, "-", vbTextCompare) Then
      MsgBox "This Selection Not Valid", vbCritical
   Else
      strSheetName = ActiveSheet.Name
      Set objCurRange = Selection

      '-- на всякий случай копируем общий образец строки
      Sheets("Settings").Range("List1Item").Copy

      '-- копируем образец строки для текущего листа
      On Error Resume Next
      Sheets("Settings").Range(strSheetName & "Item").Copy

      objCurRange.EntireRow.Select
      varSection = Selection.Range("A1").Value
      Selection.Range("A2").Select
      Selection.Insert Shift:=xlDown
      Application.CutCopyMode = False

      '-- рекомендуемая позиция ввода
      Selection.Range("A1").Select
   End If

End Sub

Единственное существенное отличие этих макросов от записей «макрорекордера» заключается в наличии проверок допустимости операций. Так, для макросов InsertCopy и DeleteRows позиция курсора при вызове не должна находиться на строке заголовков, тогда как при вставке строк-прототипов ниже позиции курсора в макросе InsertRow - такое вполне допустимо. В приведенном примере предполагается, что строка заголовков - первая. Если это не так, следует откорректировать значение параметра RelativeTo. Проверка позиции курсора производится достаточно экзотическим способом: по наличию отрицательного значения относительного адреса. Но это совсем не обязательно - можно просто сравнивать абсолютные номера строк.

Для повышения надежности в макросе DeleteRows предусмотрен диалог для подтверждения пользователем «разрушающей» операции, а в макросе InsertRow - возможность отсутствия строки прототипа для данного списка. Эта проблема решается путем вставки прототипа «по умолчанию». Подобный прием позволяет иметь в книге несколько листов со списками одинаковой структуры, без необходимости создания для каждого из них строки-прототипа.

Совет 7. Используйте разнообразные типы элементов управления Office

В справочной документации, посвященной панелям управления Office, внимание уделяется только таким элементам управления, как Button и ComboBox. Вместе с тем офисная коллекция CommandBarControls поддерживает большое количество разнообразных элементов управления, которые задаются с помощью свойства Type.

Одним из таких малоиспользуемых элементов управления является CommandBarControl с типом msoControlEdit. Это не что иное, как аналог обычного текстового поля TextBox, присутствующего практически во всех формах.

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

Другой пример, показанный на рис. 4, использует поле ControlEdit для хранения нераспределенной суммы в задаче учета оплаты по счетам. Сложность такой задачи заключается в опасности получить оплату сразу по нескольким счетам, что потребует приостановки алгоритма регистрации оплаты и перемещения фокуса с формы на основной документ. Вследствие модальности форм Office 97 такая задача вообще неразрешима. Хотя в Office 2000 эта проблема устранена после введения свойства Show Modal, допускающего потерю фокуса формой, - решение с плавающей панелью управления выглядит более изящным.

Рис. 4. Использование панели инструментов в качестве формы

Создать такую панель можно с помощью кода, приведенного ниже:

 Private Sub Workbook_Open()
'-- Создание динамической панели Оплата

   Dim cbPayment As CommandBar
   Set cbPayment = Application.CommandBars _
      .Add(Name:="Payment", _
      Position:=msoBarFloating, _
      Temporary:=True)
   With cbPayment
      .Controls.Add Type:=msoControlButton
      .Controls(1).Caption = "Payment"
      .Controls(1).Style = msoButtonIconAndCaption
      .Controls(1).OnAction = "PaymentContinue"
      .Controls(1).FaceId = 1643
      .Controls.Add Type:=msoControlEdit
      .Controls(2).Text = "0.00"
      .Controls(2).Enabled = False
      .Visible = False
   End With

End Sub

Обратите внимание на тип элемента управления msoControlEdit и на его основное рабочее свойство Text, не описанное в справочной документации.

Совет 8. Использование Word и Excel для подготовки графических файлов

Приложения Office все чаще используются в качестве инструмента для подготовки Web-страниц. И если формирование законченных HTML-документов с помощью только Word или Excel пока еще вызывает заслуженные нарекания пользователей, то ничто не мешает применить эти приложения для изготовления отдельных элементов, например полноценных графических файлов.

Так, в Excel, для объектов Chart предусмотрен метод Export, позволяющий сохранять диаграммы в виде отдельных графических файлов:

Charts(1).Export _
   OutputFileName:="my_chart.gif", FilterName:="GIF"

В Word, хотя там и нет явного метода для экспорта графических элементов, данная возможность также существует. При выполнении стандартного метода SaveAs при указании формата HTML все объекты Shape экспортируются в виде отдельных графических файлов, причем в Word 97 это происходит в формате GIF, а в Word 2000 - в JPEG. Можно воспользоваться этим обстоятельством, а ненужный HTML-документ удалить:

 Sub ExportAllShapes()
'-- Экспорт всех рисунков в виде графических файлов
   Dim objShape As Shape
   Dim strActiveDocName As String
   Dim strNewDocName As String

   If ActiveDocument.Shapes.Count <= 0 Then Exit Sub
   strActiveDocName = ActiveDocument.Name
   Documents.Add
   strNewDocName = ActiveDocument.Name

   '-- копируруем все рисунки в новый документ
   For Each objShape In Documents(strActiveDocName).Shapes
      objShape.Select
      Selection.Copy
      Documents(strNewDocName).Activate
      Selection.PasteSpecial Link:=False, _
         DataType:=wdPasteMetafilePicture, _
         Placement:=wdFloatOverText, DisplayAsIcon:=False
   Next

   '-- сохраняем новый документ в формате HTML
   ActiveDocument.SaveAs FileName:=strNewDocName & ".htm", _
      FileFormat:=114, LockComments:=True, _
      Password:="", AddToRecentFiles:=False, _
      WritePassword:="", _
      ReadOnlyRecommended:=False, _
      EmbedTrueTypeFonts:=False, _
      SaveNativePictureFormat:=False, _
      SaveFormsData:=False, SaveAsAOCELetter:=False
   ActiveWindow.Close
   Documents(strActiveDocName).Activate

   '-- удаляем ненужный файл
   Kill strNewDocName & ".htm"

End Sub

Microsoft Office обладает богатой коллекцией картинок Clipart, хранящихся в формате WMF. С помощью этого нехитрого макроса, записанного «макрорекордером», можно очень легко осуществлять «пакетное» преобразование графических форматов для этих файлов.

Особо следует остановиться на графических объектах WordArt. Эти объекты не являются объектами типа Shape, и приведенная выше процедура будет их игнорировать. Для того чтобы использовать эти объекты на Web-страницах, достаточно преобразовать объекты WordArt в рисунки с помощью команд копирования и специальной вставки.

Совет 9. Запишите макрос переопределения языка

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

Sub SetRussian()
      Dim objAll As Range
      Set objAll = Selection.Range
      objAll.WholeStory
      objAll.LanguageID = wdRussian
End Sub

Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=3294