Просмотров: 51.
отказывалась что-либо visual studio 6.0 покачал

Visual C++ 6.0 в составе Microsoft Visual Studio. Во время создания данного обзора окончательной версии Visual Studio еще не было (она должна появиться непосредственно перед выходом нашего журнала) и нам пришлось использовать “пре-релиз”, любезно предоставленный нам фирмой Microsoft. Так что в окончательной версии могут появиться изменения, хотя судя по размерам продукта, заметить их будет непросто.

Итак, начнем. Первое, что бросается в глаза при установке Microsoft Visual Studio 6.0 (MSVS), так это частота появления на экране слова “MICROSOFT” - к месту и, в основном, не к месту. Грандиозность данного продукта потрясает, особенно с точки зрения его объема – несколько урезанный нами в процессе инсталляции вариант занял более 1 Гб на жестком диске (Справедливости ради надо заметить, что в поставку MSVS входят, кроме Visual C++ 6.0 (VC) и Visual Basic 6.0 (VB), еще Visual j++ 6.0 и Visual Fox Pro 6.0, но эти продукты мы даже не устанавливали).

Разумеется, значительную часть от этого отхватил себе Help – чтобы постоянно не обращаться к CD мы поставили значительную часть Help’a на жесткий диск (примерно 500 Мб), оставив на CD только половину. Очень неудобным оказалось то, что исходные тексты примеров (при любом типе установки) все равно остаются на CD и, если машина не оснащена CD-ROM’ом (именно так и оказалось в нашем случае), то при попытке открыть эти самые исходные тексты выдается сообщение об ошибке.

Так что, по мнению Microsoft, вы можете не иметь накопителя на гибких дисках (по простому говоря флопа), но накопитель CD-ROM иметь обязаны. Help (см. рис.1) от Microsoft – это HELP .

каждую букву этого слова хочется написать, нет, высечь из камня наподобие лиц американских президентов, как это сделано где-то не то в Неваде, не то в Алабаме.

Help поистине огромен (в полном варианте где-то около 1.5 Гб), в нем можно найти десяток-другой вхождений практически любого слова или словосочетания – будь он русским, вероятно, нашлось бы и “мама мыла раму”.

Трудно сказать, что это неоспоримое достоинство, особенно если вы пытаетесь найти список документов по какому-то контексту и получаете 1000 вхождений (совсем как в Internet). Вообще Help стал более обширным, но менее читаемым. Собственно HЕLP - это, несколько урезанная версия MSDN (Microsoft Developer Network – сеть для разработчиков от компании Microsoft): кроме собственно справочной информации сюда входит масса дополнительной информации, такой как книги и периодические издания по программированию, изданные под патронажем Microsoft.

Вот список литературы представленной в MSDN Library Visual Studio 6.0 release: Developing International Software for Windows 95 and Windows NT, Advanced Microsoft Visual Basic 5, Hardcore Visual Basic, Inside OLE 2nd Edition (эта самое профессиональное издание, описывающее технологии OLE 2 и COM, можно сказать библия, которая к сожалению никогда не продавалась ни в исходном, ни в переведенном виде в нашей стране), Microsoft® Jet Database Engine Programmer’s Guide, Understanding Thin-Client/Server Computing, The Windows Interface Guidelines for Software Design.

В общем HTLP работает корректно, но иногда пытаясь перейти на описание какой-либо функции, вы оказываетесь в совершенно не относящемся к ней месте (за время нашей работы над тестами такие казусы приключились четыре раза в разных местах).

Зато оформлен Help красиво – еще бы, ведь он сделан на aaca Internet Explorer’a 4.01, который, кстати, тоже придется установить при инсталляции Visual Studio. Что нового в Visual C++ Microsoft Visual С++ 6.0 содержит множество новых возможностей, которые предназначены для помощи разработчикам в создании приложений с высоким быстродействием. Приведем некоторые из них: Внесение изменений в код при отладке и ее продолжение без необходимости прерывания сеанса отладки, перекомпоновки, повторного запуска отладчика и возвращения приложения в состояние, при котором возникла проблема.

Эта функция работает в общем, неплохо. Но при ее использовании есть определенный риск (особенно на медленных машинах, например, Pentium 120 c 64 MB RAM) не дождаться окончания компиляции, перекомпоновки и т.д. Технология IntelliSense увеличивает продуктивность и заметно упрощает программирование благодаря автоматическому перечислению членов, информации о параметрах, комментариев к коду и завершению написа-ния конструкций, что устраняет необходимость в запоминании сложных правил синтаксиса, параметров, свойств и методов объектов.

