SAP R/3 форум ABAP консультантов
Russian ABAP Developer's Club

Home - FAQ - Search - Memberlist - Usergroups - Profile - Log in to check your private messages - Register - Log in - English
Blogs - Weblogs News

Создание элементов ActiveX в Visual C++ 5



 
Post new topic   Reply to topic    Russian ABAP Developer's Club Forum Index -> OLE2, Excel, WinWord
View previous topic :: View next topic  
Author Message
admin
Администратор
Администратор



Joined: 01 Sep 2007
Posts: 1639

PostPosted: Mon Oct 08, 2007 9:31 pm    Post subject: Создание элементов ActiveX в Visual C++ 5 Reply with quote

С. Холзнер. Microsoft Visual C++ 5 с самого начала
Создание элементов ActiveX

В этом уроке мы научимся работать с элементами ActiveX - компонентами, которые можно внедрять в программы, а также в Web-страницы, отображаемые с помощью броузера. Научившись создавать элементы ActiveX, мы сможем включать их в другие программы, что открывает множество полезных возможностей. Более того, их даже можно включить в палитру редактора диалоговых окон и непосредственно перетаскивать в создаваемое диалоговое окно.

Мы научимся создавать элементы ActiveX и пользоваться ими как в специальной программе- <тестовом контейнере>, поставляемой вместе с VisualC++, так и в других программах, написанных на VisualC++. Мы увидим, как организовать прорисовку элемента ActiveX, чтобы он выглядел так, как нам требуется.

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

Наконец, мы узнаем, как внедрить в элементы ActiveX методы, которые могут вызываться из других программ, и свойства (хранимые в виде внутренних переменных), значения которых могут задаваться другими программами. Элементы ActiveX могут поддерживать свои, нестандартные события, они также будут упомянуты в этом уроке.

Приступим к нашему первому элементу ActiveX - boxer.

Элемент ActiveX Boxer

Наш первый элемент ActiveX рисует на экране небольшой прямоугольник, разделенный на четыре части; когда пользователь щелкает мышью в одной из них, та окрашивается в черный цвет:



Если пользователь щелкнет другую часть, закраска переходит на нее:




Запустите VisualC++ и начните создание программы boxer. На этот раз в диалоговом окне New выберите строку MFC ActiveX ControlWizard (см.рис.13.1).



Рис.13.1. Создание элемента ActiveX

Создание управляющего элемента при помощи MFC ActiveX ControlWizard занимает всего два этапа. Подтвердите все установки по умолчанию кнопкой Finish; ControlWizard завершает создание элемента.

Код элемента в созданном проекте содержится в файлах BoxerCtl.h и BoxerVtl.cpp. Он является производным от класса COleControl, а содержимое файла BoxerCtl.cpp отчасти напоминает код стандартного класса вида. Например, в нем присутствует метод OnDraw(), в котором происходит рисование элемента.

Рисование элемента ActiveX

В настоящий момент метод OnDraw() в файле BoxerCtl.cpp выглядит так:

Code:
void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds,
 const CRect& rcInvalid)
{
 // TODO: замените следующий фрагмент кодом
 // рисования элемента


 pdc->FillRect(rcBounds, CBrush::FromHandle
 ((HBRUSH)GetStockObject(WHITE_BRUSH)));
 pdc->Ellipse(rcBounds);
}



Методу OnDraw() передается прямоугольник rcBounds, в пределах которого должен быть нарисован элемент, а заранее помещенный в него код закрашивает этот прямоугольник белым цветом и рисует в нем эллипс. Мы нарисуем в элементе собственное изображение, поэтому удалите из OnDraw() строку для рисования эллипса: pdc->Ellipse(rcBounds);.

Мы разделим область элемента на четыре прямоугольника с именами box1-box4 и объявим их в файле BoxerCtl.h:

Code:
class CBoxerCtrl : public COleControl
{
 .
 .
 .
// Реализация
protected:
 ~CBoxerCtrl();
 CRect box1;
 CRect box2;
 CRect box3;
 CRect box4;



В методе OnDraw() происходит разделение области элемента на четыре части и размещение прямоугольников в левом верхнем, правом верхнем, левом нижнем и правом нижнем углу:

Code:
void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
 pdc->FillRect(rcBounds, CBrush::FromHandle ((HBRUSH)GetStockObject(WHITE_BRUSH)));


 box1 = CRect(rcBounds.left, rcBounds.top, rcBounds.right/2, rcBounds.bottom/2);
 box2 = CRect(rcBounds.left, rcBounds.bottom/2, rcBounds.right/2, rcBounds.bottom);
 box3 = CRect(rcBounds.right/2, rcBounds.top, rcBounds.right, rcBounds.bottom/2);
 box4 = CRect(rcBounds.right/2, rcBounds.bottom/2,
 rcBounds.right, rcBounds.bottom);
 .
 .
 .
}



Затем мы рисуем все четыре прямоугольника:

Code:
void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
 pdc->FillRect(rcBounds, CBrush::FromHandle ((HBRUSH)GetStockObject(WHITE_BRUSH)));


 box1 = CRect(rcBounds.left, rcBounds.top,
 rcBounds.right/2, rcBounds.bottom/2);
 box2 = CRect(rcBounds.left, rcBounds.bottom/2,
 rcBounds.right/2, rcBounds.bottom);
 box3 = CRect(rcBounds.right/2, rcBounds.top,
 rcBounds.right, rcBounds.bottom/2);
 box4 = CRect(rcBounds.right/2, rcBounds.bottom/2,
 rcBounds.right, rcBounds.bottom);


 pdc->Rectangle(&box1);
 pdc->Rectangle(&box2);
 pdc->Rectangle(&box3);
 pdc->Rectangle(&box4);
}



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

Создание обработчика сообщения в элементе ActiveX

