Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004
.pdf
402 ЧАСТЬ III Мощные средства и методы отладки приложений .NET
ло, что, когда я набирал код для формы Windows, автосохранение иногда предъяв ляло свои права и передо мной появлялось окно проектирования. Удивительно, но в модели автоматизации нет способа активизации окна кода из документа.
Мне нужен был способ поиска заголовка активного документа, т. е. окна с ак тивной вкладкой. Для этого можно вызвать DTE.ActiveWindow, но так вы получите окно, которое в данный момент имеет фокус во всех окнах IDE, а не окно, в кото ром вы выполняете редактирование или проектирование. После многих проб я увидел, что командная панель Window всегда содержит активный заголовок до кумента в пункте меню, начинающегося с «&1» (амперсанд показывает, что дан ный элемент меню должен быть подчеркнут). Использовать меню для получения заголовка действительного активного и впрямь глупо, но сделать это в модели ав томатизации иначе нельзя. Вооруженный заголовком активного документа и зна чением, возвращенным DTE.ActiveWindow, я наконец мог обдумать реализацию со хранения, так как теперь я хоть мог восстанавливать текущее активное окно до кумента и окно с действительным фокусом.
Просматривая в цикле документы, я должен был сделать пару вещей и только потом приступать к сохранению файла. Прежде всего я по первому символу фай ла должен был определить, является ли он новым. Если бы первый символ был тильдой (~), это значило бы, что файл был создан, но никогда не сохранялся. Так как я хотел, чтобы метод TrimAndSave.SaveAll выполнял реальное автосохранение (которое, например, прекрасно реализовано в редакторе Visual SlickEdit компа нии SlickEdit), я мог сделать так, чтобы TrimAndSave.SaveAll не сохранял новые файлы или файлы только для чтения. Это позволило бы мне избежать затопления экра на окнами Save File As при каждом автосохранении. Я мог указать в диалоговом окне параметров SuperSaver, что хочу пропускать новые файлы и файлы только для чтения. Если бы файл был новым или допускал только чтение, метод TrimAnd Save.SaveAll пропускал бы его и переходил к следующему файлу.
После определения, что документ нуждается в сохранении, мне следовало пе ревести документ в активное состояние, чтобы над ним мог поработать объект DTE.Find. Так как я должен был гарантировать, что окно редактирования файла активно, мне нужно было найти заголовок окна, соответствующий имени доку мента. Если я находил такое окно, я мог наконец удалить пустые места из строк. Если я не находил текстового окна, я просто переходил к сохранению файла.
Для новых файлов я создал собственное окно Save File As, что совсем нетруд но. Если файл уже имеет имя, я могу просто вызвать метод Document.Save. Интересно, что метод Document.Save — классический пример того, как не надо выполнять об работку исключений. Если файл допускает только чтение, Document.Save выведет диалоговое окно, спрашивающее, хотите ли вы перезаписать файл или сохранить его с новым именем. Если вы нажмете Cancel для отмены сохранения файла, Document.Save сгенерирует исключение класса COMException, которое сообщит «User pressed escape out of save dialog» (пользователь вышел из диалога сохранения). Это вполне нормальное взаимодействие с пользователем, поэтому об этом следовало бы сообщать через возвращаемое значение.
После обработки всех документов я мог заняться восстановлением исходного окна активного документа, а также самого активного окна. После восстановления окон я мог перейти к сохранению проектов и решения.
ГЛАВА 9 Расширение возможностей интегрированной среды разработки VS .NET |
403 |
|
|
Что касается проектов, требующих сохранения, то тут в первую очередь надо определить, допускает ли проект только чтение. Объект Project не имеет свойства, которое может сообщить вам это. Поэтому я должен получить и проверить атри буты файла проекта. Если проект допускает только чтение и пользователь не хо чет, чтобы ему предлагали сохранить проект при автосохранении, я не сохраняю проект.
Если проект должен быть сохранен, дело становится интереснее. Как я упоми нал в разделе «Проблемы с проектами», объектная модель проектов в Visual Studio
.NET не очень хорошо продумана и плохо документирована. Так как объект Project далеко не во всем соответствует другим типам проектов, особенно VCProject, я пытаюсь получить из проекта объект VCProject, проверяя сначала язык проекта. Если проект разрабатывается на C++, я вызываю Project.Object и привожу возвра щаемое значение к типу VCProject. Вооружившись VCProject, я могу уверенно вы зывать VCProject.Save. Если проект имеет какой то другой тип, а не VCProject, я пытаюсь сначала вызвать Save и, если вызов Save генерирует исключение, вызы ваю SaveAs, передавая в каждом случае полное имя проекта. Так как Microsoft не включила в документацию полное описание разных типов проектов, это лучшее, что я могу сделать для их сохранения.
Разобравшись с проектами, я могу сохранить решение, если это требуется. Как и в случае с проектами и документами, если решение допускает только чтение и пользователь не хочет, чтобы его беспокоили окнами Save File As, я не сохраняю решение.
Я думал, что после этого получу рабочую надстройку, но тестирование быст ро меня в этом разубедило. Протестировав автосохранение с включенной функ цией удаления пустых мест, я был огорчен масштабами моргания, связанного с переводом текстовых окон в активное состояние. Я вспомнил, что объект DTE под держивает свойство SuppressUI, которое при установке в true блокирует пользова тельский интерфейс во время выполнении кода автоматизации. Поняв, что Sup pressUI решит проблемы с морганием панели задач, я присвоил ему true в начале метода TrimAndSave.SaveAll. Увы, безрезультатно: мерцание продолжалось как ни в чем не бывало.
Конечно, я мог бы с этим смириться, но была еще одна проблема, связанная с методом Window.Active: он пытался перевести в активное состояние всю IDE, а не просто конкретное окно документа. Кроме того, если IDE была минимизирована, Window.Active восстанавливал окно.
Дальше — больше: применение объекта Find при фоновом сохранении, выпол няемом в другом потоке из за применения таймера, по видимому, изменяло его состояние. Вызов SuperSaver.SuperSaverSave, которому я назначил комбинацию Ctrl+S, работал прекрасно. Однако после фонового сохранения при каждом вызове Super Saver.SuperSaverSave начало появляться информационное окно Find/Replace, ко торое иногда выводится при работе с окном Find. Я не хотел заставлять вас от ключать информационные окна Find/Replace для использования SuperSaver, но мне пришлось пойти на это ограничение. Окно Find/Replace можно отключить, открыв окно Options, папку Environment, страницу свойств Documents и убрав флажок возле пункта Show message boxes (показывать информационные окна). После отключе ния окон Find/Replace я при каждом выполнении SuperSaver.SuperSaverSave стал слышать стандартный сигнал, который слышите вы, работая с окном Find.
404ЧАСТЬ III Мощные средства и методы отладки приложений .NET
Кэтому моменту я испытал сильное разочарование, но решил не сдаваться. К счастью, в последней попытке, хотя и далекой от совершенства, я получил боль шую часть того, что хотел. Так как я должен был использовать объект Find с пара метром vsFindTarget.vsFindTargetOpenDocuments, который ограничивает поиск и за мену только открытыми документами, мне нужно было быть очень внимательным. Я мог безопасно удалить пустые места при фоновой обработке, только если в числе активных документов не было файлов только для чтения и новых файлов. Я по настоящему хотел реализовать фоновое сохранение с удалением пустых мест из всех файлов, но это лучшее, что я мог сделать. Для обработки самого сохранения у меня был единственный вариант: вызывать реальный File.SaveAll. Так как я все еще хотел реализовать отмену появления диалоговых окон Save File As и инфор мационных окон, предупреждающих о перезаписи файлов, я не вызываю File.Save All, если пользователь отменил в SuperSaver пункт Save New And Read only Files When Auto Saving (сохранять при автосохранении новые файлы и файлы только для чтения); в активных документах нет файлов только для чтения, нуждающихся в сохранении, или новых файлов.
Конечно, несмотря на относительную простоту только что описанного алго ритма, я не мог не столкнуться с еще одной ошибкой. Свойство Document.ReadOnly, которое будто должно возвращать true, если файл допускает только чтение, не работает. Мне пришлось вручную проверять права доступа к файлам методом
File.GetAttributes.
Наконец, я реализовал в надстройке команды SuperSaver.SuperSaverSaveAll и SuperSaver.SuperSaverSave, которые, по моему, работали вполне хорошо. Я присту пил к созданию для них командной панели инструментов и столкнулся с пробле мами маски растровых изображений, рассмотренными выше. После их решения передо мной возникла последняя проблема с SuperSaver.
Так как я собирался написать команды для замены методов File.SaveSelectedItems и File.SaveAll, я хотел убедиться, что кнопки моей панели инструментов ведут себя, как кнопки реальных панелей. После серии экспериментов я заметил, что только кнопка File.SaveSelectedItems становилась серой в отключенном состоянии. Я пе репробовал все способы заставить кнопку SuperSaver.SuperSaverSave вести себя аналогично. Активное состояние определялось элементами, выбранными в теку щем решении и проекте, поэтому я никак не мог найти заклинания для проверки выполнения метода File.SaveSelectedItems, нужной для блокирования/разблоки рования его кнопки.
Я уже собрался сдаться, но тут меня осенило, что незачем все так усложнять. Мне нужно было только получить командный объект File.SaveSelectedItems и про верить, истинно ли свойство IsAvailable; если да, кнопка панели инструментов активна. Соответственно, если команда File.SaveSelectedItems неактивна, я возвращаю в методе IDTCommandTarget.QueryStatus значение vsCommandStatus.vsCommandStatusUnsup ported, и с моими кнопками и целым миром все в норме.
Разрабатывать SuperSaver было очень сложно, но мне это удалось, и я доволен. Я не только узнал многие слабости надстроек и модели автоматизации IDE Visual Studio .NET, но и осчастливил богов программирования, уничтожив пробелы в концах строк. В комментариях к SuperSaver я оставил все работоспособные алго ритмы, чтобы вы могли реализовать команды заново, используя будущие версии Visual Studio .NET с исправленными проблемами автоматизации.
ГЛАВА 9 Расширение возможностей интегрированной среды разработки VS .NET |
405 |
|
|
Надстройка SettingsMaster
После всех удовольствий с SuperSaver мне совсем не хотелось возиться с другой надстройкой для этой главы. Однако SettingsMaster оказалось не только легко разработать — эта надстройка стала одним из самых полезных средств из всех, когда либо мной созданных. Надеюсь, вам она тоже пригодится.
Как говорит название, SettingsMaster должна правильно настраивать парамет ры, т. е. все ваши параметры сборки проектов. Многие из ошибок, с которыми я сталкиваюсь годами, связаны с проблемами сборки проектов, поэтому я хотел создать единственное средство, гарантирующее правильную настройку всего про екта. Кроме того, Visual Studio .NET довольно плохо поддерживает создание при ложений группами разработчиков; единственный способ настройки параметров нескольких проектов нескольких программистов — установить их вручную. Это огромный недостаток Visual Studio .NET. Я хотел решить эти две проблемы и для проектов .NET, и для проектов на неуправляемом C++.
SettingsMaster добавляет в IDE две команды: SettingsMaster.CorrectCurrentSolution использует для автоматического применения желаемых вами параметров конфи гурационный файл по умолчанию (я еще расскажу о нем), а SettingsMaster.Custom ProjectUpdate выводит диалоговое окно Open File (открыть файл), предлагая выб рать конфигурационный файл для обновления проекта, выбранного в окне Solution Explorer.
Идея SettingsMaster заключается в хранении общих параметров группы в об щих файлах, благодаря чему при создании нового проекта программист может нажать кнопку SettingsMaster.CorrectCurrentSolution и сразу начать проект с кор ректными параметрами группы. Команда SettingsMaster.CustomProjectUpdate обновляет проект, предлагая указать файл ввода, содержащий изменения, которые вы хоти те сделать. Так, если вы решите определить новое значение для своих проектов C#, вы легко сможете добавить его во все проекты.
Страница свойств SettingsMaster в диалоговом окне Options (рис. 9 5) позво ляет задать файлы по умолчанию для каждого поддерживаемого языка. Первая версия SettingsMaster поддерживает C#, Visual Basic .NET и неуправляемый C++. В качестве отличного упражнения предлагаю вам добавить в этот набор и J#. Вы также можете указать, чтобы команды SettingsMaster автоматически сохраняли об новленные проекты после исправления параметров.
Конфигурационные файлы представляют собой относительно простые XML файлы, что продиктовано простотой синтаксического анализа и данью моде. Так как природа систем проектов в языках .NET и неуправляемом C++ сильно различ на, им соответствуют разные схемы. Основная идея в том, что конфигурацион ный файл специфичен для конкретного языка и определяет индивидуальные па раметры каждой конфигурации проектов на данном языке.
Для проектов .NET базовая схема такова (список полей см. в табл. 9 2):
<Configurations>
<ProgLanguage></ProgLanguage>
<Configuration>
<ConfigName></ConfigName>
<Properties>
<Property>
406 ЧАСТЬ III Мощные средства и методы отладки приложений .NET
<PropertyName></PropertyName>
<PropertyType></PropertyType>
<PropertyValue></PropertyValue>
</Property>
</Properties>
</Configuration>
</Configurations>
Табл. 9-2. Схема конфигурации проекта .NET
Узел |
Описание |
<Configurations> |
Основной элемент, содержащий одну или более конфигураций. |
<ProgLanguage> |
Содержит строку GUID языка программирования, поддерживаемо |
|
го данным файлом. |
|
Пример: |
|
<ProgLanguage> |
|
{B5E9BD34 6D3E 4B5D 925E 8A43B79820B4} |
|
</ProgLanguage> |
<Configuration> |
Набор свойств одной конфигурации сборки проекта. |
<ConfigName> |
Имя конфигурации. Соответствует целевой конфигурации в дис |
|
петчере конфигураций IDE Visual Studio .NET. |
|
Пример: |
|
<ConfigName>Debug</ConfigName> |
<Properties> |
Набор свойств данной конфигурации. |
<Property> |
Описание отдельного свойства. |
<PropertyName> |
Имя свойства объекта Project. Это свойство должно существовать |
|
в объекте автоматизации Project конкретного языка. |
|
Пример: |
|
<PropertyName>CheckForOverflowUnderflow</PropertyName> |
<PropertyType> |
Тип свойства. Тип может иметь только значения Boolean, String или |
|
Enum. Для свойства типа String вы должны включить атрибут типа |
|
OpType, Overwrite или Append, определяющий, как будет изменено |
|
строковое значение. Для свойства типа Enum вы должны включить |
|
атрибут типа Name, который представляет собой имя перечислимого |
|
типа, используемого корректным свойством объекта Project. |
|
Пример: |
|
<PropertyType>Boolean</PropertyType> |
|
Пример: |
|
<PropertyType Name="prjWarningLevel"> |
|
Enum</PropertyType> |
<PropertyValue> |
Значение, которое вы хотите присвоить свойству. В случае типов |
|
Boolean оно может быть равно или 1, или 0. Для типов String это |
|
строка, которую вы хотите присоединить или записать вместо пре |
|
дыдущей. Для типов Enum это численное значение перечисления. |
|
Пример: |
<PropertyValue>1</PropertyValue>
ГЛАВА 9 Расширение возможностей интегрированной среды разработки VS .NET |
407 |
|
|
Наверное, лучше всего показать, как выглядит конфигурация .NET, на двух про стых примерах. В листинге 9 5 приведен минимальный конфигурационный файл, необходимый для включения компоновки с приращением в отладочных компо новках и для ее отключения в завершающих компоновках проекта Visual Basic .NET, а в листинге 9 6 — присвоение уровню диагностики значения prjWarningLevel4 только в заключительных компоновках проектов C#.
Листинг 9-5. Проект SettingsMaster для включения компоновки с приращением в отладочных компоновках и ее отключения в завершающих компоновках проекта Visual Basic .NET
<Configurations> <ProgLanguage>{B5E9BD33 6D3E 4B5D 925E 8A43B79820B4}</ProgLanguage> <Configuration>
<ConfigName>Debug</ConfigName>
<Properties>
<Property>
<!—Turn on (/incremental+)—> <PropertyName>IncrementalBuild</PropertyName> <PropertyType>Boolean</PropertyType> <PropertyValue>1</PropertyValue>
</Property>
</Properties>
</Configuration>
<Configuration>
<ConfigName>Release</ConfigName>
<Properties>
<Property>
<!—Turn off (/incremental )—> <PropertyName>IncrementalBuild</PropertyName> <PropertyType>Boolean</PropertyType> <PropertyValue>0</PropertyValue>
</Property>
</Properties>
</Configuration>
</Configurations>
Листинг 9-6. Проект SettingsMaster для включения 4-го уровня диагностики в заключительных компоновках проектов C#
<Configurations>
<ProgLanguage>{B5E9BD34 6D3E 4B5D 925E 8A43B79820B4}</ProgLanguage>
<Configuration>
<ConfigName>Release</ConfigName>
<Properties>
<Property>
<!—Turn on to level 4—>
<PropertyName>WarningLevel</PropertyName>
<PropertyType Name="prjWarningLevel">Enum</PropertyType>
<PropertyValue>4</PropertyValue>
408 ЧАСТЬ III Мощные средства и методы отладки приложений .NET
</Property>
</Properties>
</Configuration>
</Configurations>
Схема конфигурационного файла для неуправляемых приложений C++ похо жа, однако она должна учитывать, что неуправляемые приложения определяют инструмент, с которым вы хотите работать. Базовая схема представлена в следу ющем фрагменте (список полей см. в табл. 9 3):
<Configurations>
<ProgLanguage></ProgLanguage>
<Configuration>
<ConfigName></ConfigName>
<Tools>
<Tool>
<ToolName></ToolName>
<Properties>
<Property>
<PropertyName></PropertyName>
<PropertyType></PropertyType>
<PropertyValue></PropertyValue>
</Property>
</Properties>
</Tool>
</Tools>
</Configuration>
</Configurations>
Табл. 9-3. Схема конфигурации проекта на неуправляемом C++
Узел |
Описание |
<Configurations> Основной элемент, содержащий одну или более конфигураций.
<ProgLanguage> Содержит строку GUID для неуправляемого C++. Она всегда будет иметь значение, указанное в примере.
Пример:
<ProgLanguage>
{B5E9BD32 6D3E 4B5D 925E 8A43B79820B4}
</ProgLanguage>
<Configuration> Набор свойств одной конфигурации сборки проекта.
<ConfigName> Имя конфигурации. Соответствует целевой конфигурации в дис петчере конфигураций IDE Visual Studio .NET.
Пример:
<ConfigName>Debug</ConfigName>
<Tools> |
Набор инструментов данной конфигурации. |
<Tool> |
Свойства отдельного инструмента. |
ГЛАВА 9 Расширение возможностей интегрированной среды разработки VS .NET |
409 |
|
|
|
|
Табл. 9-3. Схема конфигурации проекта … (продолжение) |
|
|
|
|
|
Узел |
Описание |
|
<ToolName> |
Имя конкретного инструмента. Им может быть любой из объектов |
|
|
инструментов, поддерживаемых объектом VCProject, а именно: |
|
|
VCAlinkTool, VCAuxiliaryManagedWrapperGeneratorTool, VCCLCompilerTool, |
|
|
VCCustomBuildTool, VCLibrarianTool, VCLinkerTool, |
|
|
VCManagedResourceCompilerTool, VCManagedWrapperGeneratorTool, |
|
|
VCMidlTool, VCNMakeTool, VCPostBuildEventTool, VCPreBuildEventTool, |
|
|
VCPreLinkEventTool, VCPrimaryInteropTool, VCResourceCompilerTool или |
|
|
VCXMLDataGeneratorTool. Вы также можете указать специальный |
|
|
объект VCConfiguration проекта VCProject для доступа к общим пара |
|
|
метрам проекта. |
|
|
Пример: |
|
|
<ToolName>VCCLCompilerTool</ToolName> |
|
<Properties> |
Набор свойств данной конфигурации инструментов. |
|
<Property> |
Описание отдельного свойства. |
|
<PropertyName> |
Имя свойства проекта. Это свойство должно существовать в объек |
|
|
те автоматизации VCProject. Если свойство инструмента использу |
|
|
ется только для DLL, добавьте атрибут Type и присвойте ему значе |
|
|
ние "DLL", а если оно используется только для EXE файлов — "EXE". |
|
|
Если свойство используется и для EXE файлов, и для DLL, не вклю |
|
|
чайте атрибут Type. |
|
|
Пример: |
|
|
<PropertyName>BasicRuntimeChecks</PropertyName> |
|
|
Пример: |
|
|
<PropertyName Type="EXE"> |
|
|
OptimizeForWindowsApplication</PropertyName> |
|
<PropertyType> |
Тип свойства. Тип может иметь только значения Boolean, String или |
|
|
Enum. Для свойства типа String вы должны включить атрибут типа |
|
|
OpType, Overwrite или Append, определяющий, как будет изменено |
|
|
строковое значение. Для свойства типа Enum вы должны включить |
|
|
атрибут типа Name, который представляет собой имя перечислимого |
|
|
типа, используемого конкретным свойством объекта Project. |
|
|
Пример: |
|
|
<PropertyType>Boolean</PropertyType> |
|
|
Пример: |
|
|
<PropertyType Name="basicRuntimeCheckOption"> |
|
|
Enum</PropertyType> |
|
<PropertyValue> |
Значение, которое вы хотите присвоить свойству. В случае типов |
|
|
Boolean оно может быть равно или 1, или 0. Для типов String это |
|
|
строка, которую вы хотите присоединить или записать вместо пре |
|
|
дыдущей. Для типов Enum это численное значение перечисления. |
|
|
Пример: |
|
<PropertyValue>4</PropertyValue>
410 ЧАСТЬ III Мощные средства и методы отладки приложений .NET
Как и в случае конфигурации .NET, я хочу привести пару простых примеров конфигураций проектов на неуправляемом C++. В листинге 9 7 показано, как вклю чить оптимизацию для всей программы в заключительных компоновках. Код ли стинга 9 8 задает DEF файл для отладочных и заключительных компоновок.
Листинг 9-7. Проект SettingsMaster для включения оптимизации всей программы в заключительных компоновках проекта на неуправляемом C++
<Configurations> <ProgLanguage>{B5E9BD32 6D3E 4B5D 925E 8A43B79820B4}</ProgLanguage> <Configuration>
<ConfigName>Release</ConfigName>
<Tools>
<Tool>
<ToolName>VCConfiguration</ToolName>
<Properties>
<Property>
<!—Turns on /GL and /LTCG.—> <!—(Whole program optimization!)—>
<PropertyName>WholeProgramOptimization</PropertyName>
<PropertyType>Boolean</PropertyType>
<PropertyValue>1</PropertyValue>
</Property>
</Properties>
</Tool>
</Tools>
</Configuration>
</Configurations>
Листинг 9-8. Проект SettingsMaster, определяющий DEF-файл для отладочных и заключительных компоновок проекта на неуправляемом C++
<Configurations> <ProgLanguage>{B5E9BD32 6D3E 4B5D 925E 8A43B79820B4}</ProgLanguage> <Configuration>
<ConfigName>Debug</ConfigName>
<Tools>
<Tool>
<ToolName>VCLinkerTool</ToolName>
<Properties>
<Property>
<!—Sets the .DEF file for the project.—>
<PropertyName Type="DLL">ModuleDefinitionFile</PropertyName> <PropertyType OpType="Overwrite">String</PropertyType> <PropertyValue>.\$(ProjectName).DEF</PropertyValue>
</Property>
</Properties>
</Tool>
</Tools>
</Configuration>
ГЛАВА 9 Расширение возможностей интегрированной среды разработки VS .NET |
411 |
|
|
<Configuration>
<ConfigName>Release</ConfigName>
<Tools>
<Tool>
<ToolName>VCLinkerTool</ToolName>
<Properties>
<Property>
<!—Sets the .DEF file for the project.—>
<PropertyName Type="DLL">ModuleDefinitionFile</PropertyName> <PropertyType OpType="Overwrite">String</PropertyType> <PropertyValue>.\$(ProjectName).DEF</PropertyValue> </Property>
</Properties>
</Tool>
</Tools>
</Configuration>
</Configurations>
Полные примеры для любого языка см. в файлах, которые я включил на CD вместе с проектом SettingsMaster; они настраивают ваши проекты с учетом всех рекомендаций, данных в главе 2. Для проектов .NET их можно использовать как есть, а вот некоторые указанные по умолчанию параметры проектов на неуправ ляемом C++ вам, возможно, захочется изменить. В проектах C++ я включаю стро ки Unicode и другие параметры, которые нравятся лично мне, но в ваших проек тах они могут вызвать проблемы. Все узлы, на которые вам стоит обратить вни мание, я прокомментировал в XML файлах.
Вопросы реализации SettingsMaster
Многие из вас могут быть счастливы просто от использования надстройки Settings Master, но ее реализация также представляет некоторый интерес. Когда я только подумал о SettingsMaster, я начал разрабатывать макрос, потому что это гораздо проще, чем создавать полную надстройку. Исходный макрос вы найдете в катало ге SettingsMaster\OriginalMacro. Когда макрос заработал, я не захотел переводить весь код на C#, поэтому я реализовал надстройку на Visual Basic .NET. Так как Visual Basic .NET — это то же самое, что и C#, только без точек с запятой, переключаться между языками очень легко.
Самая сложная часть работы над SettingsMaster состояла в определении схемы XML. Благодаря относительно небольшому размеру файлов SettingsMaster я смог использовать удивительный класс XmlDocument, что сделало навигацию по документу тривиальной. Если б мне понадобилось создать эту надстройку еще раз, я попро бовал бы разработать схему XML, позволяющую объединить всю информацию в один файл. Изучая код, вы увидите, что в нескольких местах я продублировал обработку двух типов проектов.
Чудо SettingsMaster основано на удивительном механизме отражения .NET. Возможность создания класса на лету и вызова его методов или установки и по лучения свойств — одна из самых лучших в.NET. Так как у меня были конфигура ции и проекты, я применил отражение для создания отдельных инструментов