Нечто подобное вы могли увидеть в Delphi и Visual Basic - под названием Complete Word. Динамическое обновление отображения классов облегчает навигацию по коду (добавленные переменные, члены или методы немедленно отображаются в СlassView, без необходимости перекомпоновки). Это, несомненно, большое достижение для С++. Как и любое новое средство, оно нуждается в доработке. Например, в следующих версиях динамическое обновление отображения классов наверняка перестанет тормозить после добавления inline-функций в большие header-файлы.

На 15-30 процентов (в зависимости от типа компиляции) увеличена производительность компилятора. Настройка линкера Delay Load Imports позволяет приложениям, созданным при помощи Visual С++, подгру-жать библиотеки (DLL) только при необходимости. Это снимает требование загрузки библиотеки до момента её использования.

С Composite Controls вы получаете новейшие для VC возможности создавать ActiveX'ы (в Delphi и Visual Basic ) — простое использование повторно используемых элементов управления ActiveX внутри собственных эле-ментов, что позволяет создавать полностью настраиваемые элементы управления. Однако корректной работы Composite Controls удалось добиться только при их использовании в MFC-приложениях. Если в Composite Controls используется хотя бы один ActiveX, то приложения, не использующие MFC, просто отказываются ра-ботать.

По роковой случайности Visual Basic именно такое приложение. Использование новых общих элементов управления придаст пользовательскому интерфейсу стиль Internet Explorer 4.0. Это можно считать как достоинством, так и недостатком — в зависимости от вашего отношения к интерфейсу Internet Explorer 4.0.

Шаблоны потребителя и провайдера OLE DB позволяют получать доступ ко всем типам данных или обеспе-чить унифицированный доступ к своим донным при минимальном программировании. Просмотр таблиц, изменение данных и создание SQL-запросов в IDE для любой ODBC- или OLE DB-базы данных.

Визуальное проектирование и модификация схем и объектов для Microsoft SQL Server и Oracle 7.3.3+. К сожалению, по вполне понятным причинам, нам не удалось собственноручно проверить работу пакета с интеграцией кода с мэйнфрейм-системами и сервисами транзакций при помощи Customer Information Control Systems (CICS).

Visual C++ 6.0, установленная на компьютер с процессором P120 (64 Мб оперативной памяти) под Windows NT 4.0 (Service Pack 3), работала не слишком быстро, но, в общем, приемлемо – в основном тормозил Help и загрузка проектов.

Можно предположить, что реальной минимальной конфигурацией для работы на Visual C++ 6.0 будет P100 с 36/48 Мб оперативной памяти для Windows95/NT – на более слабых машинах все действия будут выполняться слишком медленно. Программирование на Visual C++, особенно после работы на продуктах Inprise (Delphi и C++ Builder), поначалу кажется ужасно медленным – то, что делалось в одно движение теперь приходилось делать в четыре.

Во-первых, Visual C++ — не такое уж быстрое средство “быстрой разработки приложений” – приходится только мечтать о богатом и разнообразном наборе детально проработанных компонентов типа DBGrid, Query, DCOMConnection и ClientResultSet (сравните ради интереса TreeView из Delphi и из Visual C++, и станет понятно, что мы имеем в виду), а во-вторых, мы сознательно старались прижаться как можно теснее к API, поскольку именно прозрачный доступ к функциям API и хорошая их документированность позволяют создавать компактные и высокопроизводительные программы и компоненты.

К сожалению библиотека “Microsoft Foundation Class” (MFC) – основная объектно-ориентированная библиотека, входящая в поставка VC, сделана как обертка API и не дает ощутимого преимущества в областях, не связанных с документно-ориентированными графическими интерфейсами.

К тому же, в отличие от продуктов Inprise и Sybase, VС не поддерживает собственных визуальных компонентов — вместо этого можно использовать стандартные элементы интерфейса Windows (они универсальны, но невзрачны, а дополнение стандартных элементов новыми свойствами — тяжелая работа) или ActiveX’ами, множество которых поставляется с MSVS.

В наших тестах мы не обнаружили особого выигрыша от использования MFC. Зато в поставку VC входит библиотека ATL (Active Template Library) — это очень компактная библиотека, позволяющая создавать как ActiveX-компоненты, так и удаленные DCOM-серверы. За все время нашей работы над тестами среда Visual C++ ни разу не вылетела ни по явным, ни по неявным причинам, а библиотеки проектов или исполняемые файлы никогда не оказывались необоснованно заблокированными средой, как это периодически наблюдалось в продуктах других производителей.

Свойственное большинству продуктов Microsoft стремление помочь пользователю даже тогда, когда он этого не хочет, в редакторе кода Visual C++ невероятным образом ограничено и приходится как нельзя кстати – вообще, нам понравился редактор кода: из всех рассматриваемых в наших обзорах средств разработки он, безусловно, лучший. В нем впервые для C++ присутствует и работает Complete Word (что, учитывая сложность языка C++, является большим достижением).