Элементы ActiveX поддерживают обработку сообщения точно так же, как и остальные программы- воспользуйтесь ClassWizard и создайте в нашем элементе обработчик для сообщения WM_LBUTTONDOWN (см. рис.13.2).



Рис.13.2. Добавление поддержки работы с мышью для элемента ActiveX

Метод OnLButtonDown() в коде для элемента ActiveX выглядит так:

Code:
void CBoxerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{ // TODO: добавьте код обработки сообщения
 // и/или вызовите обработчик по умолчанию
 COleControl::OnLButtonDown(nFlags, point);
}



Мы должны определить, в каком из четырех прямоугольников щелкнул пользователь, и закрасить этот прямоугольник- для этого в заголовочном файле CBoxerCtl.h объявляются четыре новые переменные (они будут выполнять функции флагов):

Code:
class CBoxerCtrl : public COleControl
{
 .
 .
 .
// Реализация


protected:
 ~CBoxerCtrl();
 CRect box1;
 CRect box2;
 CRect box3;
 CRect box4;
 boolean fill1;
 boolean fill2;
 boolean fill3;
 boolean fill4;
 .
 .
 .
}



В конструкторе элемента им присваиваются значения false:

Code:
CBoxerCtrl::CBoxerCtrl()
{
 InitializeIIDs(&IID_DBoxer, &IID_DBoxerEvents);


 fill1 = fill2 = fill3 = fill4 = false;
}



В методе OnLButtonDown() можно установить значения флагов с помощью удобного метода PtInRect() класса CRect. Он возвращает true, если точка-параметр принадлежит прямоугольнику (в нашем случае прямоугольникам box1-box4):

Code:
void CBoxerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
 fill1 = box1.PtInRect(point);
 fill2 = box2.PtInRect(point);
 fill3 = box3.PtInRect(point);
 fill4 = box4.PtInRect(point);
 Invalidate();


 COleControl::OnLButtonDown(nFlags, point);
}



После установки флага для прямоугольника, на котором щелкнул пользователь, мы вызываем перерисовку вида методом Invalidate(). Это приводит к вызову OnDraw(), в котором проверяются все четыре флага и необходимый прямоугольник закрашивается методом FillSolidRect() класса CDC:

Code:
void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
 pdc->FillRect(rcBounds,CBrush::FromHandle
 ((HBRUSH)GetStockObject(WHITE_BRUSH)));


 box1 = CRect(rcBounds.left, rcBounds.top,
 rcBounds.right/2, rcBounds.bottom/2);


 box2 = CRect(rcBounds.left, rcBounds.bottom/2,
 rcBounds.right/2, rcBounds.bottom);


 box3 = CRect(rcBounds.right/2, rcBounds.top,
 rcBounds.right, rcBounds.bottom/2);


 box4 = CRect(rcBounds.right/2, rcBounds.bottom/2,
 rcBounds.right, rcBounds.bottom);


 pdc->Rectangle(&box1);
 pdc->Rectangle(&box2);
 pdc->Rectangle(&box3);
 pdc->Rectangle(&box4);


 if(fill1) pdc->FillSolidRect(&box1, RGB(0, 0, 0));
 if(fill2) pdc->FillSolidRect(&box2, RGB(0, 0, 0));
 if(fill3) pdc->FillSolidRect(&box3, RGB(0, 0, 0));
 if(fill4) pdc->FillSolidRect(&box4, RGB(0, 0, 0));
}



Программа готова, можно приступать к тестированию.

Тестирование элемента ActiveX

Чтобы проверить работу элемента Boxer, выполните команду Build|Build Boxer.ocx (управляющие элементы ActiveX получают расширение .ocx) - элемент создается и регистрируется в Windows. Затем выполните команду Tools|ActiveX Control Test Container. Запускается чрезвычайно полезная программа <тестовый контейнер> (см.рис.13.3).

Выполните в тестовом контейнере команду Edit|Insert OLE Control и дважды щелкните на строке Boxer control в окне Insert OLE Control. В результате наш элемент ActiveX появится в контейнере (см. рис.13.3).

Щелкните в любом прямоугольнике - он закрашивается черным цветом, как показано на рис.13.3. Если щелкнуть в другом прямоугольнике, черным станет он. Элемент работает так, как мы хотели, а сейчас мы попытаемся вставить его в программу.



Рис.13.3. Тестирование элемента ActiveX

Использование элемента ActiveX в программе на VisualC++

С помощью AppWizard создайте программу на базе диалогового окна и назовите ее Boxerapp. В нее можно вставить элемент типа Boxer - выполните команду Project|Add To Project|Components and Controls, и откроется окно Components and Controls Gallery. Дважды щелкните на строке Registered ActiveX Controls, чтобы вывести список всех доступных элементов ActiveX (см.рис.13.4).



Рис.13.4. Окно Components and Controls Gallery

Выделите строку Boxer Control (см. рис.13.4) и нажмите кнопку Insert. Появляется диалоговое окно с вопросом, желаете ли вы вставить элемент в свою программу; нажмите кнопку OK. Затем откроется окно Confirm Class, сообщающее о создании нового класса CBoxer. Снова нажмите кнопку OK и закройте окно Components and Controls Gallery. Элемент Boxer появится в палитре редактора диалоговых окон (см.рис. 13.5). Он представлен кнопкой с буквами OCX.


Чтобы изменить внешний вид элемента ActiveX в палитре, дважды щелкните в VisualC++ на идентификаторе растрового ресурса IDB_BOXER - значок откроется в редакторе растровых изображений, и вы сможете отредактировать его по своему усмотрению.


Рис.13.5. Элемент ActiveX в палитре

Элемент Boxer, как и любой другой управляющий элемент, можно разместить в главном диалоговом окне программы (см. рис. 13.5). Запустите программу (см. рис.13.6).



Рис.13.6. Элемент ActiveX в программе

