внутри процедуры в существующем исходном тесте проекта, оно не подвергнет его
каким бы то ни было изменениям. Если же дополнение найдет код On Error GoTo
<0> или On Error Resume Next, код обработчика будет модифицирован в соответствии
с указанным шаблоном, а непосредственно перед существующим кодом On Error будет
помещен следующий комментарий:
' TODO: Turn normal error handler on when this condition is finished
то есть "включите обычный обработчик ошибок, когда данное условие будет выполнено".
Файлы шаблонов записывают в обычном текстовом формате и имеют расширение .eht
(рис. 5).
Рис. 5
Выполнив все необходимые шаги, программист получит примерно такой код:
On Error GoTo HandleErr
ExitHere:
Exit Sub
' Error handling block added by
' Error Handler Add-In.
' DO NOT EDIT this block of code.
' Automatic error handler last updated
' at 05-29-2000 13:19:17
' ErrorHandler:$$D=05-29-2000
' ErrorHandler:$$T=13:19:17
HandleErr:
Select Case Err.Number
Case Else
' ErrorHandler:$$N=clsEmailMerge.Class_Initialize
MsgBox "Ошибка " & Err.Number & ": " & _
Err.Description, vbCritical, _
"clsEmailMerge.Class_Initialize"
End Select
' End Error handling block.
В составе ODE2000 имеется стандартный шаблон ErrorHandler.eht.
Форматы, используемые в шаблонах дополнений VBA Code Commenter и VBA Error
Handler
Эти шаблоны содержат заменяемые маркеры, которые указывают, что будет добавляться
в код процедур проекта:
Маркер
Значение
$$A
Автор. Заменяется текущим именем автора
$$B
Тело процедуры
$$D
Текущая дата в формате краткой даты Windows
$$H
Комментарии заголовка
$$I
Инициалы автора
$$N
Имя процедуры. Заменяется полным именем процедуры, включая имя класса,
если данная процедура является членом класса
$$P
Имя проекта
$$T
Текущее время в формате краткого времени Windows
$$V
Переменные заголовка
$$Y
Тип процедуры. Заменяется на Sub, Function или Property, соответственно
$$SA
Начало режима Auto. Используется, чтобы пометить начало вставляемого обработчика
ошибок
$$EA
Конец режима Auto. Используется, чтобы пометить конец вставляемого обработчика
ошибок
$$SH
Начало заголовка
$$EH
Конец заголовка
Маркеры $$A и $$I используются для вставки имени и инициалов разработчика.
Если вы ввели новые значения в поля Name и Initials в диалоговом окне VBA Code
Commenter или VBA Error Handler, дополнение сохраняет их в Реестре в каталоге
HKCU/Software/Microsoft/ODE/9.0 для дальнейшего использования. Если же дополнение
не находит их по указанному адресу, то оно пытается найти используемые по умолчанию
значения для зарегистрированного пользователя продуктов.
Дополнение VBA Code Commenter использует маркеры $$SH и $$EH, которые, соответственно,
вставляют такой комментарий:
' Code Commenter block inserted by Procedure Header Add-in
и
' End Code Commenter block
В том случае, если в существующей процедуре уже есть маркер $$SH, VBA Code
Commenter не будет изменять эту процедуру.
Для дополнения VBA Error Handler следует указывать маркеры $$SA и $$EA, которые,
соответственно, вставляют такой код:
' Error Handler block added by VBA Error Handler Add-in.
' DO NOT edit this block of code
и
' End Error Handling block
Если в тексте существующей процедуры будет найден маркер $$SA, программа VBA
Error Handler не станет изменять эту процедуру за исключением того случая, когда
установлен значок Update в диалоговом окне VBA Error Handler.
Замечание 1. Для правильной работы дополнения необходимо, чтобы файл
шаблона содержал, по крайней мере, следующие маркеры: $$B плюс либо $$SH и $$EH,
либо $$SA и $$EA. В случае их отсутствия будет выдано сообщение об ошибке при
попытке загрузить EHT-файл.
Замечание 2. Если вам не понравится код, добавленный к процедурам проекта
дополнениями VBA Code Commenter и VBA Error Handler, и вы захотите удалить его
с помощью команды , то тут вас ожидает небольшой сюрприз. После такой операции
будет удален весь текст процедуры, включая тот, что был написан вами! Не пугайтесь
-- после этого вызовите команду Edit|Undo Delete, и ваш код будет восстановлен.
String Editor
Практически во всех приложениях используются строки, состоящие из тех или иных
переменных, которые необходимо сначала описать, присвоить какое-либо значение,
а затем вывести в качестве элемента строки. Если вы хотите создать строку, включающую
несколько переменных, следует быть особенно внимательным, описывая ее, и не
забыть поставить все двойные кавычки и знаки конкатенации в нужных местах.
Рассмотрим такой код, который содержит несколько строковых переменных:
Fname$ = "Петя"
Lname$ = "Иванов"
varDate = "19 сентября"
varYear = "1975"
TextBox1.Text = Fname$ & " " & Lname$ & " родился " _
& varDate & " " & varYear & " года"
Как видно из этого примера, можно очень легко допустить ошибку, пропустив кавычки
или знак конкатенации или поставив их не в том месте. Здесь вам на помощь прийдет
дополнение String Editor, которое существенно упрощает процесс форматирования
сложных строк. Его удобно использовать для создания текстов, выводимых в диалоговых
окнах или окнах сообщений, формирования SQL-операторов или скриптов и т.д.
Работа с String Editor выглядит следующим образом:
Установите курсор в то место кода проекта, куда вы хотите вставить строку
и выберите команду String Editor в меню Add-Ins.
Введите текст нашего примера в окне String Editor (рис. 6):
Рис. 6
Fname Lname родился varDate varYear года
Выделите первую переменную и щелкните кнопку Toggle to Non-String на панели
инструментов String Editor - она будет помечена синим цветом. Повторите эту
операцию для всех переменных строки.
Щелкните кнопку Update для вставки отформатированной строки в код проекта.
Дополнение String Editor автоматически отформатирует строку, само добавит необходимые
синтаксические элементы (кавычки, знаки конкатенации и табуляции, константы
перехода на новую строку, вставит знаки пробелов между переменными и др.).
Вот еще несколько примеров форматирования, которое может быть сделано с помощью
String Editor:
Окно дополнения String Editor
Получаемый код
Наша собака довольна.
"Наша собака довольна."
Наша собака довольна.
"Наша собака " & vbNewLine & "довольна."
Наша strAnimal довольна.
"Наша " &
strAnimal & " довольна."
Наша собака довольна.
VbTab & "Наша собака довольна."
"Наша собака довольна."
Chr$(34) & "Наша собака довольна." & Chr$(34)
Package and Deployment Wizard
Package and Deployment Wizard - удобное средство создания дистрибутивов приложений,
разработанных с помощью Office 2000/VBA. Такие дистрибутивы инсталлируются программой
Setup.exe. Мастер упаковывает подлежащие установке компоненты приложения в один
или несколько сжатых CAB-файлов. Многофайловые дистрибутивы лучше записывать
на дискеты, а один CAB-файл предназначается для сохранения на компакт-диске.
Кроме того, дополнение Package and Deployment Wizard можно использовать для
создания DEP-файлов, описывающих зависимости между отдельными частями проекта
и распространяемых вместе с компонентами.
Примечание. Package and Deployment Wizard не является средством дублирования
дисков. Если вы хотите сделать копии дистрибутивных дисков, используйте соответствующую
утилиту.
После запуска Package and Deployment Wizard на экране появится окно, предлагающее
три варианта работы с мастером (рис. 7). В верхней части окна находится поле
Active Project, куда предлагается ввести полное имя проекта, предназначенного
для упаковки.
Рис. 7
Режимы работы с Package and Deployment Wizard включают:
Package
Выбрав эту кнопку, вы делаете первый шаг в создании дистрибутива приложения.
После того как проект будет упакован, вы можете вернуться в основное окно
и продолжить работу.
Deploy
Вы выбираете эту кнопку в том случае, если у вас уже есть готовый упакованный
проект и вы хотите приступить к его развертыванию. Мастер подготавливает дистрибутив
к распространению на дисках, в сети или локальной папке, а также в Internet.
Manage Scripts
Нажатие этой кнопки выводит диалоговое окно Manage Scripts, в котором вы можете
переименовывать, дублировать или удалять сценарии упаковки и развертывания.
Multi-Code Import/Export
При разработке больших проектов программисту часто приходится импортировать
и экспортировать объекты и модули, написанные на Visual Basic. Для этой задачи
лучше использовать дополнение Multi-Code Import/Export, которое поможет сэкономить
время и свести к минимуму ошибки, связанные с переносом множества модулей кода
в проект и обратно за одну операцию.
Multi-Code Import/Export состоит из двух дополнений: одно - для импорта кода,
а другое - для экспорта. Для переноса кода между двумя VBA-проектами следует
вначале экспортировать его из одного проекта в каталог-приемник с помощью дополнения
Multi-Code Export, а затем импортировать в другой проект с помощью дополнения
Multi-Code Import.
Для импорта объектов необходимо проделать следующие шаги:
Запустите дополнение Multi-Code Import, вызвав соответствующую команду из
меню Add-Ins.
На экран выведется диалоговое окно Multi-Code Import (рис. 8). В поле Import
objects сформируйте список файлов, предназначенных для импорта. (Импортировать
можно любой VBA-файл с расширением .bas, .cls, .dsr и .frm.) Для заполнения
списка используйте кнопку Browse, которая выводит диалоговое окно Ошибка!
Закладка не определена. . С помощью кнопки Remove можно удалить выделенный
VBA-объект из списка.
Рис. 8
Щелкните кнопку Import для импорта копий выделенных VBA-объектов в текущий
проект.
Экспорт объектов выполняется примерно аналогичным образом:
Запустите дополнение Multi-Code Export, вызвав соответствующую команду из
меню Add-Ins.
На экран выведется диалоговое окно Multi-Code Export (рис. 9). В левом списке
Available Objects содержится перечень имеющихся объектов и файлов. Он соответствует
текущему VBA-проекту, выделенному в Project Explorer. Используйте кнопку ">"
для добавления файлов к правому списку Selected Objects и кнопку ">>"
- для добавления всех файлов проекта. Примечание. Не все элементы проекта
могут быть экспортированы как одно целое.
Рис. 9
Список Selected Objects содержит перечень имен и типов файлов, предназначенных
для экспорта. Для удаления объектов из этого списка щелкните кнопку "<",
а для удаления всего списка - кнопку "<<".
В поле Target Folder укажите каталог, в который будут экспортироваться объекты.
Для смены папки-приемника щелкните кнопку Browse, которая выводит диалоговое
окно Browse for Folder.
Щелкните кнопку Export для копирования выделенных файлов в папку-приемник.
Code Librarian
Один из главный способов повышения производительности программирования является
использование готовых фрагментов кодов. Это могут быть какие-то централизованные
базы данных, или собственные наборы, создаваемые индивидуальным разработчиком.
В состав ODE2000 входит специальная утилита Code Librarian, которая позволят
работать с такими хранилищами программных кодов. Она реализована в виде Add-Ins,
подключаемого в среду VBA, а также автономной утилиты CodeLib.EXE, которую можно
использовать, например, пи работе с VB.
Microsoft поставляет также базу данных CodeLib.MDB с большим набором фрагментов
исходных текстов, модулей и функций для Office 2000, Visual Basic for Applications
(VBA) и систем разработки Visual Studio. Более того с марта 2000 года программисты
получили возможность доступа к новому Web-сервису Code Librarian Update, с помощью
которого они могут пополнять свой локальный архив повторно используемого кода
(Ошибка! Закладка не определена. ).
Рассмотрим возможности утилиты Code Labrarian на примере работы с базой данных
CodeLib.MDB, которая при запуске утилиты в среде VBA загружается автоматически
(рис. 10).
Рис. 10
Как мы видим, все компоненты базы данных хранятся с использованием оглавления
древовидной иерархической структуры (вкладка Contents в левом окне). В правом
верхнем окне находится список компонентов в текущем элементе оглавления, а ниже
него - краткое описание выделенного в данный момент компонента.
Для просмотра и редактирования содержимого фрагмента кода дважды щелкните его
название в списке. Операции с этим фрагментом выполняются с помощью трех вкладок:
Code (рис. 11) - в нижнем большом окне приведено содержимое фрагмента,
в верхнем поле - его развернутое название. Обратите внимание, что компонентом
базы может быть не только фрагмент кода, но, вообще говоря, любой произвольный
текст. Хотя здесь видно цветовое выделение ключевых слов, на самом деле в базе
просто сохраняется соответствующее форматирование, выполненное в источнике информации
(в данном случае это выделение цветом было сделано в VBA-редакторе).
Рис. 11
Description - здесь задается тип фрагмента кода - Function, Module,
Class Module или Code Snippet - и вводится его краткое описание (эти параметры
видны на рис. 10).
Setting - на этой вкладке задаются две группы параметров (категории
и ключевые слова), которые обеспечивают поиск нужного фрагмента.
В правой части имеется окно со списком Categories, которые привязывают текстовый
компонент к иерархическому оглавлению (рис. 12). Нужно обратить внимание, что
в отличие от привычной нам адресации файлов, отдельный компонент базы данных
может принадлежать сразу нескольким категориями (узлам оглавления). Здесь можно
использовать не только существующие категории, но и создавать новые.
Рис. 12
В левой части находится список ключевых слов данного текстового компонента
(рис. 13). Эти слова выбираются из набора ключевых слов базы данных, который
можно здесь же пополнять. (К сожалению, непонятно, как можно удалить неиспользуемые
ключевые слова.)
Рис. 13
Вернемся обратно в начальное окно утилиты (рис. 10). Теперь понятно, что три
вкладки левого под окна обеспечивают разные варианты поиска нужного фрагмента
кода: Contents - по категориям (оглавлению), Keywords - по ключевым словам,
Search - полнотекстовый поиск по различным критериям (устанавливая флажки флажки
Search titles only или Search through code, а также используя логические операции
AND, OR или NOT).
Программист может корректировать содержимое (удалять, добавлять фрагменты)
наборов кода или создать новые базы данных. Кроме того, он может выбирать функции,
менять их имена и описание, задавать их атрибуты.
Примечание. При добавлении нового кода в базу данных Code Librarian
следует использовать ключевые слова и описания, которые будут понятны другим
разработчикам, осуществляющим поиск кода в этой базе данных.
Нужный фрагмент кода можно легко вставить его в свой модуль проекта. Для этого
установите курсор в то место модуля вашего проекта, куда хотите поместить найденный
фрагмент, а затем перейдите в окно Code Librarian, выделите там необходимый
текст и щелкните кнопку Insert Code to Module на панели инструментов. Можно
также перетащить мышью выделенный фрагмент кода в модуль проекта или скопировать
его туда с помощью буфера обмена.
Поставляемая база данных CodeLib.mdb содержит довольно много полезных фрагментов
программных кодов. Но возможно, еще полезнее будет использовать утилиту Code
Librarian для создания собственного архива повторно используемого кода. Создайте
собственную базу данных и заносите в нее то, что может пригодится в будущем.
Это могут быть и законченные утилиты и просто какие-то небольшие программные
конструкции. Ведь, наверняка, почти все программисты периодически сталкиваются
с ситуацией - "помню, что уже делал такую конструкции и решал какие-то проблемы
с ее отладкой, но не помню - когда и где..."
А если вы решите писать книгу по программированию, то было бы целесообразно
распространять ее вместе со своей библиотекой кода, причем такой упорядоченный
набор примеров можно формировать по ходу дела.
В заключении отметим, что утилита Code Librarian заметно выиграла бы, если
в ней были реализованы некоторые полезные дополнительные режима, например поддержка
перекрестных ссылок между отдельными ее компонентами.
VBA Source Code Control
Использование VBA Source Code Control выгодно не только в группах разработчиков
- отдельные программисты тоже могут выиграть, применяя контроль версий проекта.
Так, если вы произвели какие-либо изменения, а затем захотели вернуться к предыдущей
версии, то с помощью Visual SourceSafe можно легко восстановить предыдущий исходный
код.
При работе же в группах, когда много людей совместно создают, поддерживают
и обновляют файлы для крупного приложения, координация их работы может представлять
большую сложность. Использование Visual SourceSafe позволяет осуществлять надежное
и простое управление исходным кодом, синхронизируя работу разработчиков в группе
согласно сделанным ими изменениям.
Дополнение VBA Source Control позволяет подключить автономный пакет Visual
SourceSafe (система контроля версий) в среду VBA, благодаря чему разработчики
получают следующие возможности управления проектами:
выяснять, какие объекты были восстановлены;
восстанавливать и изменять объект;
сохранять объект, чтобы другие разработчики смогли воспользоваться теми
изменениями, которые были проведены с объектом;
просматривать историю внесения изменений для каждого объекта или всей базы
данных;
визуально сравнивать версии объекта;
создавать версии объектов и возвращаться к предыдущей версии (даже для удаленных
объектов);
производить слияние различных версий объекта;
переходить к последним версиям всех объектов.
Обратите внимание, что в Microsoft Office 2000 существует два типа дополнений
VBA Source Code Control:
Access Source Code Control, используемый при разработке приложений с помощью
Microsoft Access, который хранит двоичный код и код своих объектов в качестве
отдельных элементов внутри базы данных Visual SourceSafe;
Новый VBA Source Code Control, применяемый при разработке приложений с помощью
других продуктов Microsoft Office 2000 (например, Excel или Word). Это дополнение
предоставляет все функциональные возможности Visual SourceSafe в среде разработки
Office.
Дополнение VBA Source Code Control работает следующим образом. При разработке
крупного приложения все VBA-объекты, создаваемые группой программистов, хранятся
в проекте Visual SourceSafe. При этом каждый разработчик работает над VBA-проектом
на своей машине. Восстановление исходного кода объектов из пакета Visual SourceSafe
означает, что этот код копируется из проекта Visual SourceSafe в проект разработчика
на локальной машине. Сохранение исходного кода объекта происходит путем копирования
его с локальной машины разработчика в базу данных Visual SourceSafe.
После установки дополнения VBA Source Code Control и подключения системы контроля
версий Visual SourceSafe с помощью команды Add-Ins|VBA Source Code Control|Add
Project to SourceSafe в подменю Add-Ins|VBA Source Code Control появляются такие
команды (рис. 14):
Рис. 14
Get Latest Version записывает текущий объект из базы данных поверх
локальной версии. При вызове команды в списке объектов могут появиться такие,
которые в действительности не входят в состав базы данных разработчика. Это
значит, что эти объекты были помещены в Visual SourceSafe другими программистами,
а вы их еще не скопировали.
Check Out копирует выделенные объекты в текущий проект и обновляет
окно состояния элемента управления Project, указывая тем самым, что файлы
были скопированы конкретному члену команды разработчиков. Восстановление объекта
дает вам возможность проводить с ним какие-либо изменения. При этом, когда
вы восстановили объект, никто их других разработчиков не может выполнить ту
же самую операцию до тех пор, пока вы не сохранили его.
Check In выводит диалоговое окно, в котором вы можете выбрать объект
для сохранения. Здесь у вас есть дополнительная возможность сохранить файлы
- Keep checked out, но продолжать работать над ними, сохраняя за ними статус
восстановленных. Кроме того, вы можете добавить комментарий, в котором указывается,
когда были сделаны последние изменения. Сохранение объекта дает возможность
другим разработчикам просматривать и использовать сделанные вами изменения.
Undo Check Out возвращает к последней версии, сохраненной в Visual
SourceSafe. При вызове команд Get Latest Version, Check Out, or Undo Check
Out может оказаться так, что версии объектов на локальной машине будут отличаться
от тех, что находятся в проекте Visual SourceSafe. Если это произойдет, то
объекты будут синхронизированы, то есть скопированы из базы данных Visual
SourceSafe на машину разработчика и записаны поверх локальных версий.
Show History выводит диалоговое окно, отображающее историю разработки
текущего объекта.
Show Differences сравнивает локальную копию объекта с аналогичной
в проекте Visual SourceSafe и показывает различия между ними.
SourceSafe Properties выводит свойства объекта Visual SourceSafe
(такие как комментарии и статус "Восстановлен/Сохранен ".
Add Files to SourceSafe выводит диалоговое окно, содержащее список
объектов текущего проекта, которые еще не включены к систему контроля версий.
Это диалоговое окно используется для добавления объектов к Visual SourceSafe.
Get Object from SourceSafe копирует объект из Visual SourceSafe,
подсоединяет его к проекту на локальной машине и предоставляет вам возможность
включить его в систему контроля версий внутри вашего проекта. Копируемый объект
по существу является новым объектом, который теперь принадлежит вашему проекту
и больше не связан с исходным объектом, который остается в Visual SourceSafe.
Run SourceSafe запускает Visual SourceSafe Explorer. Если последний
уже загружен, то эта команда выводит окно Visual SourceSafe поверх всех остальных.
Refresh File Status обновляет данные в окне VBA Source Code Control.
WinAPI Viewer
При работе с внешними функциями DLL-библиотек их описание с помощью оператора
Declare должно быть включено в состав каждого программного компонента проекта
(форма, модуль и пр.), где они используются. Однако при этом нужно быть особенно
внимательным - ошибка может повлечь неприятности в виде, например, зависания
программы.
Кроме того, многие такие функции используют в качестве параметров специальные
структуры данных Type, а для управления режимами выполнения функций - определенные
значения параметров. Здесь нужно обратить внимание на следующую особенность
современного стиля документации и литературы по VB: если в описании говорится
об использовании параметра или типа данных, имя которых обозначено заглавными
буквами (например LB_GETITEMHEIGHT), то имеются в виду некоторые стандартные
значения констант или структур.
Для упрощения работы с наиболее часто используемыми внешними функциями - стандартным
набором Windows - в состав ODE 2000 входят два файла, содержащие описания процедур,
а также константы и структуры данных: WIN32API.TXT (собственно набор Win32 API)
и MAPI32.TXT (дополнительный набор Message API - почтовых функций).
Предупреждение. Не следует загружать файл WIN32API.TXT в проект в виде
программного модуля. Файл занимает слишком много места в памяти. Обычной практикой
является копирование нужных описаний, констант и структур данных в соответствующие
программные модули проекта.
Далее все происходит достаточно просто - когда вам нужно получить описания,
константы и типы данных для работы с API, выберите команду Add-Ins|API Viewer,
после чего появится окно утилиты (рис. 15). Далее необходимо загрузить нужный
файл описаний, например WIN32API.TXT, с помощью команды Load Text File из меню
File. Потом, устанавливая в списке API Type нужный вид информации, можно просматривать
содержимое файла в списке Available Items. Для быстрого поиска можно использовать
кнопку Search.
Рис. 15
Для более быстрой загрузки файла описания можно преобразовать текстовый файл
в базу данных Jet, однако при работе с MDB-файлом почему-то пропадает кнопка
Search. Для преобразования файла следует выполнить такие действия:
Запустить дополнение WinAPI Viewer.
В меню File выбрать команду Load Text File, а зетем выбрать имя txt-файла,
который вы собираетесь преобразовать.
В меню File выбрать команду Convert Text to Database.
Ввести имя и местоположение создаваемого файла базы данных и щелкнуть OK.
Примечание. К сожалению, выполнить такое преобразование нам не удалось,
поскольку команда Convert Text to Database на наших компьютерах оказалась почему-то
недоступной.
Добавление описаний из исходного файла в проект VB выполняется следующим образом.
В списке Available Items выделяется нужный элемент, а потом с помощью кнопки
Add его содержимое переносится в окно Selected Items. Чтобы удалить информацию
из окна Selected Items, надо установить на нее курсор и нажать кнопку Remove.
Скопировать содержимое окна Selected Items в проект VB можно двумя способами:
Нажав кнопку Copy, скопировать данные в буфер обмена, а потом, перейдя в
среду VB, вставить информацию в нужное место.
Нажав кнопку Insert, сразу скопировать информацию в раздел Declarations
активного в этот момент программного модуля VB. (Это самый удобный вариант
- ведь обращение за описанием API-функции производится обычно как раз при
активизации соответствующего модуля.)
ВНИМАНИЕ! ВСТРЕЧАЮТСЯ ОШИБКИ! К сожалению, в файле описаний встречаются
ошибки. В частности, в WIN32API.TXT приведено такое описание функции GetCurrentDirectory:
Declare Function GetCurrentDirectory Lib "kernel32" _ Alias "GetCurrentDirectory"...
Здесь видно, что имя функции и ее альтернативное название совпадают. Соответственно
при копировании этой строки в программный код редактор VB совершенно логично
автоматически убирает команду Alias. При запуске программы на выполнение выдается
сообщение об отсутствии функции в DLL-библиотеке. Ошибка очевидна - в конце
названия функции после команды Alias пропала буква "A": ... Alias "GetCurrentDirectoryA"...
Имейте это в виду, если вам встретится аналогичная ошибка в других описаниях.
Дополнительную информацию Вы можете получить в компании Interface Ltd.
Обсудить на форуме
Microsoft
Отправить ссылку на страницу по e-mail