Правда, надо признать, что реализация Complete Word’а совсем сырая, так он зачастую путается с переменными, тип которых описан через typedef, и не показывает функции из template классов. Не меньшим достижением можно считать существенно возросшую по отношению к предыдущим версиям скорость компиляции проекта – конечно, он работает намного медленнее, чем компилятор Object Pascal в Delphi, но, затраты времени на компиляцию в этих двух средах уже по крайней мере сравнимы, а C++ Builder и Power++, по нашим впечатлениям, отстают от них обоих и довольно значительно.

Удобно сделана отладка проекта, в том числе и в схеме клиент-сервер DCOM (рис. 2). При отладке COM-объектов (например, нашего ActiveX’a) можно использовать содержащее его приложение, специальный Test Container или просто Visual Basic. Выбор осуществляется в меню Project/Settings на закладке Debug (поле “Executable for debug session”). Разумеется, при отладке можно трассировать выполнение программы, просматривать содержимое переменных и области памяти, а также регистры процессора.

Самый простой способом трассировки кода DCOM-сервера заключается в установке точки прерывания в коде клиента на вызове метода сервера, после чего, при остановке выполнения на этом месте, выполняется Step Into (F11), в результате чего загружается вторая копия среды Visual C++ с проектом сервера в режиме отладки.

Если связать два проекта в пределах одного WorkSpace, то любое изменение в одном из них будет приводить к перекомпиляции обоих (связать проекты можно в меню Project/Dependencies). Мы использовали связь между DCOM-проектами клиента и сервера, чтобы синхронизировать их и быть уверенным в том, что не забыли перекомпилировать, скажем, сервер, перед запуском только что перекомпилированного клиента.

Ошибка в дереве WorkSpace с раздвоением функций, когда на закладке Class View каждая ветка дерева получает своего “двойника”, не приводит к нарушениям в работе, а всего-лишь несколько сбивает с толку не привыкших к этому программистов (со временем привычка появляется J). Наши тесты показали, что Class View плохо справляется с очень большими проектами и в некоторых случаях VC не может открыть Workspace, который она сама только что сохранила.

Надеемся, что в продажной версии (или в ближайших “сервис-паках”) эта проблема будет устранена. В Visual C++ можно создать несколько конфигураций для одного проекта (конфигурацию, с которой вы работаете в данный момент, можно установить в меню Build/Set Active Configuration).

Для новых проектов визард VC создает несколько таких конфигураций: Win 32 Debug, Win 32 Debug Unicode, Win 32 Release… (см. рис. 3) Для отладки, разумеется, используется режим Debug, а для создания окончательной версии в ATL проекте можно выбрать Release MinDependency (весь код объединяется в одной dll) или MinSize (исполняемый файл становится меньше, но появляется необходимость таскать за собой ATL.DLL).

Можно задать свой сценарий компиляции, если в меню Project/Project Settings выбрать закладку Custom Build. В случае, если после стандартной компиляции приходится выполнять еще какое-то дополнительное действие, например запуск bat-файла. Мы использовали эту возможность для компиляции DCOM-проекта: дело в том, что возвращаемые нами массивы являются типами, несовместимыми с Automation, и для их поддержки в VC необходима так называемая DLL посредник/заглушка (Proxy/Stub DLL) или просто заглушка, выполняющая передачу (маршалинг) содержимого параметров функций между машинами.

Код заглушки генерируется автоматически при компиляции проекта DCOM сервера, но компилировать заглушку надо вручную. Чтобы не утруждать себя лишней работой (не забывайте, ведь лень — двигатель прогресса), мы и воспользовались Custom Build.

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

Чтобы этого не происходило, мы создали файл stub.bat в текущем каталоге проекта DCOM-сервера со следующими командами: После этого мы добавили вызов stub.bat в Custom Build, для чего в поле Commands вписали вызов “call stub.bat”, а в Outputs – “$(TargetDir)\msDCOM_1_Testps.dll”. Логично было бы сделать это автоматически при создание проекта, но, по непонятным соображениям, в Visual C++ это не сделано.

После модификации установок проекта, закладка Custom Build стала выглядеть так же, как на рис. 3. ActiveX-компонент TreeView, работающий с базой данных Безусловно, в VC хорошо поддерживается технология COM — иначе и быть не могло, ведь спецификация ActiveX родилась именно в Microsoft. Создание компонента ActiveX не представляет каких-либо проблем, для чего также в VC как в Delphi или в C++ Builder’e, используется соответствующий Wizard.

Запустить этот Wizard можно из меню File/New с закладки Projects. Здесь есть целых два Wizard’а: “MFC ActiveX ControlWizard” и “ATL COM AppWizard”.