Как видите, элемент ActiveX присутствует в программе и работает так, как ему положено. Вы можете как угодно щелкать на прямоугольниках, и каждый раз выбранный вами прямоугольник будет закрашиваться (см. рис.13.6). Итак, нам удалось создать свой первый элемент ActiveX!

Исходный текст программы содержится в файлах BoxerCtl.h/BoxerCtl.cpp.

BoxerCtl.h и BoxerCtl.cpp

Code:
#if !defined(AFX_BOXERCTL_H__00B2C1F4_95A2_11D0_8860 _444553540000__INCLUDED_)
#define AFX_BOXERCTL_H__00B2C1F4_95A2_11D0_8860_444553540000__INCLUDED_


#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000


// BoxerCtl.h : Объявление класса элемента ActiveX
// CBoxerCtrl.


///////////////////////////////////////////////////////////
// CBoxerCtrl : реализация содержится в BoxerCtl.cpp.


class CBoxerCtrl : public COleControl
{
 DECLARE_DYNCREATE(CBoxerCtrl)


// Конструктор
public:
 CBoxerCtrl();


// Переопределения
 // Переопределения виртуальных функций,
 // сгенерированные ClassWizard
 //{{AFX_VIRTUAL(CBoxerCtrl)
 public:
 virtual void OnDraw(CDC* pdc, const CRect& rcBounds,
 const CRect& rcInvalid);
 virtual void DoPropExchange(CPropExchange* pPX);
 virtual void OnResetState();
 //}}AFX_VIRTUAL


// Реализация
protected:
 ~CBoxerCtrl();
 CRect box1;
 CRect box2;
 CRect box3;
 CRect box4;
 boolean fill1;
 boolean fill2;
 boolean fill3;
 boolean fill4;
 DECLARE_OLECREATE_EX(CBoxerCtrl)// Фабрика класса и guid
 DECLARE_OLETYPELIB(CBoxerCtrl) // GetTypeInfo
 DECLARE_PROPPAGEIDS(CBoxerCtrl)// Идентификаторы
 // страниц свойств DECLARE_OLECTLTYPE(CBoxerCtrl) // Имя типа и
 // вспомогательная информация


// Схемы сообщений
 //{{AFX_MSG(CBoxerCtrl)
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()


// Диспетчерские схемы
 //{{AFX_DISPATCH(CBoxerCtrl)
 // ВНИМАНИЕ - здесь ClassWizard вставляет
 // и удаляет функции.
 // НЕ ИЗМЕНЯЙТЕ содержимое этих фрагментов
 // сгенерированного кода!
 //}}AFX_DISPATCH
 DECLARE_DISPATCH_MAP()


 afx_msg void AboutBox();


// Схемы событий
 //{{AFX_EVENT(CBoxerCtrl)
 // ВНИМАНИЕ - здесь ClassWizard вставляет
 // и удаляет функции.
 // НЕ ИЗМЕНЯЙТЕ содержимое этих фрагментов
 // сгенерированного кода!
 //}}AFX_EVENT
 DECLARE_EVENT_MAP()


// Диспетчерские идентификаторы и идентификаторы событий
public:
 enum
 {
 //{{AFX_DISP_ID(CBoxerCtrl)
 // ВНИМАНИЕ - здесь ClassWizard вставляет
 // и удаляет элементы перечисляемого типа.
 // НЕ ИЗМЕНЯЙТЕ содержимое этих фрагментов
 // сгенерированного кода!
 //}}AFX_DISP_ID
 };
};


//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio вставляет дополнительные
// объявления перед предшествующей строкой.


#endif // !defined(AFX_BOXERCTL_H__00B2C1F4_95A2_11D0
 // _8860_444553540000__INCLUDED)
// BoxerCtl.cpp : реализация элемента ActiveX CBoxerCtrl.


#include "stdafx.h"
#include "boxer.h" #include "BoxerCtl.h"
#include "BoxerPpg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CBoxerCtrl, COleControl)


///////////////////////////////////////////////////////////
// Схема сообщений


BEGIN_MESSAGE_MAP(CBoxerCtrl, COleControl)
 //{{AFX_MSG_MAP(CBoxerCtrl)
 ON_WM_LBUTTONDOWN()
 //}}AFX_MSG_MAP
 ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


///////////////////////////////////////////////////////////
// Диспетчерская схема


