Kselax.ru

Hacker Kselax — the best hacker in the world

Menu
  • Блог
  • Контакты
  • wp plugin генератор
  • Русский
    • Русский
    • English
Menu

Макросы в MFC

Posted on 11 июля, 201527 июля, 2015 by admin

Здорова ребятки!

В Этом посте я буду разбирать макросы MFC, там очень много разных макросов, которые не понятные зачем они используются и так далее. Пока что я разобрал два макроса IMPLEMENT_DYNCREATE и DECLARE_DYNCREATE начнем с них.

IMPLEMENT_DYNCREATE и DECLARE_DYNCREATE

Показать »

Эти макросы используются для динамического создания объектов и так начнем с определения макроса IMPLEMENT_DYNCREATE

1
2
3
4
5
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
class_name::CreateObject, NULL)

как мы видим создается функция CreateObject(), посмотрим определение макроса PASCAL:

1
#define PASCAL      __stdcall

Это просто знак для компилятора «Соглашение вызова». Дальше посмотрим определение макроса IMPLEMENT_RUNTIMECLASS:

1
2
3
4
5
6
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL, class_init }; \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return RUNTIME_CLASS(class_name); }

как мы видим здесь создается определение функция GetRuntimeClass и создается инициализируется структура CRuntimeClass. В нашем классе должен быть член класса с названием class_name::class##class_name. Посмотрим определение макроса AFX_COMBAT:

1
#define AFX_COMDAT __declspec(selectany)

Это какаето фигня, вот ссылка, можете почитать что там пишут по этому поводу. Смотрим определение макроса RUNTIME_CLASS:

1
#define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)

ну и смотрим макросс _RUNTIME_CLASS:

1
#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

тут возвращается указатель на class_name::class##class_name, он должен находится в нашем классе.

Теперь давайте напишем какой реальный код создается при вызове макроса IMPLEMENT_DYNCREATE

1
IMPLEMENT_DYNCREATE(CSpaceship,CCmdTarget);

CSpaceship — это класс порожденный от ССmdTarget, CCmdTarget- это базовый класс класса CSpaceship. И в итоге этот макрос создаст следующий код:

1
2
3
4
CObject* PASCAL CSpaceship::CreateObject()
{ return new CSpaceship; }
IMPLEMENT_RUNTIMECLASS(CSpaceship, CCmdTarget, 0xFFFF,
CSpaceship::CreateObject, NULL)

как видим появилось определение первой функция  CSpaceship::CreateObject, дальше вызывается макрос IMPLEMENT_RUNTIMECLASS, запишем что в результате этого вызова мы получим:

1
2
3
4
5
AFX_COMDAT const CRuntimeClass CSpaceship::classCSpaceship = {
#CSpaceship, sizeof(class CSpaceship), 0xFFFF, CSpaceship::CreateObject,
RUNTIME_CLASS(CCmdTarget), NULL, NULL };
CRuntimeClass* CSpaceship::GetRuntimeClass() const
{ return RUNTIME_CLASS(CSpaceship); }

здесь мы видим что идет инициализация структуры CRuntimeClass CSpaceship::classCspaceship — это статический член получается класса CSpaceship. и создается определение функции CSpaceship::GetRuntimeClass. И давайте теперь последний штрих заменим макрос RUNTIME_CLASS:

1
2
3
4
5
6
7
8
9
CObject* PASCAL CSpaceship::CreateObject()
{ return new CSpaceship; }
 