ActiveX компонент, созданный с помощью MFC, больше по размеру (или тянет за собой MFC DLL) и не поддерживает dual-интерфейсов, а создать на MFC DCOM-сервер, реализованный как сервис NT, вообще невозможно. По этой причине был выбран “ATL COM AppWizard”. Мы назвали создаваемый проект “Atl02Test” – и да не осудят нас за неброское название. В появившемся после нажатия кнопки “OK” окне мы выбрали опцию Dynamic Link Library(DLL) и нажали Finish. Созданный нами проект является пустым — необходимо добавить в него COM объект.

Сделать это можно, если выбрать из меню “Insert” пункт “New ATL Object…” или нажать правую кнопку мыши на название проекта (“atl02Test Classes”) в ClassView и в появившемся меню выбрать пункт “New ATL Object…” (см.

рис. 4). В появившемся Wizard’e мы выбрали Full Control (в категории Controls), после чего назвали объект “atl01”. На закладке Attributes мы включили опции: Support ISupportErrorInfo и Support Connection Points. На закладке Miscellaneous в поле “Add control based on” выбрали SysTreeView32. После нажатия на кнопку OK все зажужжало, и в дереве WorkSpace появился новый класс с именем Сatl01.

В принципе, после компиляции ActiveX компонент TreeView уже готов и зарегистрирован в системе, но никакой функциональной нагрузки он пока не несет — впереди еще не один килобайт кода, который непременно следует добавить. В первую очередь, поскольку компонент должен работать с базой данных (в нашем случае, с MSКSQLКserver), мы выбрали ODBC, для чего добавили в header файл “stdafx.h” строку #include <SQLEXT.H>. Для работы с базой в файле atl02Test.cpp мы объявили несколько переменных: И продекларировали часть из них (те, которые там используются) в файле atl01Ctrl.h: А одну из них – в файле atl01Ctrl.cpp: extern HIMAGELIST g_hImageList1; После этого несложного действия мы несколько изменили функцию DllMain (она находится в папке Globals (ClassView)), которая вызывается при загрузке-выгрузке DLL нашего ActiveX’a.

На загрузку DLL (DLL_PROCESS_ATTACH) мы создали ImageList, PopupMenu (все компоненты, независимо от того сколько их будет создано в приложении, будут использовать одну и ту же копию этих объектов) и инициализировали переменные для работы с базой данных, а на выгрузку DLL (DLL_PROCESS_DETACH) – освободили занятые ресурсы: После написания этого кода, мы переместились на функцию OnCreate (в файл atl01Ctrl.h) — кстати, такой переход удобно осуществлять с помощью двойного щелчка мыши на названии функции в ClassView.