BEGIN_DISPATCH_MAP(CBoxerCtrl, COleControl)
 //{{AFX_DISPATCH_MAP(CBoxerCtrl)
 // ВНИМАНИЕ - здесь ClassWizard вставляет
 // и удаляет элементы схемы.
 // НЕ ИЗМЕНЯЙТЕ содержимое этих фрагментов
 // сгенерированного кода!
 //}}AFX_DISPATCH_MAP
 DISP_FUNCTION_ID(CBoxerCtrl, "AboutBox",
 DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()


///////////////////////////////////////////////////////////
// Схема событий


BEGIN_EVENT_MAP(CBoxerCtrl, COleControl)
 //{{AFX_EVENT_MAP(CBoxerCtrl)
 // ВНИМАНИЕ - здесь ClassWizard вставляет
 // и удаляет элементы схемы.
 // НЕ ИЗМЕНЯЙТЕ содержимое этих фрагментов
 // сгенерированного кода!
 //}}AFX_EVENT_MAP
END_EVENT_MAP()


///////////////////////////////////////////////////////////
// Страницы свойств


// TODO: При необходимости добавьте новые
// страницы свойств. // Не забудьте увеличить значение счетчика!
BEGIN_PROPPAGEIDS(CBoxerCtrl, 1)
 PROPPAGEID(CBoxerPropPage::guid)
END_PROPPAGEIDS(CBoxerCtrl)


///////////////////////////////////////////////////////////
// Инициализация фабрики класса и guid


IMPLEMENT_OLECREATE_EX(CBoxerCtrl, "BOXER.BoxerCtrl.1",0xb2c1e6, 0x95a2, 0x11d0, 0x88, 0x60, 0x44, 0x45, 0x53, 0x54, 0, 0)


///////////////////////////////////////////////////////////
// Идентификатор библиотеки типа и версия


IMPLEMENT_OLETYPELIB(CBoxerCtrl, _tlid, _wVerMajor,
 _wVerMinor)


///////////////////////////////////////////////////////////
// Идентификаторы интерфейсов


const IID BASED_CODE IID_DBoxer ={ 0xb2c1e4, 0x95a2, 0x11d0, { 0x88, 0x60, 0x44, 0x45,0x53, 0x54, 0, 0 }};
const IID BASED_CODE IID_DBoxerEvents ={ 0xb2c1e5, 0x95a2, 0x11d0, { 0x88, 0x60, 0x44, 0x45,0x53, 0x54, 0, 0 }};


///////////////////////////////////////////////////////////
// Информация типа для элемента


static const DWORD BASED_CODE _dwBoxerOleMisc =
 OLEMISC_ACTIVATEWHENVISIBLE


 OLEMISC_SETCLIENTSITEFIRST


 OLEMISC_INSIDEOUT


 OLEMISC_CANTLINKINSIDE


 OLEMISC_RECOMPOSEONRESIZE;


IMPLEMENT_OLECTLTYPE(CBoxerCtrl, IDS_BOXER, _dwBoxerOleMisc)


///////////////////////////////////////////////////////////
// CBoxerCtrl::CBoxerCtrlFactory::UpdateRegistry -
// добавляет или удаляет записи системного реестра
// для CBoxerCtrl


BOOL CBoxerCtrl::CBoxerCtrlFactory::UpdateRegistry
 (BOOL bRegister)
{
 // Убедитесь, что ваш элемент соответствует требованиям
 // совместной потоковой модели. Подробности приведены
 // в документе MFC TechNote 64.
 // Если элемент нарушает требования совместной модели,
 // необходимо модифицировать следующий фрагмент программы
 // и заменить 6-й параметр с afxRegApartmentThreading
 // на 0.


 if (bRegister)
 return AfxOleRegisterControlClass(AfxGetInstanceHandle(),
 m_clsid,m_lpszProgID,IDS_BOXER, IDB_BOXER,
 afxRegApartmentThreading,_dwBoxerOleMisc,_tlid,
 _wVerMajor,_wVerMinor);
 else
 return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


///////////////////////////////////////////////////////////
// CBoxerCtrl::CBoxerCtrl - конструктор


CBoxerCtrl::CBoxerCtrl()
{
 InitializeIIDs(&IID_DBoxer, &IID_DBoxerEvents);


 // TODO: инициализируйте данные экземпляра
 // вашего элемента.
 fill1 = fill2 = fill3 = fill4 = false;
}


///////////////////////////////////////////////////////////
// CBoxerCtrl::~CBoxerCtrl - деструктор


CBoxerCtrl::~CBoxerCtrl()
{
 // TODO: уничтожьте данные экземпляра вашего элемента.
}


///////////////////////////////////////////////////////////
// CBoxerCtrl::OnDraw - функция рисования


void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds,
 const CRect& rcInvalid)
{
 // TODO: замените следующий фрагмент
 // вашим кодом рисования.


 pdc->FillRect(rcBounds,CBrush::FromHandle
 ((HBRUSH)GetStockObject(WHITE_BRUSH)));


 box1 = CRect(rcBounds.left, rcBounds.top,
 rcBounds.right/2, rcBounds.bottom/2);
 box2 = CRect(rcBounds.left, rcBounds.bottom/2,
 rcBounds.right/2, rcBounds.bottom); box3 = CRect(rcBounds.right/2, rcBounds.top,
 rcBounds.right, rcBounds.bottom/2);
 box4 = CRect(rcBounds.right/2, rcBounds.bottom/2,
 rcBounds.right, rcBounds.bottom);


 pdc->Rectangle(&box1);
 pdc->Rectangle(&box2);
 pdc->Rectangle(&box3);
 pdc->Rectangle(&box4);


 if(fill1) pdc->FillSolidRect(&box1, RGB(0, 0, 0));
 if(fill2) pdc->FillSolidRect(&box2, RGB(0, 0, 0));
 if(fill3) pdc->FillSolidRect(&box3, RGB(0, 0, 0));
 if(fill4) pdc->FillSolidRect(&box4, RGB(0, 0, 0));
}


///////////////////////////////////////////////////////////
// CBoxerCtrl::DoPropExchange - поддержка устойчивости


void CBoxerCtrl::DoPropExchange(CPropExchange* pPX)
{
 ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
 COleControl::DoPropExchange(pPX);


 // TODO: Вызовите функции PX_ для каждого
 // устойчивого свойства.
}


///////////////////////////////////////////////////////////
// CBoxerCtrl::OnResetState - сброс элемента в состояние
// по умолчанию


void CBoxerCtrl::OnResetState()
{
 COleControl::OnResetState(); // Присваивает значения по
 // умолчанию из DoPropExchange
 // Сбросьте любые другие параметры состояния элемента
}


///////////////////////////////////////////////////////////
// CBoxerCtrl::AboutBox - отображение диалогового
// окна About
void CBoxerCtrl::AboutBox()
{
 CDialog dlgAbout(IDD_ABOUTBOX_BOXER);
 dlgAbout.DoModal();
}
///////////////////////////////////////////////////////////
// Обработчики сообщений CBoxerCtrl


void CBoxerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{ // TODO: добавьте код обработки сообщения
 // и/или вызовите обработчик по умолчанию
 fill1 = box1.PtInRect(point);
 fill2 = box2.PtInRect(point);
 fill3 = box3.PtInRect(point);
 fill4 = box4.PtInRect(point);
 Invalidate();


 COleControl::OnLButtonDown(nFlags, point);
}




Мы посмотрели, как создать элемент ActiveX и организовать его прорисовку. Однако на этом возможности ActiveX отнюдь не исчерпываются - управляющие элементы могут также обладать событиями, методами и свойствами. Сейчас мы познакомимся с этой темой подробнее.

Создание элемента ActiveX на базе кнопки

Следующий пример демонстрирует ряд новых аспектов программирования ActiveX- например, возможность создания элементов на базе уже существующих управляющих элементов (например, кнопок). Мы также увидим, как организовать в элементах ActiveX поддержку событий- программа, в которую внедрен такой элемент, сможет обработать событие так же, как она обрабатывает любоесообщение Windows. В нашем случае элемент будет называться Buttoner и поддерживать событие Click. Присутствующий в программе метод-обработчик (скажем, OnClickButtonerctrl1()) будет вызываться при щелчке мышью внутри элемента.

Кроме того, в новом примере будут поддерживаться методы элементов ActiveX- в частности Beep(). В других программах вы сможете при помощи ClassWizard создавать переменные, связанные с нашим элементом (например, m_buttoner), и вызывать метод с помощью записи типа m_buttoner.Beep().

Наконец, мы рассмотрим свойства элементов ActiveX. В нашем примере будет поддерживаться свойство с именем data. В нем будет храниться количество щелчков мышью, сделанных на элементе. Существуют два способа обращения к свойству data из других программ: можно либо разрешить ссылаться на свойство в записи типа m_buttoner.data и непосредственно читать и присваивать значение этого свойства, либо воспользоваться более надежным способом и предоставить специальные методы для обращения к свойству. В этом случае другая программа должна вызывать метод m_buttoner.SetData(), чтобы присвоить значение свойству, и m_buttoner.GetData(), чтобы получить его. Использование методов для доступа более надежно, поскольку присваиваемое значение можно предварительно проверить. В нашем примере будет использоваться именно этот вариант.

Создайте программу Buttoner с помощью ControlWizard. Во втором окне ControlWizard выберите строку BUTTON из раскрывающегося списка под вопросом Which window class, if any, should this control subclass? (Какой оконный класс, если таковой существует, должен субклассировать данный элемент?), как показано на рис.13.7, и завершите создание элемента кнопкой Finish.



Рис.13.7. Создание элемента Buttoner на базе кнопки

Можно приступать к настройке элемента Buttoner.

Настройка элемента Buttoner

Пока что наш новый элемент ActiveX выглядит, как пустая кнопка, однако мы можем настроить его внешний вид и поместить на него надпись- например, <Нажми меня!>. Мы сделаем это в конструкторе элемента, расположенном в файле ButtonerCtl.cpp:

Code:
CButtonerCtrl::CButtonerCtrl()
{
 InitializeIIDs(&IID_DButtoner, &IID_DButtonerEvents);
 // TODO: инициализируйте данные экземпляра
 // вашего элемента.
}


Элемент Buttoner, как и все управляющие элементы ActiveX, порождается от класса COleControl, поэтому мы можем воспользоваться методом SetText() этого класса и изменить надпись на элементе:

Code:
CButtonerCtrl::CButtonerCtrl()
{
 InitializeIIDs(&IID_DButtoner, &IID_DButtonerEvents);
 // TODO: инициализируйте данные экземпляра
 // вашего элемента.
 SetText("Нажми меня!");
}


Можно приступать к программированию. Начнем с добавления событий в элемент ActiveX. Другие программы, использующие его, могут содержать обработчики, вызываемые при возникновении события.



Рис.13.8. Настройка элемента ActiveX

Добавление событий

Мы создадим в элементе Buttoner событие Click, происходящее при щелчке мышью. Возникновение события (с извещением программы, в которую внедрен элемент ActiveX) называется возбуждением (firing) события, поэтому говорят, что при щелчке мышью программа возбуждает событие Click. При возбуждении события Click вызывается его обработчик в программе, содержащей наш элемент. Давайте посмотрим, как это делается.

В ClassWizard перейдите на вкладку ActiveX Events и нажмите кнопку Add Event. Открывается одноименное окно (см. рис.<N>13.9).



Рис.13.9. Добавление события к элементу ActiveX

В нем мы и создадим событие Click. Выберите строку Click в раскрывающемся списке External name (см.рис.13.9) - в наш элемент добавляется событие Click. Чтобы событие действительно произошло, нужно вызвать метод FireClick(), который также указан в окне Add Event.


Если вы хотите, чтобы новое событие вызывалось с параметрами (которые будут передаваться обработчику программы, работающей с элементом), введите параметры и их типы в списке Parameter, расположенном в нижней части окна Add Event.

Событие Click будет возбуждаться при щелчке левой кнопкой мыши, поэтому сейчас мы включим в элемент ActiveX обработчик OnLButtonDown():

Code:
void CButtonerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: добавьте код обработки сообщения
 // и/или вызовите обработчик по умолчанию


 COleControl::OnLButtonDown(nFlags, point);
}