AFX_COMDAT const CRuntimeClass CSpaceship::classCSpaceship = {
#CSpaceship, sizeof(class CSpaceship), 0xFFFF, CSpaceship::CreateObject,
((CRuntimeClass*)(&CCmdTarget::class##CCmdTarget)), NULL, NULL };
 
CRuntimeClass* CSpaceship::GetRuntimeClass() const
{ return ((CRuntimeClass*)(&CSpaceship::classCSpaceship)); }

вот в общем то что мы получили в результате вызова

1
IMPLEMENT_DYNCREATE(CSpaceship,CCmdTarget);

два определения функции и инициализацию переменной.

 

Дальше разберем макрос DECLARE_DYNCREATE, вот его определение:

1
2
3
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \
static CObject* PASCAL CreateObject();

создалось объявление функции CreateObject  и вызвался макрос DECLARE_DYNAMIC, вот его определение:

1
2
3
4
#define DECLARE_DYNAMIC(class_name) \
public: \
static const CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \

здесь создается статический член на структуру CRuntimeClass и виртуальный метод GetRuntimeClass который возвращает указатель на структуру CRuntimeClass. Давайте запишем как это будет выглядеть для вызова

1
DECLARE_DYNCREATE(CSpaceship);

вот код:

1
2
DECLARE_DYNAMIC(CSpaceship)
static CObject* PASCAL CreateObject();

и еще раз для макроса DECLARE_DYNAMIC:

1
2
3
4
public:
static const CRuntimeClass classCSpaceship;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();

отакой код получается создает в классе

1
DECLARE_DYNCREATE(CSpaceship);

и от такой код

1
2
3
4
5
6
7
8
9
CObject* PASCAL CSpaceship::CreateObject()
{ return new CSpaceship; }
 
AFX_COMDAT const CRuntimeClass CSpaceship::classCSpaceship = {
#CSpaceship, sizeof(class CSpaceship), 0xFFFF, CSpaceship::CreateObject,
((CRuntimeClass*)(&CCmdTarget::class##CCmdTarget)), NULL, NULL };
 
CRuntimeClass* CSpaceship::GetRuntimeClass() const
{ return ((CRuntimeClass*)(&CSpaceship::classCSpaceship)); }

создается при вызове

1
IMPLEMENT_DYNCREATE(CSpaceship,CCmdTarget);

Приведем несколько реальных примеров использования этих двух макросов IMPLEMENTE_DYNCRATE и DECLARE_DYNCRATE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using std::cout;
#include <afxwin.h>
 
class CMy_class : public CObject
{
public:
//есили конструктора нету, то он вроде создается пустой сам по себе
// CMy_class(){}
void print(){cout <<"class CMy_class\r\n";}
//создает две функции:
//static CObject* PASCAL CreateObject();
//virtual CSpaceship* GetRuntimeClass() const;
//и переменную static const CRuntimeClass classCSpaceship;
DECLARE_DYNCREATE(CMy_class)
};
 
//создает определение функций выше
/*CObject* PASCAL CMy_class::CreateObject()
        { return new CMy_class; }
AFX_COMDAT const CRuntimeClass CMy_class::classCMy_class = {
"CMy_class", sizeof(class CMy_class), 0xFFFF, CMy_class::CreateObject,
((CRuntimeClass*)(&CObject::classCMy_class)), NULL, NULL };
CRuntimeClass* CMy_class::GetRuntimeClass() const
{ return ((CRuntimeClass*)(&CMy_class::classCMy_class)); }
*/
IMPLEMENT_DYNCREATE(CMy_class,CObject)
 
int main()
{
//создаем динамически объект
CMy_class* ptr=(CMy_class*)CMy_class::CreateObject();
ptr->print();
//получаем доступ к структуре CRuntimeClass
CRuntimeClass* pRun=ptr->GetRuntimeClass();
//m_lpszClassName-имя класса в виде строки заканчивающееся нулем
//m_nObjectSize-размер объекта в байтах
//m_wSchema-номер версии
cout <<pRun->m_lpszClassName<<" - "<<pRun->m_nObjectSize<<" - "<<pRun->m_wSchema<<"\r\n";
 
return 0;
}

Вывод:

mfc macros

TRACE

Показать »

И так разберем этот макрос, сразу не сильно понятно что он делает, почитать можно здесь. Так этот макрос работает только при отладке, если мы просто компилируем программу то он компилируется в ничего. Разберем простой примерчик кода:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using std::cout;
#include <afxwin.h>
 
void f(double a, int b)
{
TRACE("'%d' - Переменная %f\r\n",b,a);
}
 
int main()
{
TRACE("Hellow world!\r\n");
f(0.35, 333);
 
return 0;
}

И вывод:

mfc outputВывод идет во вкладку вывод когда мы нажимаем F5 — отладка.

Там еще существует несколько макросов TRACE0,TRACE1,TRACE2 и TRACE3 цифры означают количество параметров. Хз. зачем их использовать, мы будем использовать просто TRACE.

 BEGIN_MESSAGE_MAP и END_MESSAGE_MAP и DECLARE_MESSAGE_MAP

Показать »

Так в общем разберем два этих макроса

Начнем с BEGIN_MESSAGE_MAP, вот ее определение:

1
2
3
4
5
6
7
8
9
10
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
PTM_WARNING_DISABLE \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return GetThisMessageMap(); } \
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ \
typedef theClass ThisClass;    \
typedef baseClass TheBaseClass;    \
static const AFX_MSGMAP_ENTRY _messageEntries[] =  \
{

Как мы видим создается определение функция theClass::GetMessageMap и определение второй функции theClass::GetThisMessageMap. Давайте выведем все остальные макросы которые есть в объявлении макроса выше. PTM_WARNING_DISABE:

1
2
3
#define PTM_WARNING_DISABLE \
__pragma(warning( push )) \
__pragma(warning( disable : 4867 ))

тут ничего не ясно что это за фигня, про __pragma можно тут почитать. Смотрим определение AFX_MSGMAP:

1
2
3
4
5
struct AFX_MSGMAP
{
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
const AFX_MSGMAP_ENTRY* lpEntries;
};

Это оказывается структура, и посмотрим определение AFX_MSGMAP_ENTRY:

1
2
3
4
5
6
7
8
9
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;   // windows message
UINT nCode;      // control code or WM_NOTIFY code
UINT nID;        // control ID (or 0 for windows messages)
UINT nLastID;    // used for entries specifying a range of control id's
UINT_PTR nSig;   // signature type (action) or pointer to message #
AFX_PMSG pfn;    // routine to call (or special value)
};

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

1
BEGIN_MESSAGE_MAP(CSpaceship,CCmdTarget)

И получаем мы:

1
2
3
4
5
6
7
8
9
10
__pragma(warning( push ))
__pragma(warning( disable : 4867 ))
const AFX_MSGMAP* CSpaceship::GetMessageMap() const
{ return GetThisMessageMap(); }
const AFX_MSGMAP* __stdcall CSpaceship::GetThisMessageMap()
{
typedef CSpaceship ThisClass;   
typedef CCmdTarget TheBaseClass;   
static const AFX_MSGMAP_ENTRY _messageEntries[] =  
{

как бы такой вроде код создается. как видно идет определение одной функции CSpaceship::GetMessageMap и начинается начало определения второй функции CSpaceship::GetThisMessageMap

Разберем макрос END_MESSAGE_MAP, вот его определение:

1
2
3
4
5
6
7
8
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
static const AFX_MSGMAP messageMap = \
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
return &messageMap; \
}   \
PTM_WARNING_RESTORE

по коду видно что в скобках передаются какие то параметры видимо доинициализируют структуру AFX_MSGMAP_ENTRY, а также создается статическая конст переменная на AFX_MSGMAP под названием messageMap, ей присваиваются два указателя в скобках TheBaseClass::GetThisMessageMap и _messageEntries[0] — указатель на первый элемент. и возвращается указатель на messageMap — указатель на структуру.

Давайте теперь все вместе запишем что у нас получается

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__pragma(warning( push ))
__pragma(warning( disable : 4867 ))
const AFX_MSGMAP* CSpaceship::GetMessageMap() const
{ return GetThisMessageMap(); }
const AFX_MSGMAP* __stdcall CSpaceship::GetThisMessageMap()
{
typedef CSpaceship ThisClass;   
typedef CCmdTarget TheBaseClass;   
static const AFX_MSGMAP_ENTRY _messageEntries[] =  
{
//здесь записываем наши функции
 
//конец функций
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};
static const AFX_MSGMAP messageMap =
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] };
return &messageMap;
}   
PTM_WARNING_RESTORE

И наконец разберем DECLARE_MESSAGE_MAP

Этот макрос добавляется непосредственно в сам класс и он добавляет к классу объявление функций:

1
2
3
4
#define DECLARE_MESSAGE_MAP() \
protected: \
static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
virtual const AFX_MSGMAP* GetMessageMap() const; \

Видно что добавляется определение ptotected: и две функции: статическая GetThisMessageMap; и GetMessageMap обе функции возвращают указатель на структуру AFX_MSGMAP* выще мы нашли ее определение. Вообще глянув на код выще функция GetMessageMap вызывает функцию GetThisMessageMap, GetMessage получается обертка над GetMessageMap.

Посмотрим теперь как используется эти макросы вот код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BEGIN_MESSAGE_MAP(Ctest_timerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER() // реагировать на таймер
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)//собственная функция
 
ON_MESSAGE(WM_THREADENDED,OnThreadEnded)
 
ON_BN_CLICKED(IDC_BUTTON1, &Ctest_timerDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &Ctest_timerDlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &Ctest_timerDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &Ctest_timerDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &Ctest_timerDlg::OnBnClickedButton5)
END_MESSAGE_MAP()

я из кода:

1
2
3
4
5
6
7
static const AFX_MSGMAP_ENTRY _messageEntries[] =  
{
//здесь записываем наши функции
 
//конец функций
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};

что тут идет инициализация последнего элемента массива _messageEntries[] значением

1
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }

получается каждый наш макрос: ON_WM_SYSCOMMAND, ON_WM_PAINT, ON_WM_QUERYDRAGICON, и т.д. заменяет на скобки с 6 параметрами для инициализации массива структуры

1
static const AFX_MSGMAP_ENTRY _messageEntries[]

Приведем пример определения например макроса ON_WM_QUERYDRAGICON:

1
2
3
4
#define ON_WM_QUERYDRAGICON() \
{ WM_QUERYDRAGICON, 0, 0, 0, AfxSig_hv, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< HCURSOR (AFX_MSG_CALL CWnd::*)(void) > ( &ThisClass :: OnQueryDragIcon)) },

видно что там 6 параметров так же как и у структуры AFX_MSGMAP_ENTRY, шестой параметр — это указатель на функцию. Определение AFX_MSG_CALL:

1
2
3
4
#ifndef AFX_MSG_CALL
#define AFX_MSG_CALL
#endif
typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

в общем мы скажем что ничего не ясно что происходит. Ясно одно что эти 3 макроса создают 2 функции одна из которых обертка это GetMessageMap, а вторая GetThisMessageMap создает два typedef на класс и базовый класс с названиями ThisClass и TheBaseClass и производит инициализацию массива static const AFX_MSGMAP_ENTRY _messageEntries[] ={{},{},{},{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }}. Так же там я только щас заметил создается статический указатель на первый элемент массива этими строчками:

1
2
static const AFX_MSGMAP messageMap = \
        { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \

и потом этот указатель на карту возвращается return &messageMap; это похоже на возвтар указателя, значит messageMap — это просто первый элемент массива.

Приведем реальный примерчик использования этих макросов.

В примерчике создается 2 карты сообщений:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <afxwin.h> // MFC Основные и стандартные компоненты
 
#define IDC_MYBUTTON 100 // Идентификатор кнопки
#define IDC_MYEDIT 102 // Идентификатор поля редактирования
 
class CMyButton: public CButton
{
public:
afx_msg void OnLButtonDblClk(UINT, CPoint);
afx_msg void OnRButtonDblClk(UINT, CPoint);
private:
DECLARE_MESSAGE_MAP(); // таблица откликов кнопки
};
 
void CMyButton::OnLButtonDblClk(UINT, CPoint)
{
MoveWindow(CRect(120,100,220,150),TRUE);
}
 
void CMyButton::OnRButtonDblClk(UINT, CPoint)
{
MoveWindow(CRect(120,10,220,50),TRUE);
}
 
BEGIN_MESSAGE_MAP(CMyButton, CButton) // таблица откликов на сообщения
ON_WM_LBUTTONDBLCLK()
ON_WM_RBUTTONDBLCLK()
END_MESSAGE_MAP()
 
class CMainWnd : public CFrameWnd
{
public:
CMainWnd(); // Конструктор по умолчанию
~CMainWnd();//деструктор
afx_msg void OnLButtonDblClk(UINT, CPoint); // виртуальная процедура ответа на левую кнопку
afx_msg void OnRButtonDblClk(UINT, CPoint); // виртуальная процедура ответа на правую кнопку
afx_msg void OnKeyDown(UINT, UINT, UINT); // виртуальная процедура ответа на клавишу
afx_msg void OnButtonDown();//функция вызывающаяся по нажатию на кнопку
private:
CStatic* MyStatic; // Указатель на объект надпись
CMyButton* MyButton; // Указатель на объект кнопка
CEdit* MyEdit; // Указатель на объект поле редактирования
DECLARE_MESSAGE_MAP(); // таблица откликов
};
 
//карта сообщений создается две функции
BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) // таблица откликов на сообщения
ON_WM_LBUTTONDBLCLK() // реакция на нажатие левой кнопки мыши
ON_WM_RBUTTONDBLCLK() // реакция на нажатие правой кнопки мышки
ON_WM_KEYDOWN() // реакция на нажатие клавиши
END_MESSAGE_MAP()
 
void CMainWnd::OnKeyDown(UINT, UINT, UINT)
{
AfxMessageBox(L" Key Button Down ");
}
void CMainWnd::OnRButtonDblClk(UINT, CPoint)
{
AfxMessageBox(L" Rigth Button Click ");
}
void CMainWnd::OnLButtonDblClk(UINT, CPoint)
{
AfxMessageBox(L" Left Button Click ");
}
 
CMainWnd::CMainWnd()
{
Create(NULL,L"Step2",WS_OVERLAPPEDWINDOW,rectDefault,
NULL,NULL);// Создать окно программы
// оператор new по умолчанию в случае ошибки вернет NULL
// проверка указателя на NULL дает возможность избавиться от дальнейших ошибок
MyStatic = new CStatic();
if (MyStatic!=NULL) MyStatic->Create(L"MyStatic",WS_CHILD|WS_VISIBLE|SS_CENTER,
CRect(10,10,100,50),this); // создали
MyButton = new CMyButton();  // Меняем класс, на основе которого создается объект
if (MyButton!=NULL) MyButton->Create(L"MyButton",WS_CHILD|WS_VISIBLE|SS_CENTER,
CRect(120,10,220,50),this,IDC_MYBUTTON);
MyEdit = new CEdit();
if (MyEdit!=NULL) MyEdit->Create(WS_CHILD|WS_VISIBLE|WS_BORDER,
CRect(240,10,340,50),this,IDC_MYEDIT);
}
CMainWnd::~CMainWnd()
{
if (MyStatic!=NULL) delete MyStatic; // удалить динамический объект
if (MyButton!=NULL) delete MyButton; // удалить динамический объект
if (MyEdit!=NULL) delete MyEdit; // удалить динамический объект
}
 
class CMyApp : public CWinApp
{
public:
CMyApp(); //конструктор по умолчанию
virtual BOOL InitInstance();//стандартная инициализация
};
 
CMyApp::CMyApp() // конструктор главного класса приложения
{}
 
BOOL CMyApp::InitInstance() // стандартная инициализация
{
m_pMainWnd=new CMainWnd(); // создать класс окна
ASSERT(m_pMainWnd); // проверить его правильность
m_pMainWnd->ShowWindow(SW_SHOW);// Показать окно
m_pMainWnd->UpdateWindow(); // Обновить окно
return TRUE; // Вернуть что все нормально
};
 
CMyApp theApp; // запуск приложения

так же еще бывает такая штука

1
2
3
4
5
BEGIN_MESSAGE_MAP(CSpaceship,CCmdTarget)
//{{AFX_MSG_MAP(CSpaceship)
//ПРИМЕЧАНИЕ: здесь ClassWizard будет добавлять и удалять макросы
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

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

 BEGIN_INTERFACE_MAP, END_INTERFACE_MAP,  INTERFACE_PART и BEGIN_INTERFACE_PART,  END_INTERFACE_PART,  STDMETHOD_,  DECLARE_INTERFACE_MAP

Показать »

Да как мы видим очень много макросов нужно разобрать, начнем с этих макросов которые формируют код:

1
2
3
4
BEGIN_INTERFACE_MAP(CSpaceship,CCmdTarget)
INTERFACE_PART(CSpaceship,IID_IMotion,Motion)
INTERFACE_PART(CSpaceship,IID_IVisual,Visual)
END_INTERFACE_MAP()

Описание BEGIN_INTERFACE_MAP, INTERFACE_PART и END_INTERFACE_MAP

Определение BEGIN_INTERFACE_MAP:

1
2
3
4
5
6
7
#define BEGIN_INTERFACE_MAP(theClass, theBase) \
const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const \
{ return &theClass::interfaceMap; } \
AFX_COMDAT const AFX_INTERFACEMAP theClass::interfaceMap = \
{ &theBase::interfaceMap, &theClass::_interfaceEntries[0], }; \
AFX_COMDAT const AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = \
{ \

Как видим создается определение функции GetInterfaceMap() которая возвращает указатель на структуру interfaceMap типа AFX_INTERFACEMAP посмотрим его определение:

1
2
3
4
5
6
7
8
9
struct AFX_INTERFACEMAP
{
#ifdef _AFXDLL
const AFX_INTERFACEMAP* (PASCAL* pfnGetBaseMap)(); // NULL is root class
#else
const AFX_INTERFACEMAP* pBaseMap;
#endif
const AFX_INTERFACEMAP_ENTRY* pEntry; // map for this class
};

это получается структура, в которой содержится указатель на саму себя pBaseMap и какой то указатель на функцию pfnGetBaseMap, наверно эта функция возвращает этот указатель. Посмотрим определение AFX_INTERFACEMAP_ENTRY:

1
2
3
4
5
struct AFX_INTERFACEMAP_ENTRY
{
const void* piid;       // the interface id (IID) (NULL for aggregate)
size_t nOffset;         // offset of the interface vtable from m_unknown
};

ага это структуна, на нее есть указатель, и как видим она содержит указатель на void* piid и size_t nOffset.

Ладно в самой BEGIN_INTERFACE_MAP происходит инициализация члена interfaceMap, как мы определили это структура и ей передается указатель на первый элемент массива _iterfaceEntries[0]

1
2
AFX_COMDAT const AFX_INTERFACEMAP theClass::interfaceMap = \
{ &theBase::interfaceMap, &theClass::_interfaceEntries[0], };

я от смотрю на нее и не сильно понимаю что происходит, но глядя на фигурные скобки понимаю что идет инициализация struct структуры AFX_INTERFACEMAP

Так же мы видим что идет инициализация массива _interfaceEntries в фигурных скобках

1
2
AFX_COMDAT const AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = \
{ \

 

Давайте посмотрим определение END_INTERFACE_MAP

1
2
3
#define END_INTERFACE_MAP() \
{ NULL, (size_t)-1 } \
}; \

тут все проще происходит инициализация последнего элемента массива _interfaceEntries {} это показывают. Глядя на весь код нам становится ясно что макросы:

1
2
INTERFACE_PART(CSpaceship,IID_IMotion,Motion)
INTERFACE_PART(CSpaceship,IID_IVisual,Visual)

должны заменятся на фигурные скобки {} для инициализации массива _interfaceEntries, в  фигурных скобках должно быть 2 элемента, давайте посмотрим определение INTERFACE_PART:

1
2
#define INTERFACE_PART(theClass, iid, localClass) \
{ &iid, offsetof(theClass, m_x##localClass) }, \

Ну да так оно и есть, как мы вдидим возвращается два параметра в скобках, первый параметрах это const void* piid; // the interface id (IID) (NULL for aggregate), а второй это size_t nOffset; // offset of the interface vtable from m_unknown.

То есть конструкция:

1
2
3
4
BEGIN_INTERFACE_MAP(CSpaceship,CCmdTarget)
INTERFACE_PART(CSpaceship,IID_IMotion,Motion)
INTERFACE_PART(CSpaceship,IID_IVisual,Visual)
END_INTERFACE_MAP()

создаст нам определение функции GetInterfaceMap инициализирует переменную AFX_COMDAT const AFX_INTERFACEMAP theClass::interfaceMap и инициализирует массив AFX_COMDAT const AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[], которому мы передаем значения в виде макросов INTERFACE_PART.

Переходим теперь к макросам интерфейсов которые определяются в классе это DECLARE_INTERFACE_MAP, посмотрим его определение:

1
2
3
4
5
6
define DECLARE_INTERFACE_MAP() \
private: \
static const AFX_INTERFACEMAP_ENTRY _interfaceEntries[]; \
protected: \
static const AFX_INTERFACEMAP interfaceMap; \
virtual const AFX_INTERFACEMAP* GetInterfaceMap() const; \

Что и доказывает что есть две статические переменные _interfaceEntries[] массив и interfaceMap указатель  вроде как и прототип функции GetInterfacemap

Идем дальше в классе еще существую другие записи от такие:

1
2
3
4
BEGIN_INTERFACE_PART(Motion,IMotion)
STDMETHOD_(void,Fly)();
STDMETHOD_(int&,GetPosition)();
END_INTERFACE_PART(Motion)

Посмотрим определение BEGIN_INTERFACE_PART:

1
2
3
4
5
6
7
#define BEGIN_INTERFACE_PART(localClass, baseClass) \
class X##localClass : public baseClass \
{ \
public: \
STDMETHOD_(ULONG, AddRef)(); \
STDMETHOD_(ULONG, Release)(); \
STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj); \

Здесь видно что начинается создаваться класс x##localClass : public baseClass, там вроде как  добавляются 3 метода Addref, Release и QueryInterface, щас посмотрим определение макроса STDMETHOD_:

1
#define STDMETHOD_(type,method)  virtual COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE method

Определение STDMETHOD:

1
#define STDMETHOD(method) virtual COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE method

Определение HRESULT:

1
typedef __success(return >= 0) long HRESULT;

Определение COM_DECLSPEC_NOTHROW:

1
#define COM_DECLSPEC_NOTHROW DECLSPEC_NOTHROW

Определение DECLSPEC_NOTHROW:

1
#define DECLSPEC_NOTHROW   __declspec(nothrow)

это как мы видим директива препроцессора. Этот атрибут сообщает компилятору, что и объявленная функция, и функции, которые она вызывает, никогда не создают исключений. Почитать можно тут. Посмотрим определение STDMETHODCALLTYPE:

1
#define STDMETHODCALLTYPE       __stdcall

запишем полностью

1
2
3
4
5
6
7
#define BEGIN_INTERFACE_PART(localClass, baseClass) \
class X##localClass : public baseClass \
{ \
public: \
virtual __declspec(nothrow) ULONG __stdcall AddRef();
virtual __declspec(nothrow) ULONG __stdcall Release();
virtual __declspec(nothrow) __success(return >= 0) __stdcall QueryInterface(REFIID iid, LPVOID* ppvObj);

от такое получается создаются определения функций.

Посмотрим определение END_INTERFACE_PART:

1
2
3
#define END_INTERFACE_PART(localClass) \
} m_x##localClass; \
friend class X##localClass; \

как мы видим делает конец класса и добавляет встраиваемый член m_x##localClass и делает наш класс другом

Определение STDMETHOD_(void,Fly)(); мы уже знаем тут создастся определение функции:

1
virtual __declspec(nothrow) void __stdcall Fly();

и для второго определения STDMETHOD_(int&,GetPosition)(); функция:

1
virtual __declspec(nothrow) int& __stdcall GetPosition();

И теперь давайте все вместе запишем что у нас получилось:

1
2
3
4
5
6
7
8
9
10
class X##localClass : public baseClass
{
public:
virtual __declspec(nothrow) ULONG __stdcall AddRef();
virtual __declspec(nothrow) ULONG __stdcall Release();
virtual __declspec(nothrow) __success(return >= 0) __stdcall QueryInterface(REFIID iid, LPVOID* ppvObj);
virtual __declspec(nothrow) void __stdcall Fly();
virtual __declspec(nothrow) int& __stdcall GetPosition();
} m_x##localClass;
friend class X##localClass;

Вот такой от класс создается, то есть создается интерфейсный класс и определения этих классов записывается вне класса в виде:

1
2
3
4
5
6
7
8
9
10
11
12
13
STDMETHODIMP_(ULONG) CSpaceship::XMotion::Release()
{
TRACE("CSpaceship::XMotion::Release\n");
METHOD_PROLOGUE(CSpaceship,Motion)
return pThis->ExternalRelease();
}
 
STDMETHODIMP CSpaceship::XMotion::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
ITrace(iid, "CSpaceship::XMotion::QueryInterface");
METHOD_PROLOGUE(CSpaceship,Motion)
return pThis->ExternalQueryInterface(iid,ppvObj);
}

Смотрим определение STDMETHODIMP_:

1
#define STDMETHODIMP_(type)     type STDMETHODCALLTYPE

Смотрим определение STDMETHODCALLTYPE:

1
#define STDMETHODCALLTYPE       __stdcall

Смотрим определение STDMETHODIMP:

1
#define STDMETHODIMP            HRESULT STDMETHODCALLTYPE

Ну в общем добавляются директивы препроцессора и всякая фигня перед функцией.

Попробуем создать реальный пример с использованием этих макросов.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <iostream>
using std::cout;
#include <afxwin.h>
 
//идентификаторы интерфейсов
//{692D03A-C689-11CE-B337-88EA36DE9E4E}
static const IID IID_IOne=
{0x692d03a4,0xc689,0x11ce,{0xb3,0x37,0x88,0xae,0x36,0xde,0x9e,0x4e}};
 
//{692D0eA5-C689-11CE-B337-88EA36DE9E4E}
static const IID IID_ITwo=
{0x692d03a5,0xc689,0x11ce,{0xb3,0x37,0x88,0xea,0x36,0xde,0x9e,0x4e}};
 
//------Интерфейсы COM-----
struct IOne : public IUnknown
{
STDMETHOD_(void,One_Print)()=0;
};
struct ITwo : public IUnknown
{
STDMETHOD_(void,Two_Print)()=0;
};
 
//-----Сам объект COM-----
class CMy_COM : public CCmdTarget
{
private:
int m_pOne;
int m_pTwo;
protected:
CMy_COM():m_pOne(10),m_pTwo(20){TRACE("CMy_COM\n");}
virtual ~CMy_COM(){TRACE("~CMy_COM\n");}
 
//для динамического создания
DECLARE_DYNCREATE(CMy_COM)
 
//создаем вложеные классы интерфейсы
//XOne m_xOne
BEGIN_INTERFACE_PART(One,IOne)
STDMETHOD_(void,One_Print)();
END_INTERFACE_PART(One)
//XTwo m_xTwo
BEGIN_INTERFACE_PART(Two,ITwo)
STDMETHOD_(void,Two_Print)();
END_INTERFACE_PART(Two)
};
 
IMPLEMENT_DYNCREATE(CMy_COM,CCmdTarget)
 
//-----------определение функций интерфейсов-------
//---IOne
//1.Стандарт из IUnknown
STDMETHODIMP_(ULONG) CMy_COM::XOne::AddRef()
{
TRACE("CMy_COM::XOne::AddRef\n");
METHOD_PROLOGUE(CMy_COM,One)
return pThis->ExternalAddRef();
}
 
STDMETHODIMP_(ULONG) CMy_COM::XOne::Release()
{
TRACE("CMy_COM::XOne::Release\n");
METHOD_PROLOGUE(CMy_COM,One)
return pThis->ExternalRelease();
}
 
STDMETHODIMP CMy_COM::XOne::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
TRACE("CMy_COM::XOne::QueryInterface iid=%d", iid);
METHOD_PROLOGUE(CMy_COM,One)
return pThis->ExternalQueryInterface(&iid,ppvObj);
}
 
//2. собственная функция
STDMETHODIMP_(void) CMy_COM::XOne::One_Print()
{
TRACE("CSpaceship::XMotion::Fly\n");
METHOD_PROLOGUE(CMy_COM,One)
TRACE("m_pOne=%d\n",pThis->m_pOne);
return;
}
 
//-----ITwo-----
//1.Стандарт из IUnknown
STDMETHODIMP_(ULONG) CMy_COM::XTwo::AddRef()
{
TRACE("CMy_COM::XOne::AddRef\n");
METHOD_PROLOGUE(CMy_COM,Two)
return pThis->ExternalAddRef();
}
 
STDMETHODIMP_(ULONG) CMy_COM::XTwo::Release()
{
TRACE("CMy_COM::XOne::Release\n");
METHOD_PROLOGUE(CMy_COM,Two)
return pThis->ExternalRelease();
}
 
STDMETHODIMP CMy_COM::XTwo::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
TRACE("CMy_COM::XOne::QueryInterface iid=%d", iid);
METHOD_PROLOGUE(CMy_COM,Two)
return pThis->ExternalQueryInterface(&iid,ppvObj);
}
 
//2. собственная функция
STDMETHODIMP_(void) CMy_COM::XTwo::Two_Print()
{
TRACE("CMy_COM::XTwo::Two_Print\n");
METHOD_PROLOGUE(CMy_COM,Two)
TRACE("m_pTwo=%d\n",pThis->m_pTwo);
return;
}
 
 
int main()
{
cout <<"COM-klient\r\n";
 
IUnknown* pIUnk=nullptr;
IOne* pIOne=nullptr;
ITwo* pITwo=nullptr;
 
CMy_COM* p = (CMy_COM*)CMy_COM::CreateObject();
pIOne=&p->m_xOne;
pITwo=&p->m_xTwo;
 
pIOne->One_Print();
pITwo->Two_Print();
 
exit(1);
//передаем идентификатор интерфейса и получаем интерфейс
pIUnk->QueryInterface(IID_IOne,(void**)&pITwo);
if(pITwo==nullptr){cout <<"ne naideno\r\n";}
else
{
pITwo->QueryInterface(IID_ITwo,(void**)&pIOne);
pITwo->Two_Print();
}
if(pIOne==nullptr){cout <<"ne naideno\r\n";}
else{pIOne->One_Print();}
if(pIUnk!=nullptr)pIUnk->Release();
if(pIOne!=nullptr)pIOne->Release();
if(pITwo!=nullptr)pITwo->Release();
 
cout <<"end COM-klient\r\n";
return 0;
}

в этом коде я не могу еще реально использовать функции AddReff, Release  и QueryInterface. Они не работают.

 DECLARE_OLECREATE, IMPLEMENT_OLECREATE и IMPLEMENT_OLECREATE_FLAGS

Показать »

Посмотрим определение DECLARE_OLECREATE:

1
2
3
4
#define DECLARE_OLECREATE(class_name) \
public: \
static COleObjectFactory factory; \
static const GUID guid; \

Как видим создается объявление двух статических переменных static COleObjectFactory factory и static const GUID guid, GUID — это уникальный глобальный идентификатор.

Посмотрим определение IMPLEMENT_OLECREATE:

1
2
3
4
5
#define IMPLEMENT_OLECREATE(class_name, external_name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
COleObjectFactory class_name::factory(class_name::guid, \
RUNTIME_CLASS(class_name), FALSE, _T(external_name)); \
AFX_COMDAT const GUID class_name::guid = \
{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; \

тут видно идет инициализация статической переменной (объекта) COleObjectFactory class_name::factory(); и ей передаются какие то параметры и идет инициализация второго статического члена __declspec(selectany) const GUID class_name::guid={}, как видно из инициализации это структура GUID — уникальный глобальный идентификатор и определение AFX_COMDAT:

1
#define AFX_COMDAT __declspec(selectany)

Посмотрим определение макроса IMPLEMENT_OLECREATE_FLAGS:

1
2
3
4
5
#define IMPLEMENT_OLECREATE_FLAGS(class_name, external_name, nFlags, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
COleObjectFactory class_name::factory(class_name::guid, \
RUNTIME_CLASS(class_name), FALSE, nFlags, _T(external_name)); \
AFX_COMDAT const GUID class_name::guid = \
{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; \

как видно происходит то же самое что и в макросе IMPLEMENT_OLECREATE, только еще добавляется флаг. Например в таком вызове:

1
2
// {1CCB6EAC-3853-4354-8CB2-E454C5B3AE15}
IMPLEMENT_OLECREATE_FLAGS(CMyCom, "My_new_COM.MyCom", afxRegApartmentThreading, 0x1ccb6eac, 0x3853, 0x4354, 0x8c, 0xb2, 0xe4, 0x54, 0xc5, 0xb3, 0xae, 0x15)

флаг у нас переменная afxRegApartmentThreading, ее определение:

1
2
3
4
5
6
7
enum AFX_REG_FLAGS
{
afxRegDefault               = 0x0000,
afxRegInsertable            = 0x0001,
afxRegApartmentThreading    = 0x0002,
afxRegFreeThreading     = 0x0004,
};

как видно IMPLEMENT_OLECREATE отличается от IMPLEMENT_OLECREATE_FLAGS отличается тем что происходит инициализация с флагом и без флага, в классе COleObjectFactory определено два конструктора, вот их определения:

1
2
3
4
5
6
// Construction
public:
COleObjectFactory(REFCLSID clsid, CRuntimeClass* pRuntimeClass,
BOOL bMultiInstance, LPCTSTR lpszProgID);
COleObjectFactory(REFCLSID clsid, CRuntimeClass* pRuntimeClass,
BOOL bMultiInstance, int nFlags, LPCTSTR lpszProgID);

В одном с флагом, в другом без.

Приведем примерчик использования этих макросов.

вот заголовочный файл с классом, файл CMyCom.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma once
 
 
// конечный объект команды CMyCom
 
class CMyCom : public CCmdTarget
{
DECLARE_DYNCREATE(CMyCom)
 
public:
CMyCom();
virtual ~CMyCom();
 
virtual void OnFinalRelease();
 
protected:
//создает карту сообщений
DECLARE_MESSAGE_MAP()
//
DECLARE_OLECREATE(CMyCom)
// DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
};

и вот файл с определением функция класса, там в самом низу есть макрос IMPLEMENT_OLECREATE_FLAGS

Файл MyCom.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// MyCom.cpp: файл реализации
//
 
#include "stdafx.h"
#include "My_new_COM.h"
#include "MyCom.h"
 
 
// CMyCom
 
IMPLEMENT_DYNCREATE(CMyCom, CCmdTarget)
 
 
CMyCom::CMyCom()
{
EnableAutomation();
// Чтобы обеспечить работу приложения в течение всего периода активности объекта автоматизации OLE,
// конструктор вызывает AfxOleLockApp.
AfxOleLockApp();
}
 
CMyCom::~CMyCom()
{
// Чтобы прервать работу приложения, когда все объекты созданы
// при помощи OLE-автоматизации, деструктор вызывает AfxOleUnlockApp.
AfxOleUnlockApp();
}
 
 
void CMyCom::OnFinalRelease()
{
// Когда будет освобождена последняя ссылка на объект автоматизации,
// вызывается OnFinalRelease. Базовый класс автоматически
// удалит объект. Перед вызовом базового класса добавьте
// дополнительную очистку, необходимую вашему объекту.
 
CCmdTarget::OnFinalRelease();
}
 
 
BEGIN_MESSAGE_MAP(CMyCom, CCmdTarget)
END_MESSAGE_MAP()
 
 
// Примечание: мы добавили поддержку для IID_IMyCom, чтобы обеспечить безопасную с точки зрения типов привязку
//  из VBA. Этот IID должен соответствовать GUID, связанному с
//  disp-интерфейсом в файле .IDL.
 
// {04CB6FA4-A072-4AC8-BD06-AB04A7B7BD2B}
static const IID IID_IMyCom =
{ 0x4CB6FA4, 0xA072, 0x4AC8, { 0xBD, 0x6, 0xAB, 0x4, 0xA7, 0xB7, 0xBD, 0x2B } };
 
BEGIN_INTERFACE_MAP(CMyCom, CCmdTarget)
INTERFACE_PART(CMyCom, IID_IMyCom, Dispatch)
END_INTERFACE_MAP()
 
// {1CCB6EAC-3853-4354-8CB2-E454C5B3AE15}
IMPLEMENT_OLECREATE_FLAGS(CMyCom, "My_new_COM.MyCom", afxRegApartmentThreading, 0x1ccb6eac, 0x3853, 0x4354, 0x8c, 0xb2, 0xe4, 0x54, 0xc5, 0xb3, 0xae, 0x15)
 
 
// обработчики сообщений CMyCom

FAILED и SUCCEEDED

Показать »

Определение этих макросов:

1
2
#define SUCCEEDED(hr)   (((HRESULT)(hr)) >= 0)
#define FAILED(hr)      (((HRESULT)(hr)) < 0)

как мы видим они просто принимают аргумент типа HRESULT и смотрят больше >=0 он или <0, то есть булево значение получается, а используется он вот в этом коде:

1
2
3
4
5
CLSID clsid;//GUID
hr = ::CLSIDFromProgID(L"My_COM", &clsid); //теперь мы просим систему найти для нас clsid по заданному ProgID
if (FAILED(hr)) { //если функция отработала с ошибкой делаем что то
return;
}

ProgID — это идентификатор программы, я его назвал как «My_COM» и через него функция CLSIDFromProgID возвращает GUID и мы проверяем с помощью макроса FAILED что результат у нас получилось, если результат меньше 0 то вернется true и мы выйдем из функции, если больше то будем что то делать дальше.

И можно еще так его использовать:

1
2
3
4
5
6
CLSID clsid;//GUID
hr = ::CLSIDFromProgID(L"My_COM", &clsid); //теперь мы просим систему найти для нас clsid по заданному ProgID
if (!SUCCEEDED(hr)) { //если функция отработала с ошибкой делаем что то
TRACE("unable to find Program ID -- error = %x\n", hr);
return;
}

DECLARE_DISPATCH_MAP() и BEGIN_DISPATCH_MAP()
END_DISPATCH_MAP()

Показать »

и так посмотрим определение макроса DECLARE_DISPATCH_MAP

1
2
3
4
5
6
7
8
#define DECLARE_DISPATCH_MAP() \
private: \
static const AFX_DISPMAP_ENTRY _dispatchEntries[]; \
static UINT _dispatchEntryCount; \
static DWORD _dwStockPropMask; \
protected: \
static const AFX_DISPMAP dispatchMap; \
virtual const AFX_DISPMAP* GetDispatchMap() const; \

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

1
2
3
4
5
6
7
8
9
10
11
struct AFX_DISPMAP
{
#ifdef _AFXDLL
const AFX_DISPMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_DISPMAP* pBaseMap;
#endif
const AFX_DISPMAP_ENTRY* lpEntries;
UINT* lpEntryCount;
DWORD* lpStockPropMask;
};

и глянем определение AFX_DISPMAP_ENTRY

1
2
3
4
5
6
7
8
9
10
11
struct AFX_DISPMAP_ENTRY
{
LPCTSTR lpszName;       // member/property name
long lDispID;           // DISPID (may be DISPID_UNKNOWN)
LPCSTR lpszParams;      // member parameter description
WORD vt;                // return value type / or type of property
AFX_PMSG pfn;           // normal member On<membercall> or, OnGet<property>
AFX_PMSG pfnSet;        // special member for OnSet<property>
size_t nPropOffset;     // property offset
AFX_DISPMAP_FLAGS flags;// flags (e.g. stock/custom)
};

В общем добавляются к классу данные 4 члена и функция.

 

Так смотрим макросы которые создают карту диспетчеризации, я подозреваю они инициализируют все эти 4 переменных, глянем определение макроса BEGIN_DISPATCH_MAP

1
2
3
4
5
6
7
8
9
10
#define BEGIN_DISPATCH_MAP(theClass, baseClass) \
const AFX_DISPMAP* theClass::GetDispatchMap() const \
{ return &theClass::dispatchMap; } \
AFX_COMDAT const AFX_DISPMAP theClass::dispatchMap = \
{ &baseClass::dispatchMap, &theClass::_dispatchEntries[0], \
&theClass::_dispatchEntryCount, &theClass::_dwStockPropMask }; \
AFX_COMDAT UINT theClass::_dispatchEntryCount = (UINT)-1; \
AFX_COMDAT DWORD theClass::_dwStockPropMask = (DWORD)-1; \
AFX_COMDAT const AFX_DISPMAP_ENTRY theClass::_dispatchEntries[] = \
{ \

видно создается определение добавленной функции GetDispatchMap() и дальше идет инициализация добавленных ранее членов. Так же видно что заполняется массив dispatchEntries[].

Посмотрим определение END_DISPATCH_MAP

1
2
3
#define END_DISPATCH_MAP() \
{ VTS_NONE, DISPID_UNKNOWN, VTS_NONE, VT_VOID, \
(AFX_PMSG)NULL, (AFX_PMSG)NULL, (size_t)-1, afxDispCustom } }; \

Видно что добавился последний элемент к массиву и все конец.

Что то я не увидел в этом классе IDispatch.

 

 

 

 

 

 

 

 

 

 

 

 

 

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Рубрики

  • C++ (293)
  • JavaScript (1)
  • linux (1)
  • MFC (39)
  • node.js (2)
  • React (3)
  • vBulletin (5)
  • Visual Studio (9)
  • wordpress (18)
  • Разное (29)

Метки

Ajax bootstrap CentOS CLI expressjs FormData GDlib google Invisible reCAPTCHA JWT media MFC php react-router-dom redux repository wordpress RTTI STL vBulletin vector Visual Studio WINAPI wordpress wp-plugins XMLHttpRequest Двоичное дерево Задачи С++ Игры С++ Исключения С++ О-большое Операторы_С++ Перегрузка операторов С++ Поиск С++ Потоки Проектирование_С++ С++ Типы_С++ Типы С++ Шаблоны С++ библиотеки локализация макросы С++ сортировка С++

Свежие комментарии

  • ExchiNuGs к записи Программка для заполнения форума на vBulletin 3.8.7
  • RA3PKJ к записи visual C++, создание диалоговых окон.
  • admin к записи Как удалить изображение из google
  • Shakanris к записи Программка для заполнения форума на vBulletin 3.8.7
  • костя к записи visual C++, создание диалоговых окон.
©2021 Kselax.ru Theme by ThemeGiant