Шаг 17.
Технология OLE. Создание сервера OLE (продолжение)

    На этом шаге мы рассмотрим, как задать функциональность созданному серверу.

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

    Допустим, мы хотим сначала заняться вопросами отображения. Как и в любой созданной с помощью AppExpert программе, основная часть рисования выполняется классом отображения, производным от класса OWL TOleView. Файл, в котором содержится реализация отображения, имеет имя LSVROLVW.CPP. Приведем первоначальный текст этого файла с переводом некоторых комментариев:

    Листинг 1. Файл LSVROLVW.CPP

/*  Project olesvr
    
    Copyright c 1994. All Rights Reserved.

    SUBSYSTEM:    olesvr.exe Application
    FILE:         lsvrolvw.cpp
    AUTHOR:       


    OVERVIEW
    ========
    Source file for implementation of olesvrOleView (TOleView).      
    Исходный файл реализации olesvrOleView (TOleView).      
*/


#include <owl\owlpch.h>
#pragma hdrstop

#include "olsvrapp.h"
#include "lsvrolvw.h"

#include <stdio.h>


//{{olesvrOleView Implementation}}
//{{Реализация olesvrOleView}}

//
// Build a response table for all messages/commands handled
// by olesvrOleView derived from TOleView.
// Создать таблицу для всех сообщений/команд, поддерживаемых
// olesvrOleView, производным от TOleView.
//
DEFINE_RESPONSE_TABLE1(olesvrOleView, TOleView)
//{{olesvrOleViewRSP_TBL_BEGIN}}
    EV_WM_GETMINMAXINFO,
    EV_OC_VIEWSHOWTOOLS,
//{{olesvrOleViewRSP_TBL_END}}
END_RESPONSE_TABLE;


//////////////////////////////////////////////////////////
// olesvrOleView
// ==========
// Construction/Destruction handling.
// Обработка создания/уничтожения.
olesvrOleView::olesvrOleView (TDocument& doc, TWindow* parent)
    : TOleView(doc, parent)
{
    ToolBar = 0;

    // INSERT>> Your constructor code here.
    // ВСТАВИТЬ>> В этом месте код вашего конструктора.

}


olesvrOleView::~olesvrOleView ()
{
    // INSERT>> Your destructor code here.
    // ВСТАВИТЬ>> В этом месте код вашего конструктора.

}


//
// Paint routine for Window, Printer, and PrintPreview for a TOleView client.
// Процедура рисования для Window, Printer и PrintPreview клиента TOleView.
//
void olesvrOleView::Paint (TDC& dc, bool erase, TRect& rect)
{
    olesvrApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), olesvrApp);
    if (theApp) {
        // Only paint if we're printing and we have something to paint, 
        // otherwise do nothing.
        // Рисовать только в случае, если необходимо что-нибудь напечатать 
        // или отобразить.
        if (theApp->Printing && theApp->Printer && !rect.IsEmpty()) {
            // Use pageSize to get the size of the window to render into.  
            // For a Window it's the client area,
            // for a printer it's the printer DC dimensions and for 
            // print preview it's the layout window.
            // Использовать pageSize для получения 
            // размера окна для визуализации информации.  
            // Для Window - это рабочая область,
            // для принтера - это размеры контекста устройства,
            // для print preview - это окно формата.
            TSize   pageSize(rect.right - rect.left, rect.bottom - rect.top);

            TPrintDialog::TData &printerData = theApp->Printer->GetSetup();

            // Compute the number of pages to print.
            // Вычислить число страниц, которые необходимо напечатать.
            printerData.MinPage = 1;
            printerData.MaxPage = 1;

            TOcView     *ocView = GetOcView();

            //
            // Default TOcPart painting
            // Рисование TOcPart по умолчанию
            //
            TRect clientRect = GetClientRect();
            TRect logicalRect = clientRect + (TSize&)ocView->GetOrigin();
    
            for (TOcPartCollectionIter i(GetOcDoc()->GetParts()); i; i++) {
    	        TOcPart& p = *i.Current();
    	        if (p.IsVisible(logicalRect)) {
    		        TRect r = p.GetRect();
    		        r -= ocView->GetOrigin();
    		        p.Draw(dc, r, clientRect); // Draw the embedded object.
                                                   // Нарисовать внедренный объект.
    		        if (p.IsSelected()) {
    			        TUIHandle handle(r,
    				                     TUIHandle::HandlesIn       |
    				                     TUIHandle::Grapples        |
    				                     TUIHandle::HatchBorder,
                                         5);
    			        handle.Paint(dc);
    		        } else {
    			        TUIHandle handle(r, TUIHandle::HatchBorder, 5);
    			        handle.Paint(dc);
    		        }
    	        }
            }

            // INSERT>> Special printing code goes here.
            // ВСТАВИТЬ>> В этом месте выполняется печать.

        } else {
            TOleView::Paint(dc, erase, rect);

            // INSERT>> Normal painting code goes here.
            // ВСТАВИТЬ>> В этом месте выполняется обычное рисование.

        }
        dc.TextOut(0, 30, "olesvr OLE Server");
    }
}


void olesvrOleView::EvGetMinMaxInfo (MINMAXINFO far& minmaxinfo)
{
    olesvrApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), olesvrApp);
    if (theApp) {
        if (theApp->Printing) {
            minmaxinfo.ptMaxSize = TPoint(32000, 32000);
            minmaxinfo.ptMaxTrackSize = TPoint(32000, 32000);
            return;
        }
    }
    TOleView::EvGetMinMaxInfo(minmaxinfo);
}


