- •Лабораторные работы по курсу «Современные технологии и инструментарий программирования»
- •1. Разработка и использование «обычных» библиотек dll (cui)
- •1.1.Бесценные методические приказания
- •2.Разработка и использование dll-расширения
- •Ознакомиться с теоретической частью работы, для чего придется изучить раздел конспекта «Разработка и использование собственных dll», особенно подраздел «Основы dll».
- •2.1.Разработка библиотеки-расширения
- •2.2.Разработка клиентского приложения для dll-расширения
- •3.Разработка внутрипроцессного сервера и клиентского приложения с использованием atl
- •Часть 1. Разработка простого внутрипроцессного сервера сом, реализованного в виде библиотеки dll
- •Interface iMathem2; // добавлено
- •Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера сом
- •4.Разработка и использование локального сервера
- •Часть 1. Разработка локального сервера сом
- •Часть 2. Разработка клиентского приложения для локального сервера сом
- •Литература
- •7. Проект New_Syntax
- •8. Руководство_по_c#.Doc
4.Разработка и использование локального сервера
Квалифицированный специалист - это человек, который удачно избегает маленьких ошибок, неуклонно двигаясь к какому-нибудь глобальному заблуждению
Закон Мерфи
Цель работы – освоение техники разработки локального сервера СОМ и клиентского приложения для него (4 час.).
Задание. Работа состоит из двух частей:
Разработка локального сервера, реализованного в виде приложения с графическим интерфейсом пользователя и предоставляющего диспетчерский интерфейс (IDispatch). Это приложение должно предоставлять методы и свойства, предназначенные для рисования графических фигур.
Разработка клиентского приложения для локального сервера.
Попутно предполагается провести еще один тренаж по использованию CDC-объектов, предназначенных для работы с графикой.
Важно. СОМ объект сервера должен иметь методы и свойства, предназначенные для выполнения таких действий:
отображения главного (и, по всей видимости, единственного) окна приложения;
прекращения выполнения приложения;
очистки окна приложения;
рисования какой-нибудь фигуры (не линии и не эллипса);
задания координат и размеров выводимой фигуры.
Часть 1. Разработка локального сервера сом
Методические указания. Предлагается следующая последовательность создания локального COM сервера в MVS-2010:
создание каркаса «обычного» приложения, класс вида которого является наследником класса CFormView;
разработка и отладка методов рисования графических фигур как обычных функций;
добавление СОМ объекта, разработка его методов и свойств.
Шаг 1. Создание каркаса приложения.
Рекомендуется создать папку с именем вроде Lab4 и в ней разместить, в недалеком уже будущем, два проекта: локальный сервер с именем проекта LocSrv и клиентское приложение для него LocSrvClient.
Выполнить тему меню FileNewProject., выбрать Project Types=MFC и Templates=MFC Application. Дадим проекту имя LocSrv и нажмем кнопку ОК.
На следующем шаге (вкладка Application Type) выберем архитектуру приложения с единственным документом (Single Document) и поддержкой технологии документ/вид (Document/View architecture support). Для облегчения каркаса приложения сделайте также остальные установки в соответствии с рис.1.
Установки на вкладках Compound Document Support, Document Template Strings, и DataBase Support можно оставить все установки без изменения.
На вкладке User Interface Features выберите радиокнопку Use classic menu и не пугайтесь предупреждений ИС – ничего она вам не сделает, вы же в танке!
На вкладке Advanced Features важно установить флажки “Automation” и “Common Control Manifest”, а остальные флажки лучше снять.
На вкладке Generated Classes в качестве базового класса (Base class) для класса вид (в нашем случае мастер присвоил ему имя CLocSrvView) выберите, обязательно, класс CFormView, который вы до сих пор не использовали (или уже использовали?). Закончим создание каркаса приложения победоносным нажатием кнопки Finish.
|
Рис. 1. Свойства приложения
Шаг 2. Любуемся пока еще работоспособным приложением.
Итак, каркас приложения создан и, после его сборки и запуска на выполнение мы должны сразу увидеть главное и единственное окно приложения с элементом Static Text посередине, который играет чисто рекламную роль, нам вовсе не нужен и его можно спокойно удалить.
Созданное мастером окно не имеет ничего, кроме собственно рамки, но его внешний вид нас и не очень интересует. Пока у нас есть обычное приложение и никаким сервером оно не является. Его можно построить, запустить на выполнение и убедиться в том, что оно еще работает, так как вы пока не добавляли в него свой код.
Шаг 3. Учимся рисовать.
Прежде чем пытаться создать СОМ объект, который умеет рисовать, давайте попробуем что-нибудь нарисовать «по-простому», без использования методов СОМ объекта. Для этого необходимо в классе вида CLocSrvView создать (перекрыть функцию CFormView::OnDraw()) виртуальную функцию OnDraw(). Чтобы это сделать, надо на вкладке ClassView выбрать CLocSrvView, вызвать окно свойств этого класса (Alt+Enter) и в этом окне щелкнуть кнопку Overrides (рис. 2). В появишемся списке функций надо выбрать OnDraw и сгенерировать ее (с помощью, как мы любим говорить, интуитивно понятного интерфейса).
|
Рис.2. Генерация виртуальной функции CLocSrvView::OnDraw()
Искусник ИС создаст заготовку функции OnDraw() такого нехитрого вида:
void CLocSrvView::OnDraw(CDC* /*pDC*/)
{
// TODO: Add your specialized code here and/or call the base class
}
Снимите комментарий с имени формального параметра pDC, так как он нам понадобится. Кстати, а зачем имя параметра закомментировано, а? Отгадайте.
Рисование в программах на С++, как вы знаете, немножко сложновато, но зато о нем пишут почти в любой книге. Например, в работе [1] о нем можно почитать на с.27-28, в главах 5 и 11. Рекомендуется прямо сейчас, как говорится, в своем же присутствии, ознакомиться с разделами конспекта «6.5. Рисование внутри окна представления: Windows GDI» и «7. Интерфейс графического устройства, цвет и шрифт».
В следующем листинге приведен пример рисования линии и эллипса, занимающих всю клиентскую область окна.
|
Введите текст функции OnDraw(), откомпилируйте и запустите приложение на выполнение. вы должны увидеть окно, похожее на рис. 3. Если в Вашем окне присутствует лишний элемент управления с текстом-подсказкой – удалите его. Попробуйте изменять размеры окна приложения и понаблюдайте при этом за панелью задач: заметили что-нибудь доселе невиданное?
Рис.3. Неповторимый рисунок в окне приложения
Шаг 4. Создание нового класса.
Теперь создадим класс, который и будет представлять собой СОМ объект. В л.р. «Разработка внутрипроцессного сервера и клиентского приложения с использованием ATL» мы создавали СОМ объект с использованием библиотеки ATL, а в этой работе воспользуемся, для разнообразия, другой возможностью – создадим СОМ объект на базе класса MFC.
Выполните команду ProjectAdd Class и в появившемся окне выберите Categories==MFC и Templates==MFC Class, натисните Add. В следующем окне задайте свойства нового класса в соответствии с рис. 4.
Рис. 4. Свойства нового класса CPainter
Особо обратите внимание на то, что в качестве базового надо указать класс CCmdTarget и выбрать радиокнопку Createable by type ID. Выбор последнего свойства позволит использовать сервер из программ на языке VBA (Visual Basic for Application). Кстати, в окошке рядом с этим кнопарем мы увидим внешнее имя нашего сервера LocSrv.Painter, тот самый ProgID, который полезен в клиентском приложении. Шлепайте по кнопке Finish!
Шаг 5. Подготовка сервера.
Ознакомьтесь с содержимым файлов проекта, в частности, сгенерированными мастером файлами Painter.h, Painter.cpp и LocSrv.idl. Первые два файла содержат описания сокласса и его интерфейсов, а методов у СОМ объекта пока нет, так как туповатый мастер ИС не может угадать наши намерения и методы придется создавать самостоятельно.
Если вы посмотрите на вкладку ClassView рабочего пространства, то должны там увидеть класс CPainter и интерфейсы ILocSrv и IPainter. В принципе на этом этапе можно было бы снабдить СОМ объект методами и свойствами, но прежде лучше бы выполнить некоторые подготовительные работы.
Во-первых, для того чтобы в методах класса CPainter можно было рисовать, надо как-то «добраться» до окна вида серверного приложения (класс CLocSrvView) и контекста устройства CDC для него.
Во-вторых, приведите функцию CLocSrvApp::InitInstance(), которая находится в файле LocSrv.cpp, к подобающему виду. Внимательно просмотрите ее текст, в котором есть некоторые изменения по сравнению с исходным текстом, и прочтите комментарии.
|
|
|
|
В принципе в таком состоянии приложение должно компилироваться и работать, почти как и прежде. Можете проверить, что если приложение вызвать на выполнение с параметром командной строки /Unregserver, то главное окно приложения не появится и программа завершится после разрегистрации сервера, что и будет доведено до Вашего сведения в соответствующем оконце. Подобным образом приложение будет себя вести и при его запуске с ключом командной строки /Regserver, только при этом оно будет регистрироваться в реестре, для чего вам понадобятся соответствующие полномочия, и окно с сообщением о регистрации отображаться не будет. Добавить параметр командной строки к приложению можно, например, так:
запустить ехе-файл приложения на выполнение из командной строки, например, воспользовавшись какой-нибудь оболочкой вроде Far или командой «Выполнить» из меню «Пуск»;
в свойствах проекта (Alt+F7) выбрать ветвь Debugging и задать параметр(ы) командной строки в поле Command Arguments.
Если вы пойдете по второму пути, то не забудьте удалить параметр из командной строки, когда он уже не будет нужен!
Если приложение запустить на выполнение с ключом /Embedding (предварительно сняв комментарий с оператора return true), т.е. как будто оно было запущено клиентом, то мы выйдем из обсуждаемой функции CLocSrvApp::InitInstance() без прорисовки окна представления. В результате мы сможем узнать о том, что наше приложение выполняется, либо путем просмотра выполняющихся процессов с помощью Диспетчера задач или из заголовка окна ИС, в котором будет присутствовать желанное слово Running.
Шаг 6. Добавление методов в СОМ объект сервера.
Добавление методов (и свойств тоже) в СОМ объект локального сервера выполняется так же, как для внутрипроцессного сервера, что вы уже проделывали. Для добавления метода надо выбрать вкладку ClassView в окне решений, в ней выбрать ветвь LocSrv и в ней подветвь IPainter, помеченную значком интерфейса . Вызвав контекстное меню для IPainter, выберите команду AddAdd method для добавления метода к интерфейсу IPainter. В появившемся окне надо объявить метод void PDraw(), т.е. выбрать Return type==void и задать Method name==PDraw. Маг ИС добавит метод к интерфейсу объекта и создаст его заготовку в файле Painter.cpp. Подобным же образом создайте еще один метод void Stop().
Замечание. Добавляйте методы интерфейса СОМ объекта обязательно с помощью мастера, т.е. с помощью команды AddAdd method. В принципе это можно сделать и вручную, но надо знать в какие файлы и куда именно нужно добавить необходимые описания.
Когда мы «рисовали» в методе CLocSrvView::OnDraw(CDC* pDC) класса представления, то указатель pDC на контекст устройства нам был предоставлен «на блюдечке с голубой каемочкой». А где его взять в методе CPainter::PDraw()? Один из возможных выходов – использование глобальной переменной. Для этого в файле LocSrvView.cpp надо описать соответствующий указатель и инициализировать его в конструкторе класса CLocSrvView:
CView * glView;
CLocSrvView::CLocSrvView():CFormView(CLocSrvView::IDD)
{
glView=this;
}
Необходимые изменения выделены полужирным шрифтом. Теперь в файле Painter.cpp мы опишем этот же указатель как внешний (extern) и, таким чудодейственным образом, получим указатель на окно вида, с помощью которого, в свою очередь, получим вожделенный указатель на контекст устройства pDC.
Вот пример реализации методов интерфейса IPainter:
|
|
|
Метод Stop() предназначен для остановки работы сервера клиентским приложением, так как по-хорошему сервер завершаться, по крайней мере у меня, не захотел. Функция PostQuitMessage(), как следует из ее имени, просто посылает главному окну приложения-сервера сообщение Quit. В принципе приложение может его и проигнорировать, если его кто-нибудь этому научит.
Операторы
CWnd * pWnd=AfxGetApp()->GetMainWnd();
pWnd->ShowWindow(SW_SHOW);
предназначены для получения указателя на окно приложения и его прорисовки. Так как мы в функции CLocSrvApp::InitInstance() окно показываем всегда, то вызов функции ShowWindow() у нас в данном примере закомментирован.
На этом этапе серверное приложение должно собираться и работать, хотя собственно СОМ объект создаваться и использоваться не будет. Теперь можно удалить код из метода CLocSrvView::OnDraw(), так как дальше мы будем строить клиентское приложение и с его помощью рисовать в окне сервера (рекомендую закомментировать код этого метода или в самом его начале вставить оператор return). С другой стороны, этого можно, конечно, и не делать, если такое поведение приложения не противоречит логике его функционирования.
Замечание. Если оставить какой-либо код в методе CLocSrvView::OnDraw(), то этот код будет выполняться всякий раз, когда изображение в окне должно быть перерисовано. Например, если вы свернете окно и затем его развернете, то будет выполняться код метода CLocSrvView::OnDraw(), а не IPainter::PDraw(). В то же время метод PDraw() вызывается именно и только клиентским приложением.
В каталоге Debug у вас должен присутствовать файл LocSrv.tlb, содержащий библиотеку типов, которая нам понадобится для разработки клиентского приложения.
При запуске сервера как самостоятельного приложения он должен зарегистрировать себя в реестре сам (если, конечно, у вас есть высочайшее разрешение на запись в реестр, а именно в ветвь HKEY_CLASSES_ROOT).
Еще пару комментариев к тексту функции PDraw(). Вызов функции GetClientRect(rect) предназначен для того, чтобы получить размеры действительного прямоугольника окна клиентского приложения. Для того чтобы получить корректный прямоугольник и указатель на контекст устройства pDC, надо передать методу PDraw() указатель на объект вида CView нашего приложения-сервера, что мы и сделали.
Метод AfxGetApp()->GetMainWnd() возвращает указатель на главное окно приложения (окно-рамку). Этот указатель часто бывает весьма полезен не только для отображения окна, как это мы сделали в методе PDraw(), но и для доступа к другим многочисленным свойствам и методам окна-рамки, например:
/*Изменение заголовка главного окна приложения*/
AfxGetApp()->m_pMainWnd->SetWindowTextW(_T("Ку-ку!"));
/*Включение режима «мигания» (flash) заголовка приложения в панели
задач*/
AfxGetApp()->m_pMainWnd->FlashWindow(true);