В этой функции собственно и создается компонент TreeView – мы лишь добавили несколько флагов в m_ctlSysTreeView32.Create. Здесь m_ctlSysTreeView32 – глобальная переменная для создаваемого TreeView: В функции InitializeAll выполняются действия, следующие за созданием окна компонента TreeView (кстати, создавать свои функции, методы, переменные и т.п.

удобнее всего из всплывающего меню, которое появляется по щелчку правой кнопки мыши на ветке “Catl1 Ctrl в ClassView (рис.5): После выполнения инициализации TreeView отобразит корневую ветку с названием “Root” и плюс перед ней, (плюс указывает на наличие дочерних веток). На самом деле, никаких дочерних веток у ветки “Root”, пока она закрыта, нет – они существуют только в базе данных. Чтобы эти ветки появились в дереве, надо обработать событие Expanding, которое срабатывает перед раскрытием ветки (например, после нажатия на плюс или на кнопку “*”).

Раз уж мы собрались обрабатывать событие Expanding, то неплохо бы посмотреть, какие еще события будут полезны для нашего теста? Поскольку дочерние ветки будут создаваться в дереве при попытке раскрыть ветку, то необходимо удалять дочерние ветки из дерева после закрытия ветки – родителя. Событие Collapsed вылавливается в событии Expanded по флагу TVE_COLLAPSE, поскольку и TVN_ITEMEXPANDED и TVN_ITEMEXPANDED срабатывают с одинаковым успехом и на закрытие, и на раскрытие ветки.

Разница заключается во флагах, которые можно получить из nmTreeView->action: закрытию ветки соответствует флаг TVE_COLLAPSE, а раскрытию ветки — TVE_EXPAND.

Кроме того, мы обработали событие завершения редактирования текста ветки (TVN_ENDLABELEDIT) и на щелчок правой кнопкой мыши (NM_RCLICK). Последнее мы выбрали для вызова всплывающего меню. Все описанные выше события относятся к сообщению WM_NOTIFY, для установки обработчиков которого используется макрос NOTIFY_CODE_HANDLER в Message Map’e: Функции-обработчики событий мы описали вручную, наверное потому, что нам так больше понравилось (а может потому, что программисты из Microsoft забыли сделать поддержку для сообщений TVN_*, NM_* и WM_NOTIFY, ограничившись поддержкой только стандартных WM_* сообщений).

Вот код этих обработчиков: Трудно не заметить, что в вышеописанных обработчиках событий используются некоторые, еще не описанные нами в тексте функции. Вот их описание: После описания всех этих функций осталось только создать у нашего ActiveX’a свойство CurID_RT, и компонент будет работать так, как требуется. Для создания свойства проще всего щелкнуть правой кнопкой мыши на ветке Iatl01Ctrl в Class View, и во всплывшем меню выбрать “Add Property”.

В появившемся Wizard’e “Add Property to Interface” мы установили Property Type в long и поле Property Name в CurID_RT (остальные настройки оставили неизменными). При нажатии на OK создались заглушки для функций get_CurID_RT(long *pVal) и put_CurID_RT(long newVal).

Параметры pVal и newVal были созданы по умолчанию, чтобы изменить их названия соответственно на pID_RT и ID_RT пришлось руками перебить описания этих функций в файлах atl02Test.idl, atl01Ctrl.cpp и atl01Ctrl.h (здесь проявляется явное отставание от Inprise продукты которого оснащены визуальным редактором автоматически обновляющем все файлы).

Вообще, изменение названий обычных функций, а особенно методов и свойств ActiveX компонентов, выполнять неудобно – приходится все это делать ручками, причем изменение описания в cpp-файле приводит к невозможности перейти на объявление в header-файле через соответствующий пункт всплывающего меню. Будем надеяться, что раз уж сделали в Visual C++ удобную навигацию по проекту, так не грех предусмотреть в следующих версиях продукта и удобную возможность редактирования названий и описаний функций.

А пока мы вручную изменили во всех трех местах названия параметров для функций свойства CurID_RT и описали реализацию этого свойства следующим образом: Как вы заметили, в функции put_CurID_RT использовался вызов SQL Stored-процедуры “GetALLParent”. Текст этой процедуры приводится ниже: Ну вот и все с ActiveX’ом. Осталось только создать тестовое приложение (лучше всего сделать это в Visual Basic’e, поставляемом в комплекте Visual Studio – для того, чтобы сохранить Microsoft-чистоту эксперимента).

Мы полностью повторили внешний вид тестовых приложений, уже не раз созданных при работе с продуктами Inprise и Sybase – наш ActiveX, поле редактирования и две кнопки: первая GetCurID_RT, а вторая, само собой, SetCurID_RT.

По нажатию на GetCurID_RT в поле редактирования записывается полученный номер текущей записи, а по нажатию на SetCurID_RT в ActiveX’e выделяется ветка с номером из поля редактирования. Сверхсложный код обработок нажатия на эти две кнопки приведен ниже (здесь atl01Ctrl1 – название нашего ActiveX, а dfCurID_RT – название поля редактирования): После запуска Visual Basic-приложения (VB) можно понаблюдать за работой компонента (рисунок 6), и заодно посмотреть объемы занимаемой им памяти.

Поскольку вся функциональность находится в ActiveX’e, будем учитывать только его размер (ведь, к тому же, мы рассматриваем Visual C++, а не Visual Basic). Наш ActiveX, скомпилированный в режиме MinDependеncy, занял на жестком диске 61 Кб (он находится в …\ReleaseMinDependency\atl02Test.dll ). Никаких дополнительных библиотек при этом режиме компиляции не требуется (естественно исключая библиотеки доступа к БД, в DCOM тесте мы избавимся и от них), поэтому можно считать это значение окончательным – понятно, что на действительно больших объемах кода разница с аналогичными компонентами, написанными, скажем, на Delphi (там такой ActiveX занял 600 Кб без учета BDE и библиотеки доступа к БД (DB-LIB)) будет не столь убийственна, но не отметить ее нельзя.

К нашему величайшему сожалению, когда мы встроили ActiveX, сделанный на Delphi, в тестовый проект, сделанный на VB, среда VB вылетела при закрытии VB-приложения с сообщением об ошибке 216, повторяющемся в бесконечном цикле. Причем, если запускать полученный Exe не из-под отладки Basic’a, а сам по себе, такой беды не происходит. Честно говоря, разбираться в том, “кто виноват и что делать” не входило в наши планы, поэтому мы создали одинаковые тесты для ActiveX’ов, сконструированных на Visual C++ и Delphi на Delphi4 (об ошибке 216 мы уже говорили в обзоре по Delphi4).

Итак: созданный на Delphi4 ActiveX, встроенный в тестовый проект, созданный на той же Delphi, занял 3 Мб в оперативной памяти. Полностью такой же тестовый проект с ActiveX’ом, созданным на Visual C++, занял 1.1 Мб. При этом возник небольшой сбой в Delphi design-time: при изменении размера ActiveX’a его размер менялся как-то странно (на месте оставалась рамка старого размера) – однако расхождение в понимании методов изменения размеров компонентов (alignment, resize или как вам будет угодно) между Visual C++ и Delphi трудно отнести к недостаткам какого-либо одного из этих двух продуктов (Заметим только что в VB размеры этого компонента изменялись правильно).

Многоуровневое приложение Прежде, чем делать какие-то общие выводы, мы создали DCOM тест для трех уровневой схемы клиент-сервер. Мы не стали изобретать DBGrid (это совсем не так уж просто!) и использовали в качестве DCOM-клиента тестовое приложение, созданное нами ранее для ActiveX’a “atl01Ctrl” (оно хранится в библиотеке “atl02Test”).

Само собой разумеется, что некоторые функции этого ActiveX’a пришлось переписать, поскольку всю работу с базой данных мы вынесли на серверный объект, который в связи с этим получил методы AddNode, DeleteNode, UpdateNode, GetSubNodes и GetAllParentes.

Как мы это сделали: сначала мы создали новый WorkSpace и назвали его “Test_1_ALL”, затем скопировали в образовавшийся каталог проект с ActiveX’ом (“atl02Test”) и добавили его в WorkSpace Test_1_ALL — это для DCOM-клиента. После этого мы создали в этом же WorkSpace новый проект с названием “msDCOM_1_Test”, выбрав при создании проекта на закладке “Projects” Wizard c названием “ATL COM App Wizard”.

После запуска Wizard’a уcтановили “Server Type” в Service (EXE) и, нажав OK, получили проект для DCOM-сервера. Затем с помощью Wizard’a New ATL Object добавили в проект объект Simple Object из категории Objects, дав ему имя “msDCOM_1_srv” и установив атрибуты так же, как мы делали это при создании ActiveX-теста. Добавив в header-файл stdafx.h строку “#include <SQLEXT.h>” для работы с SQL-сервером через ODBC, мы описали в файле msDCOM_1_Test.cpp следующие переменные: После чего продекларировали их в файле msDCOM_1_srv.cpp, (кроме bOK) поскольку они будут там использоваться: Затем, в функции _tWinMain перед строкой “_Module.Start();” добавили свой код инициализации работы с базой данных и, в файл msDCOM_1_srv.h, написали свою inline-функцию SQL_OK (для упрощения проверок возвращаемых значений ODBC функций: Кроме этого, надо описать в функции Run проверку на bOK: Для того, чтобы DCOM-сервер все-таки работал, а не просто радовал нас своим существованием, мы добавили в интерфейс ImsDCOM_1_srv методы AddNode, DeleteNode, UpdateNode, GetSubNodes и GetAllParentes (проще всего для этого воспользоваться Wizard’ом “Add Metod” из вплывающего меню на ветке ImsDCOM_1_srv в дереве ClassView – рис.

7.): Мы постарались дать исчерпывающие комментарии к этому коду в тексте функций, но повторим вкратце основные положения: • метод AddNode создает новую ветку.