Чтобы возбудить событие Click, достаточно вызвать специальный метод FireClick(), созданный ClassWizard (если событие передает обработчикам какие-либо параметры, их следует передать методу FireEvent(), где Event - имя вашего события).

Code:
void CButtonerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
 FireClick();


 COleControl::OnLButtonDown(nFlags, point);
}



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

Мы научились возбуждать события из элемента ActiveX. Число щелчков должно сохраняться в свойстве data, и сейчас мы создадим это свойство.

Добавление свойств к элементам ActiveX

Свойством называется переменная класса элемента. Если тот содержит свойство с именем data, то другие программы могут обращаться к нему через запись типа m_buttoner.data или через функции чтения/записи свойства: m_buttoner.SetData() и m_buttoner.GetData(). Мы познакомимся со свойствами на примере свойства data, сохраняющего число щелчков мышью.

Для добавления свойств в элемент ActiveX также используется ClassWizard. Откройте его и перейдите на вкладку Automation (ранее называлась OLE Automation), затем нажмите кнопку Add Property, чтобы вызвать одноименное окно (см.рис.13.10).

Введите в поле External name имя свойства data; сделайте его коротким целым числом, выбрав из списка Type строку short. Установите переключатель Get/Set methods- это значит, что программы будут вызывать метод SetData(), чтобы присвоить значение свойству, и метод GetData(), чтобы узнать значение свойства (если установить переключатель Member Variable, другие программы смогут напрямую обращаться к свойству: m_buttoner.data). Нажмите кнопку OK, чтобы закрыть окно Add Property, а потом закройте ClassWizard.