bool olesvrOleView::EvOcViewShowTools (TOcToolBarInfo far& tbi)
{
    // Construct & create a control bar for show, destroy our bar for hide
    // Сконструировать и создать панель управления для отображения,
    // уничтожить нашу панель для сокрытия
    if (tbi.Show) {
        if (!ToolBar) {
            ToolBar = new TControlBar(this);

            olesvrApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), olesvrApp);
            CHECK(theApp);

            theApp->CreateGadgets(ToolBar, true);
        }

        ToolBar->Create();
        tbi.HTopTB = (HWND)*ToolBar;
    } else {
        if (ToolBar) {
            ToolBar->Destroy();
            delete ToolBar;
            ToolBar = 0;
        }
    }

    return true;
}

    Основная процедура отображения, генерируемая AppExpert функция olesvrOleView::Paint(TDC& dc, bool erase, TRect& rect), которая содержит управляющий код, но в действительности ничего не рисует. Запрограммируем код для функции Paint(), рисующий пятиконечную звезду. Закрасим звезду, с помощью функции GDI Polygon(), и зададим несколько опций. Создадим новую функцию в классе olesvrOleView с именем OurPaint(), которая и будет рисовать изображение.

    При вызове olesvrOleView::Paint() этой функции передаются три параметра: ссылка на объект TDC, логическая переменная, указывающая, следует ли очистить область пользователя, и ссылка на объект TRect, содержащая координаты прямоугольника в области пользователя, который следует перерисовать. Точно такие же параметры передаются при вызове функции OurPaint(). В листинге 2 приводится функция OurPaint().

    Листинг 2. Функция olesvrOleView::OurPaint()

void olesvrOleView::OurPaint (TDC& dc, bool /*erase*/, TRect& rect)
{
 //Это функция отображения.
 TPoint Points[10];
 HBRUSH cBrush;
 int OldFillMode;
 int FillMode=ALTERNATE;
 cBrush=CreateSolidBrush(RGB(254,128,6));
 TRect Clientrect;
 GetWindow()->GetClientRect(Clientrect);
 Clientrect.left=15;
 Clientrect.right=75;
 Clientrect.bottom=75;
 Clientrect.top=15;
 Points[0].x=(Clientrect.right+Clientrect.left)/2;
 Points[0].y=Clientrect.top;
 Points[1].x=Clientrect.right;
 Points[1].y=Clientrect.bottom;
 Points[2].x=Clientrect.left;
 Points[2].y=((Clientrect.bottom+Clientrect.top)/3)*1;
 Points[3].x=Clientrect.right;
 Points[3].y=((Clientrect.bottom+Clientrect.top)/3)*1;
 Points[4].x=Clientrect.left;
 Points[4].y=Clientrect.bottom;
 Points[5]=Points[0];
 dc.SelectObject(cBrush);
 OldFillMode=dc.SetPolyFillMode(FillMode);
 dc.Polygon(Points,6);
 dc.SetPolyFillMode(OldFillMode);
 dc.RestoreBrush();
 DeleteObject(cBrush);
}

    Следует также добавить вызов функции OurPaint() в тело функции olesvrOleView::Paint(). Эта модификация приводится в листинге 3 в выделенной сроке.

    Листинг 3. Обращение к функции OurPaint() в теле функции olesvrOleView::Paint())

  .   .   .   .
  {
    TOleView::Paint(dc, erase, rect);
    // Вставить >> В этом месте выполняется обычное рисование.
    OurPaint(dc, erase, rect);
  }
  dc.TextOut (0, 30, "olesvr OLE Server");
}
}

    Необходимо внести прототип функции в заголовочный файл LSVROEVW.H, как показано в листинге 4.

    Листинг 4. Заголовочный файл LSVROLVW.H с добавленным прототипом функции OurPaint())

#if !defined(__lsvrolvw_h)   // Sentry, use file only if it's not already included.
                             // Предотвращение повторных включений этого файла.
#define __lsvrolvw_h

/*  Project olesvr
    
    Copyright c 1994. All Rights Reserved.

    SUBSYSTEM:    olesvr.exe Application
    FILE:         lsvrolvw.h
    AUTHOR:       


    OVERVIEW
    ========
    Class definition for olesvrOleView (TOleView).      
    Определение класса olesvrOleView (TOleView).      
*/


#include <owl\owlpch.h>
#pragma hdrstop


#include "olsvrapp.rh"            // Definition of all resources.
                                  // Определение всех ресурсов.

//{{TOleView = olesvrOleView}}
class olesvrOleView : public TOleView {
public:
    olesvrOleView (TDocument& doc, TWindow* parent = 0);
    virtual ~olesvrOleView ();
    void olesvrOleView::OurPaint (TDC& dc, bool erase, TRect& rect);
private:
    TControlBar *ToolBar;

//{{olesvrOleViewVIRTUAL_BEGIN}}
public:
    virtual void Paint (TDC& dc, bool erase, TRect& rect);
//{{olesvrOleViewVIRTUAL_END}}
//{{olesvrOleViewRSP_TBL_BEGIN}}
protected:
    void EvGetMinMaxInfo (MINMAXINFO far& minmaxinfo);
    bool EvOcViewShowTools (TOcToolBarInfo far& tbi);
//{{olesvrOleViewRSP_TBL_END}}
DECLARE_RESPONSE_TABLE(olesvrOleView);
};    //{{olesvrOleView}}


#endif                                      // __lsvrolvw_h sentry.

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

    Однако при запуске программы в рабочей области OLESVR ничего не отображается!

    На следующем шаге мы рассмотрим решение этой проблемы.




Предыдущий шаг Содержание Следующий шаг