Этот метод в параметре Parent получает значение ID ветки-родителя, для которой надо добавить дочернюю ветку, в параметре Name — шаблон имени задающегося по умолчанию (“Новый элемент № %d” или что-то вроде этого), и возвращает в параметре *pID_RT номер созданной ветки; • метод DeleteNode удаляет ветку.

В параметре ID_RT получает номер ветки, которую следует удалить; • метод UpdateNode изменяет название ветки. Этот метод в параметре ID_RT получает ID ветки, которой следует изменить название, а в параметре Name – новое название; • метод GetSubNodes возвращает список всех дочерних веток для указанной ветки. Этот метод в параметре ID_RT получает ID ветки-предка, для которой ищутся дочерние ветки. В параметре **pArrID возвращается указатель на массив указателей на номера дочерних веток, в параметре **pArrName — указатель на массив указателей на названия дочерних веток (типа BSTR), в параметре **pArrChildrenCount – указатель на массив указателей на количество дочерних веток каждой из найденных дочерних веток (ставить перед ними плюсы, или нет), а в параметре *count возвращается указатель на количество дочерних веток (это же – размер массивов).

Кроме всего прочего *count используется при описании метода GetSubNodes (см. файл msDCOM_1_Test.idl); • метод GetAllParentes возвращает список всех предков для указанной ветке в порядке погружения от корневой ветки до ветки-родителя. Этот метод получает номер ветки, для которой ищутся предки, и возвращает в параметре **pArrParent указатель на массив указателей на номера веток-предков, а в параметре *count – указатель на количество веток-предков.