Рис.13.10. Окно Add Property

Теперь в программе можно ссылаться на значение свойства data через переменную m_data, начнем с обнуления этого значения в конструкторе:

Code:
CButtonerCtrl::CButtonerCtrl()
{
 InitializeIIDs(&IID_DButtoner, &IID_DButtonerEvents);
 SetText("Нажми меня!");


 m_data = 0;
}



В свойстве должно храниться число щелчков на элементе, поэтому в OnLButtonDown() следует увеличивать значение m_data:

Code:
void CButtonerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: добавьте код обработки сообщения
 // и/или вызовите обработчик по умолчанию


 FireClick();


 m_data++;
 COleControl::OnLButtonDown(nFlags, point);
}



Если другая программа вызовет метод GetData() нашего элемента, она получит значение переменной m_data, равное количеству щелчков, сделанных на нем.

Добавление свойства закончено. К настоящему моменту наш элемент имеет событие Click и свойство data. Сейчас мы добавим в него метод Beep(), которыйможет вызываться другими программами с помощью записи вида m_buttoner.Beep().

Добавление методов

Чтобы добавить в элемент новый метод, вызовите ClassWizard и перейдите на вкладку Automation. Нажмите кнопку Add Method, и откроется одноименное окно (см.рис.13.11).



Рис.13.11. Окно Add Method

Присвойте новому методу имя Beep (в обоих полях - External name и Internal name) и укажите тип возвращаемого значения void (см.рис. 13.11). Нажмите кнопку OK, чтобы закрыть окно Add Method, а потом закройте ClassWizard. В элементе появляется метод Beep():

Code:
void CButtonerCtrl::Beep()
{
 // TODO: добавьте код диспетчерской обработки
}



При вызове этого метода компьютер будет выдавать звуковой сигнал, для этого мы воспользуемся методом MFC MessageBeep():

Code:
void CButtonerCtrl::Beep()
{
 MessageBeep(MB_OK);
}



В нашем элементе появился новый метод, который может использоваться в других программах. Теперь они могут вызывать метод Beep() элемента внутри своего кода.

Настало время посмотреть, как элемент Buttoner ведет себя в других приложениях. Давайте попробуем внедрить его в программу и поработать с ним на уровне программного кода.

Внедрение элемента Buttoner в другую программу

При помощи AppWizard создайте новую программу на базе диалогового окна и присвойте ей имя Buttonerapp. Включите элемент Buttoner в палитру редактора диалоговых окон. Для этого следует вызвать окно Components and Controls Gallery, о чем рассказывалось в предыдущем примере. Когда VisualC++ предложит задать имя класса элемента, подтвердите предложенное по умолчанию имя CButtoner.

Теперь мы добавим элемент Buttoner в новую программу с помощью редакторадиалоговых окон (см. рис.13.12). Он присваивает элементу идентификатор ID_BUTTONERCTRL1.



Рис.13.12. Элемент Buttoner в новой программе



Рис.13.13. Создание переменной для элемента ActiveX

Разместите над элементом Buttoner надпись Щелкните элемент Buttoner:, а под ним- текстовое поле для вывода сведений о количестве щелчков. Содержимое поля будет определяться методом GetData(), возвращающим значение свойства data.

С помощью ClassWizard свяжите с элементом Buttoner переменную m_buttoner (см. рис.13.13). Обратите внимание: она принадлежит недавно созданному классу CButtoner. Кроме того, свяжите содержимое текстового поля с переменной m_text (см. рис.13.13).

Элемент Buttoner внедрен в приложение Buttonerapp, и для вызова его методов (например, Beep()) можно пользоваться записью вида m_buttoner.Beep().

Связывание элемента ActiveX с кодом программы

В ClassWizard мы создадим обработчик для события Click элемента Buttoner. Найдите событие в окне ClassWizard (см.рис.13.14) и создайте новый обработчик, которому ClassWizard присваивает имя OnClickButtonerctrl1():

Code:
void CButtonerappDlg::OnClickButtonerctrl1()
{
 // TODO: добавьте код обработки события
 // и/или вызовите обработчик по умолчанию
}



Рис.13.14. Создание обработчика для события от элемента ActiveX

Этот метод будет вызываться при каждом щелчке мышью на элементе. Чтобы узнать, сколько раз пользователь щелкнул на элементе, следует определить значение свойства data, а для этого нужно вызвать метод GetData():

Code:
void CButtonerappDlg::OnClickButtonerctrl1()
{
 m_text.Format("свойство data = %ld", m_buttoner.GetData());
 UpdateData(false);
}


Теперь при каждом щелчке на элементе программа Buttonerapp будет выводить общее количество щелчков, хранящееся в свойстве data (см.рис. 13.15). Наша программа, содержащая управляющий элемент ActiveX, работает именно так, как нам хотелось.

На примере элемента Buttoner мы узнали много нового- как создать элемент ActiveX на базе существующего управляющего элемента и как организовать в нем поддержку событий, методов и свойств.

Исходный текст элемента Buttoner содержится в файлах ButtonerCtl.h/ButtonerCtl.cpp, а исходный текст программы Buttonerapp- в файлах ButtonerappDlg.h/ ButtonerappDlg.cpp.



Рис.13.15. Использование свойств и методов элемента ActiveX