Работает по образу и подобию метода GetSubNodes, отличаясь только количеством массивов и SQL-запросом. Не правда ли, слово “указатель” встречалось в этом описании довольно часто? Такие структуры, как указатель на массив указателей, не всегда бывают понятны не только широкому кругу читателей, но и некоторым Visual Basic’ам, поэтому необходимо компилировать Visual C++ проект с использованием proxy/stub (как мы это описывали в начале этого обзора).

Если случайно про это забыть, то при попытке запустить DCOM-сервер клиентское приложение закричит дурным голосом, что произошла ошибка 0x80020008 (что-то вроде – неверный тип данных). После компиляции проекта DCOM-сервера с proxy/stub (и последующей регистрации этой самой proxy/stub) проблема отпадает как бы сама собой, однако предупреждения на описание методов GetSubNodes и GetAllParentes по прежнему будут выдаваться компилятором MIDL не обращайте на них внимания.

На этом наш DCOM-сервер можно считать законченным. Клиентское приложение тоже практически готово, и немного изменить его, чтобы оно вызывало DCOM-сервер и работало с ним – просто минутное дело.

Для начала мы удалили из файла stdafx.h строку “#include <SQLEXT.H>” и объявления переменных hdbc2, hdbc, henv, hstmt, hstmt2 из файлов atl02Test.cpp и atl01Ctrl.h – ведь вся работа с базой данных выполняется теперь DCOM-сервером, после чего добавили в файл atl02Test.cpp строки: И в файл atl01Ctrl.cpp: Это позволило нам использовать описания интерфейсов DCOM-сервера.

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

Для создания такого диалога мы добавили в проект DCOM-клиента (atl02Test) новый ATL object типа Dialog из категории Miscellaneouse и назвали его CLoginDlg (не очень удачно, т.к. название класса получилось CCLoginDlg). Добавив на появившуюся форму поле редактирования (в списке компонентов оно называется Edit Box), мы дали ему ID (уникальный идентификатор) “IDC_EDIT_ServerName” — по этому ID мы будем обращаться к полю редактирования из текста программы.

Примечание: MFC позволяет создать переменную “обертку” типа CString или CEdit для более удобной работы с полями редактирования, но наш проект основан на ATL и не поддерживает такой функциональности. Установить ID проще всего, вызвав всплывающее меню на размещенном на форме компоненте и выбрав Properties (рисунок.

8) – на первой же закладке можно вписать ID. Добавив строку: #include “CLoginDlg.h” в файл atl02Test.cpp мы подключили этот диалог к проекту DCOM-клиента. Единственной целью нашего Login-диалога является получение и передача имени удаленного компьютера в то место, где его очень ждут – перед вызовом CoCreateInstanceEx (именно таким путем мы запускали серверное приложение). Для успешного выполнения поставленной боевой задачи мы описали в классе CCLoginDlg (файл CLoginDlg.h) переменную: После чего изменили обработчики: нажатия кнопки “OK” и инициализации диалога следующим образом: Теперь, когда диалог уже был описан, мы удалили всю инициализацию работы с базой данных из DllMain и перенесли создание всплывающего меню и Image-листа в функцию DllGetClassObject (для того чтобы не создавать их при регистрации DLL'и), после чего добавили в нее же создание DCOM-сервера на удаленной машине.

В том же файле (atl02Test.cpp ) объявили глобальную переменную ImsDCOM_1_srv (для интерфейса ImsDCOM_1_srv DCOM-сервера, в котором описаны наши методы) и флаг g_bLoading, чтобы создание сервера происходил только один раз при создании первого ActiveX компонента: Осталось изменить реализации для некоторый функций, где обращения к базе данных заменить на вызовы методов DCOM-сервера, и клиентское приложение будет готово: После того, как весь этот код был описан, мы получили работающие сервер и клиент (в качестве клиента используется все тот же тестовое приложение, написанное на VB), которое мы сделали для тестирования ActiveX’a).

После компиляции в режиме ReliseaMinDependancy (убедившись, что в Properties для проекта DCOM-сервера добавлены Link’и к библиотекам odbc32.lib odbccp32.lib, причем для всех режимов компиляции). Запустив клиента и указав ему имя локальной машины для поиска сервера, мы запустили DCOM-сервер на том же компьютере, что и клиента: при этом новые клиенты подключались к уже созданному серверу – т.е.

все работало, как надо. Загруженная и работающая пара DCOM-клиент-сервер заняла в оперативной памяти около 2 Мб, каждый новый клиент занимал по 1 Мб (как для теста, написанного на VB, так и для теста, написанного на Delphi4). Клиентский ActiveX занял на диске около 80 Кб плюс msDCOM_1_Testps.dll около 25 Кб, тогда как DCOM-сервер – около 70 Кб. Для запуска клиента с удаленной машины очень важно не забыть зарегистрировать на ней библиотеку с ActiveX-клиентом (atl02Test.dll) и библиотеку с proxy/stub-заглушкой (msDCOM_1_Testps.dll) – без этих действий клиент работать не будет!