ButtonerCtl.h и ButtonerCtl.cpp

[code:1:686b9e242d]#if !defined(AFX_BUTTONERCTL_H__6AE5A16F_9584_11D0_8860
_444553540000__INCLUDED_)
#define AFX_BUTTONERCTL_H__6AE5A16F_9584_11D0_8860
_444553540000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000


// ButtonerCtl.h : объявление класса элемента
// ActiveX CButtonerCtrl.


///////////////////////////////////////////////////////////
// CButtonerCtrl : реализация содержится в ButtonerCtl.cpp.


class CButtonerCtrl : public COleControl
{
DECLARE_DYNCREATE(CButtonerCtrl)
// Конструктор
public:
CButtonerCtrl();
// Переопределения
// Переопределения виртуальных функций,
// сгенерированные ClassWizard
//{{AFX_VIRTUAL(CButtonerCtrl)
public:
virtual void OnDraw(CDC* pdc, const CRect& rcBounds,
const CRect& rcInvalid);
virtual void DoPropExchange(CPropExchange* pPX);
virtual void OnResetState();
//}}AFX_VIRTUAL // Реализация
protected:
~CButtonerCtrl();


DECLARE_OLECREATE_EX(CBoxerCtrl) // Фабрика класса и guid
DECLARE_OLETYPELIB(CBoxerCtrl) // GetTypeInfo
DECLARE_PROPPAGEIDS(CBoxerCtrl)// Идентификаторы
// страниц свойств
DECLARE_OLECTLTYPE(CBoxerCtrl) // Имя типа и
// вспомогательная
// информация


// Поддержка субклассирования


BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL IsSubclassedControl();
LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam);


// Схемы сообщений
//{{AFX_MSG(CButtonerCtrl)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()


// Диспетчерские схемы
//{{AFX_DISPATCH(CButtonerCtrl)
short m_data;
afx_msg void OnDataChanged();
afx_msg void Beep();
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
afx_msg void AboutBox();


// Схемы событий
//{{AFX_EVENT(CButtonerCtrl)
//}}AFX_EVENT
DECLARE_EVENT_MAP()


// Диспетчерские идентификаторы и идентификаторы событий
public:
enum
{
//{{AFX_DISP_ID(CButtonerCtrl)
dispidData = 1L,
dispidBeep = 2L,
//}}AFX_DISP_ID
};
};


//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio вставляет дополнительные
// объявления перед предшествующей строкой. #endif
// !defined(AFX_BUTTONERCTL_H__6AE5A16F_9584_11D0
// _8860_444553540000__INCLUDED)


// ButtonerCtl.cpp : реализация класса элемента
// ActiveX CButtonerCtrl.


#include "stdafx.h"
#include "Buttoner.h"
#include "ButtonerCtl.h"
#include "ButtonerPpg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CButtonerCtrl, COleControl)


///////////////////////////////////////////////////////////
// Схема сообщений


BEGIN_MESSAGE_MAP(CButtonerCtrl, COleControl)
//{{AFX_MSG_MAP(CButtonerCtrl)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


///////////////////////////////////////////////////////////
// Диспетчерская схема


BEGIN_DISPATCH_MAP(CButtonerCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CButtonerCtrl)
DISP_PROPERTY_NOTIFY(CButtonerCtrl, "data", m_data,
OnDataChanged, VT_I2)
DISP_FUNCTION(CButtonerCtrl, "Beep", Beep, VT_EMPTY,
VTS_NONE)
//}}AFX_DISPATCH_MAP
DISP_FUNCTION_ID(CButtonerCtrl, "AboutBox",
DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()


///////////////////////////////////////////////////////////
// Схема событий


BEGIN_EVENT_MAP(CButtonerCtrl, COleControl)
//{{AFX_EVENT_MAP(CButtonerCtrl)
EVENT_STOCK_CLICK()
//}}AFX_EVENT_MAP
END_EVENT_MAP() ///////////////////////////////////////////////////////////
// Страницы свойств


// TODO: При необходимости добавьте новые
// страницы свойств.
// Не забудьте увеличить значение счетчика!
BEGIN_PROPPAGEIDS(CButtonerCtrl, 1)
PROPPAGEID(CButtonerPropPage::guid)
END_PROPPAGEIDS(CButtonerCtrl)


///////////////////////////////////////////////////////////
// Инициализация фабрики класса и guid


IMPLEMENT_OLECREATE_EX(CButtonerCtrl,
"BUTTONER.ButtonerCtrl.1",0x6ae5a161, 0x9584, 0x11d0,
0x88, 0x60, 0x44, 0x45, 0x53, 0x54, 0, 0)


///////////////////////////////////////////////////////////
// Идентификатор библиотеки типа и версия


IMPLEMENT_OLETYPELIB(CButtonerCtrl, _tlid, _wVerMajor, _wVerMinor)


///////////////////////////////////////////////////////////
// Идентификаторы интерфейсов


const IID BASED_CODE IID_DButtoner =
{ 0x6ae5a15f, 0x9584, 0x11d0, { 0x88, 0x60, 0x44, 0x45,
0x53, 0x54, 0, 0 } };
const IID BASED_CODE IID_DButtonerEvents =
{ 0x6ae5a160, 0x9584, 0x11d0, { 0x88, 0x60, 0x44, 0x45,
0x53, 0x54, 0, 0 } };


///////////////////////////////////////////////////////////
// Информация типа для элемента


static const DWORD BASED_CODE _dwButtonerOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE


OLEMISC_SETCLIENTSITEFIRST


OLEMISC_INSIDEOUT


OLEMISC_CANTLINKINSIDE


OLEMISC_RECOMPOSEONRESIZE;
IMPLEMENT_OLECTLTYPE(CButtonerCtrl, IDS_BUTTONER, _dwButtonerOleMisc)


///////////////////////////////////////////////////////////
// CButtonerCtrl::CButtonerCtrlFactory::UpdateRegistry -
// добавляет или удаляет записи системного реестра
// для CBoxerCtrl


BOOL CButtonerCtrl::CButtonerCtrlFactory::
UpdateRegistry(BOOL bRegister) {
// Убедитесь, что ваш элемент соответствует требованиям
// совместной потоковой модели. Подробности приведены
// в документе MFC TechNote 64.
// Если элемент нарушает требования совместной модели,
// необходимо модифицировать следующий фрагмент программы
// и заменить 6-й параметр с afxRegApartmentThreading
// на 0.


if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_BUTTONER,
IDB_BUTTONER,
afxRegApartmentThreading,
_dwButtonerOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::CButtonerCtrl - Конструктор


CButtonerCtrl::CButtonerCtrl()
{
InitializeIIDs(&IID_DButtoner, &IID_DButtonerEvents);
SetText("Нажми меня!");
// TODO: инициализируйте данные экземпляра
// вашего элемента.
m_data = 0;
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::~CButtonerCtrl - деструктор


CButtonerCtrl::~CButtonerCtrl()
{
// TODO: уничтожьте данные экземпляра вашего элемента.
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::OnDraw - функция рисования


void CButtonerCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
DoSuperclassPaint(pdc, rcBounds);
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::DoPropExchange - поддержка устойчивости


void CButtonerCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);


// TODO: Вызовите функции PX_ для каждого устойчивого
// свойства.
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::OnResetState - сброс элемента
// в состояние по умолчанию


void CButtonerCtrl::OnResetState()
{
COleControl::OnResetState(); // Присваивает значения
// по умолчанию из DoPropExchange
// Сбросьте любые другие параметры состояния элемента
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::AboutBox - отображение диалогового
// окна About


void CButtonerCtrl::AboutBox()
{
CDialog dlgAbout(IDD_ABOUTBOX_BUTTONER);
dlgAbout.DoModal();
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::PreCreateWindow - Изменение параметров
// для CreateWindowEx


BOOL CButtonerCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = _T("BUTTON");
return COleControl::PreCreateWindow(cs);
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::IsSubclassedControl - субклассированный
// элемент


BOOL CButtonerCtrl::IsSubclassedControl() {
return TRUE;
}


///////////////////////////////////////////////////////////
// CButtonerCtrl::OnOcmCommand - обработка командных
// сообщений


LRESULT CButtonerCtrl::OnOcmCommand(WPARAM wParam,
LPARAM lParam)
{
#ifdef _WIN32
WORD wNotifyCode = HIWORD(wParam);
#else
WORD wNotifyCode = HIWORD(lParam);
#endif
// TODO: Переключиться на wNotifyCode.
return 0;
}


///////////////////////////////////////////////////////////
// Обработчики сообщений CButtonerCtrl


void CButtonerCtrl::OnLButtonDown(UINT nFlags,
CPoint point)
{
// TODO: добавьте код обработки сообщения
// и/или вызовите обработчик по умолчанию
FireClick();
m_data++;
COleControl::OnLButtonDown(nFlags, point);
}


void CButtonerCtrl::OnDataChanged()
{
// TODO: добавьте код для обработки оповещений
// от элемента
SetModifiedFlag();
}


void CButtonerCtrl::Beep()
{
// TODO: добавьте код диспетчерской обработки
MessageBeep(MB_OK);
}
ButtonerappDlg.h и ButtonerappDlg.cpp
// ButtonerappDlg.h : заголовочный файл
//
//{{AFX_INCLUDES()
#include "buttoner.h"
//}}AFX_INCLUDES


#if !defined(AFX_BUTTONERAPPDLG_H__9F6EEC67_988A_11D0
_8860_444553540000__INCLUDED_)
#define AFX_BUTTONERAPPDLG_H__9F6EEC67_988A_11D0_8860
_444553540000__INCLUDED_


#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000


///////////////////////////////////////////////////////////
// Диалоговое окно CButtonerappDlg


class CButtonerappDlg : public CDialog
{
// Construction
public:
CButtonerappDlg(CWnd* pParent = NULL);
// Стандартный конструктор


// Данные диалогового окна
//{{AFX_DATA(CButtonerappDlg)
enum { IDD = IDD_BUTTONERAPP_DIALOG };
CString m_text;
CButtoner m_buttoner;
//}}AFX_DATA


// Переопределения виртуальных функций,
// сгенерированные ClassWizard
//{{AFX_VIRTUAL(CButtonerappDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX);
// Поддержка DDX/DDV
//}}AFX_VIRTUAL


// Реализация
protected:
HICON m_hIcon;


// Сгенерированные функции схемы сообщений
//{{AFX_MSG(CButtonerappDlg)


virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnClickButtonerctrl1();
DECLARE_EVENTSINK_MAP()
//}}AFX_MSG DECLARE_MESSAGE_MAP()
};


//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio вставляет дополнительные
// объявления перед предшествующей строкой.


#endif // !defined(AFX_BUTTONERAPPDLG_H__9F6EEC67_988A_11D0
// _8860_444553540000__INCLUDED_)


// ButtonerappDlg.cpp : файл реализации
//


#include "stdafx.h"
#include "Buttonerapp.h"
#include "ButtonerappDlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


///////////////////////////////////////////////////////////
// Диалоговое окно CAboutDlg, выводимое по команде About


class CAboutDlg : public CDialog
{
public:
CAboutDlg();


// Данные диалогов
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Russian ABAP Developer's Club Forum Index -> OLE2, Excel, WinWord All times are GMT + 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


All product names are trademarks of their respective companies. SAPNET.RU websites are in no way affiliated with SAP AG.
SAP, SAP R/3, R/3 software, mySAP, ABAP, BAPI, xApps, SAP NetWeaver and any other are registered trademarks of SAP AG.
Every effort is made to ensure content integrity. Use information on this site at your own risk.