Напомним, что msDCOM_1_Testps.dll требуется нам из-за массивов, которые передаются при вызовах GetAllParentes и GetSubNodes. Также надо настроить права доступа к серверу в dcomcnfg.exe на серверной машине (мы подробно описывали это в предыдущих тестах).

Если запускать этот сервер из-под Windows NT, то, вероятнее всего все необходимые библиотеки уже будут установлены в системе – например, библиотека msvcrt.dll почти наверняка лежит в каталоге System32, т.к. большинство продуктов Microsoft ее используют. Visual C++, несомненно, не самое быстрое средство разработки приложений: затраты времени на создание наших тестовых примеров на этом средстве были в 2-4 раз больше, чем при решении аналогичной задачи на Delphi4 или C++ Builder’e.

Однако, однажды написав ActiveX-компонент (или DCOM-клиент-сервер) с использованием ATL можно быть практически полностью уверенным, что все его сбои вызваны исключительно ошибками программиста и не связаны со средой разработки. Что же касается Delphi4 или C++ Builder’a, то нередко просто невозможно понять, в чем причина сбоя. Чтобы не погрешить против правды, отметим, что в исходных текстах Delphi можно найти объяснение для многих загадочных явлений (мы описывали некоторые в предыдущем обзоре), но часть из них остается для нас загадкой и по сей день.

Нельзя не признать, что программирование на Visual C++ требует более высокой квалификации программиста, тогда как, к примеру, на Delphi4 большинство стандартных задач решаются в основном путем набрасывания готовых (достаточно детально проработанных компонентов) и связывания их между собой. Хотелось бы отметить также, что размер создаваемых на VC библиотек или исполняемых файлов получается значительно меньше, чем у аналогичных объектов, созданных на Delphi (хотя вряд ли это имеет решающее значение для пользователей, работающих на современных машинах с многогигабайтными жесткими дисками и сотнями Мб оперативной памяти).

Но для распространения через Internet размеры компонента играют одну из главных ролей. В результате работы над тестами по поддержке средствами разработки технологий ActiveX и DCOM, мы сделали некоторые выводы, которые вкратце сводятся к следующему: из протестированных нами сред (Delphi4 и С++ Builder3 корпорации Inprise, Power++ 2.1 корпорации Sybase и Visual C++ корпорации Microsoft) в полной мере поддерживают технологии ActiveX и DCOM только продукты Inprise и Microsoft — Power ++, к сожалению, не дает возможности создавать ActiveX-компоненты и поддерживает распределенную технологию только для MS Transaction Server и Jaguar; • самым быстрым из протестированных нами средством разработки ActiveX-компонентов и DCOM-приложений можно признать Delphi, несколько отстает от нее C++ Builder (в основном за счет медленной компиляции, и сравнению с Delphi и VC, среды); Visual C++ имеет наибольшее количество вспомогательных средств; среда Visual C++ более стабильна, чем среда Delphi и, тем более, C++ Builder и Power++; редактор кода в Visual C++ лучше, чем в Delphi, а Complete Word — хуже (в C++ Builder’e Complete Word вообще отсутствует); ActiveX-компоненты, написанные на Visual C++ (особенно те, которые работают с базами данных), занимают меньше места и работают надежнее, чем написанные на Delphi или C++ Builder’e.

Visual C++ более пригоден для разработки массовых, высокопроизводительных систем, серверов, драйверов… ну, в общем, тяготеет к системной разработке. Но сочетание Visual C++ и Visual Basic, по нашему мнению, может ускорить разработку за счет легкости и производительности Basic'а и поднять профессиональный уровень продукта за счет богатейших возможностей Visual C++.

Delphi, С++ Builder и Power++ имеют более богатый набор компонентов и больше подходят для создания внутрикорпоративных систем автоматизации и заказных систем, а то, что все перечисленные продукты являются настоящим компиляторами, позволит обойти большинство проблем связанных с ошибками в библиотеках и узкими местами в производительности.

Итак, можно завершить наше исследование такими словами: из протестированных нами средств Visual C++ 6.0 наилучшим образом подходит для разработки ActiveX-компонентов и DCOM-приложений, особенно, если основным критерием является надежность работы приложений.

Когда надежность не является столь критичной, а на первом месте стоит минимизация времени, потраченного на разработку приложений, Delphi4 получает очевидные преимущества. C++ Builder3 практически по всем показателям проигрывает Delphi4 (принципиальные споры о том, что лучше — Object Pascal или C++, мы оставим в стороне). Но, все же, с его помощью можно куда быстрее получить конечный результат, чем используя Visual C++ 6.0.

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

С вопросами и предложениями обращайтесь [email protected]


Добавить комментарий

Ваша почта не будет опубликована.

*

*