Kselax.ru

Hacker Kselax — the best hacker in the world

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

OLE Автоматизация, создание клиентской программы на С++

Posted on 25 июля, 2015 by admin

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

в постах:

  1. http://www.kselax.ru/2015/07/ole-avtomatizaciya-sozdanie-ole-programy-dlya-ispolzovanie-v-excel/
  2. http://www.kselax.ru/2015/07/sozdanie-ole-prilozheniya-dll-s-ispolzovaniem-dialogovogo-okna-mfc/
  3. http://www.kselax.ru/2015/07/ole-avtomatizaciya-sozdanie-sdi-mfc-prilozheniya/

мы создавали сам компонент с использованием OLE автоматизации и использовали его в excel, теперь же мы создадим клиент на С++ который будет использовать эти компоненты, то есть у нас получится многомодульная программа. Начнем с создания приложения. Наша программка будет обычная SDI приложение без автоматизации.

1. Создание обычного SDI приложения в мастере MFC

Запускаем visual studio 2010, выбираем меню «Файл» -> «Создать» -> «Проект…» либо нажимаем Ctrl+Shift+N, у нас запустится окошко «Создать проект»  в нем выбираем «Приложение MFC», вводим имя проекта MyOleClient, нажимаем «Ок».

mfc create solyution

у нас запустится мастер приложений MFC, жмем «Далее», в появившемся окошке выставляем настройки такие как на скрине ниже

mfc SDI

жмем «Далее» все время или сразу нажимаем «Готово», потому что дальше мы ничего не меняем. У нас мастер создаст каркас приложения со следующим набором файлов

mfc workspace

На этом создание простого SDI приложение закончено, приступаем к портированию в наше приложение первой программки с использованием OLE автоматизации.

2. Создание контроллера для OLE_EXE

И так приступаем, как создавали мы OLE_EXE вы можете почитать тут, Это обычный компонент который поддерживает технологию OLE автоматизации. Для того чтобы в С++ программе использовать функции OLE_EXE мы должны создать класс контроллера. Для этого Visual Studio его просто генерирует из файла библиотеки типов .tlb — файла. В свою очередь файл tlb мастер visual stydio 2010 создает автоматически из файла idl или odl и сохраняет его в папку Debug или Release.

[warning]VS2010 создает файл tlb в каталоге Debug или Release в той директории где находятся файлы проекта, а не там куда создается exe файл, это важно, потому что я первый раз его искал именно там где находится exe файл и найти не мог[/warning]

Начнем генерацию контроллера из tlb файла, заходим в «Окно классов», кликаем правой клавишей мышки над «MyOleClient», из появившегося контекстного меню выбираем «Добавить» -> «Класс…», в появившемся окошке «Добавление класса» выбираем «MFC класс из TypeLib» и жмем «Добавить»

mfc add classis

мы попадаем в «Мастер добавления классов из библиотеки типов» в этом окошке находим наш файл tlb и указываем имя класса, я все делаю по умолчанию, выставите такие настройки как на скрине ниже

mfc add class for tlb

 

жмем «Готово» и мастер сгенерировал файл CBank.h, вот его код

CBank.h »

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
// Автоматически создаваемые классы-оболочки IDispatch, созданные при помощи мастера добавления класса из библиотеки типов
 
#import "D:\\Visual Studio 2010\\Projects\\OLE_EXE\\OLE_EXE\\Debug\\OLE_EXE.tlb" no_namespace
// CBank класс-оболочка
 
class CBank : public COleDispatchDriver
{
public:
CBank(){} // Вызывает конструктор по умолчанию для COleDispatchDriver
CBank(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
CBank(const CBank& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
 
// Атрибуты
public:
 
// Операции
public:
 
 
// IBank методы
public:
double Withdrawal(double dAmount)
{
double result;
static BYTE parms[] = VTS_R8 ;
InvokeHelper(0x1, DISPATCH_METHOD, VT_R8, (void*)&result, parms, dAmount);
return result;
}
void Deposit(double dAmount)
{
static BYTE parms[] = VTS_R8 ;
InvokeHelper(0x2, DISPATCH_METHOD, VT_EMPTY, NULL, parms, dAmount);
}
 
// IBank свойства
public:
double GetBalance()
{
double result;
GetProperty(0x3, VT_R8, (void*)&result);
return result;
}
void SetBalance(double propVal)
{
SetProperty(0x3, VT_R8, propVal);
}
 
};

Все контроллер создан, теперь подготовим меню для всего нашего приложения.

mfc ole exe menu

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

Показать »

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
void CMyOleClientView::OnOleLoad()
{
// TODO: добавьте свой код обработчика команд
if(!m_bank.CreateDispatch(L"OLE_EXE.Bank")) {
AfxMessageBox(L"OLE_EXE.Bank component not found");
return;
}
}
 
 
void CMyOleClientView::OnUpdateOleLoad(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_bank.m_lpDispatch==NULL);
}
 
 
void CMyOleClientView::OnOleTest()
{
// TODO: добавьте свой код обработчика команд
m_bank.Deposit(20.0);
m_bank.Withdrawal(15.0);
TRACE("new balance = %f\n", m_bank.GetBalance());
}
 
 
void CMyOleClientView::OnUpdateOleTest(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_bank.m_lpDispatch!=NULL);
}
 
 
void CMyOleClientView::OnOleUnload()
{
// TODO: добавьте свой код обработчика команд
m_bank.ReleaseDispatch();//освобождаем память
}
 
 
void CMyOleClientView::OnUpdateOleUnload(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_bank.m_lpDispatch!=NULL);
}

добавим в класс вида закрытую переменную m_bank типа CBank и подключим файл к виду #include «CBank.h».

Все в приложении мы подключили компонент OLE_EXE, нажимаем F5 — запускаем приложение в режиме отладки. и тестим, когда мы нажимаем test в отладке у нас выводится

mfc debug ole_exe

new balance = 5.00000, в общем все у нас работает.

[warning]И так где мы нашли progID для нашего приложения? Для приложения EXE_OLE progID находится в файле с классом Bank.cpp в проекте OLE_EXE, потому что сам компонент состоит из одного класса, вот эти строчки регистрируют OLE_EXE в реестре

1
2
// {91ED4E19-C337-463C-B93E-FF83FFB14FA2}
IMPLEMENT_OLECREATE_FLAGS(CBank, "OLE_EXE.Bank", afxRegApartmentThreading, 0x91ed4e19, 0xc337, 0x463c, 0xb9, 0x3e, 0xff, 0x83, 0xff, 0xb1, 0x4f, 0xa2)

Под progID «OLE_EXE.Bank»[/warning]

Переходим к внедрению следующего компонента.

3. Внедрение компонента MyOleDlg в проект

Как создавали мы этот проект MyOleDlg вы можете почитать тут.

И так проводим те же самые действия что мы делали и для первого компонента OLE_EXE. Для начала нам нужно создать контроллер наследованный от класса COleDispatchDriver. Генерируем контроллер из tlb файла. Заходи в «Окно классов», кликаем правой клавишей мышки по корню и из контекстного меню выбираем «Добавить» -> «Класс…», в появившемся окошке «Добавление класса» выбираем «MFC класс из TypeLib», жмем «Добавить». В появившемся окошке «Мастер добавления классов из библиотеки типов» выставляем примерно такие настройки как на скрине ниже

mfc add tlb file

жмем «Готово», у нас создался файл CMyDialog_Auto.h, вот его код

CMyDialog_Auto.h »

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
// Автоматически создаваемые классы-оболочки IDispatch, созданные при помощи мастера добавления класса из библиотеки типов
 
#import "D:\\Visual Studio 2010\\Projects\\MyOleDlg\\MyOleDlg\\Debug\\MyOleDlg.tlb" no_namespace
// CMyDialog_Auto класс-оболочка
 
class CMyDialog_Auto : public COleDispatchDriver
{
public:
CMyDialog_Auto(){} // Вызывает конструктор по умолчанию для COleDispatchDriver
CMyDialog_Auto(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
CMyDialog_Auto(const CMyDialog_Auto& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
 
// Атрибуты
public:
 
// Операции
public:
 
 
// IMyDialog_Auto методы
public:
BOOL DisplayDialog()
{
BOOL result;
InvokeHelper(0x3, DISPATCH_METHOD, VT_BOOL, (void*)&result, NULL);
return result;
}
 
// IMyDialog_Auto свойства
public:
long GetLongData()
{
long result;
GetProperty(0x1, VT_I4, (void*)&result);
return result;
}
void SetLongData(long propVal)
{
SetProperty(0x1, VT_I4, propVal);
}
VARIANT GetTextData()
{
VARIANT result;
GetProperty(0x2, VT_VARIANT, (void*)&result);
return result;
}
void SetTextData(VARIANT &propVal)
{
SetProperty(0x2, VT_VARIANT, &propVal);
}
 
};

все контроллер готов. Теперь нужно добавить новый пункт в меню, назовем его «MyOleDll». Оно будет иметь вид такое как на рисунке ниже

mfc menu MyOleDll

Добавим обработчики событий к пунктам меню и заполним созданные мастером функции для класса вида

Показать »

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
void CMyOleClientView::OnMyoledllLoad()
{
// TODO: добавьте свой код обработчика команд
if(!m_auto.CreateDispatch(L"MyOleDlg.MyDialog_Auto")) {
AfxMessageBox(L"MyOleDlg.MyDialog_Auto component not found");
return;
}
m_auto.SetTextData(COleVariant(L"test"));  // testing
m_auto.SetLongData(79);  // testing
// verify dispatch interface
// {A9515AD7-5B85-11D0-848F-00400526305B}
static const IID IID_IEx25bAuto =
{ 0xa9515ad7, 0x5b85, 0x11d0, { 0x84, 0x8f, 0x0, 0x40, 0x5, 0x26, 0x30, 0x5b } };
 
static const IID IID_IMyDialog_Auto =
{ 0x35EFA93C, 0x2419, 0x4349, { 0xBA, 0xE6, 0xCF, 0xA5, 0xE4, 0x3A, 0x26, 0x33 } };
LPDISPATCH p;
HRESULT hr = m_auto.m_lpDispatch->QueryInterface(IID_IMyDialog_Auto,
(void**) &p);
TRACE("OnDlloleLoad -- QueryInterface result = %x\n", hr);
p->Release();
}
 
 
void CMyOleClientView::OnUpdateMyoledllLoad(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_auto.m_lpDispatch==NULL);
}
 
 
void CMyOleClientView::OnMyoledllGetdata()
{
// TODO: добавьте свой код обработчика команд
m_auto.DisplayDialog();
COleVariant vaData = m_auto.GetTextData();
ASSERT(vaData.vt == VT_BSTR);
CString strTextData = vaData.bstrVal;
long lData = m_auto.GetLongData();
TRACE("CEx25dView::OnDlloleGetdata -- long = %ld, text = %S\n",
lData, strTextData);
}
 
 
void CMyOleClientView::OnUpdateMyoledllGetdata(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_auto.m_lpDispatch!=NULL);
}
 
 
void CMyOleClientView::OnMyoledllUnload()
{
// TODO: добавьте свой код обработчика команд
m_auto.ReleaseDispatch();
}
 
 
void CMyOleClientView::OnUpdateMyoledllUnload(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_auto.m_lpDispatch != NULL);
}

Добавим в класс вида закрытый член m_auto типа CMyDialog_Auto и подключите заголовочный файл #include «CMyDialog_Auto.h» в классе вида. На этом с кодом закончено, запускаем проект в режиме «Отладка» нажав клавишу F5 и тестируем наш компонент, вот что мы получили в отладчике.

mfc debug myOleDll

[warning]И снова как мы нашли progID? Он находится в файле проекта MyOleDlg в файле MyDialog_Auto.cpp, вот эти строчки

1
2
// {611C69EF-328F-494B-8E56-18D80EEDA81E}
IMPLEMENT_OLECREATE_FLAGS(CMyDialog_Auto, "MyOleDlg.MyDialog_Auto", afxRegApartmentThreading, 0x611c69ef, 0x328f, 0x494b, 0x8e, 0x56, 0x18, 0xd8, 0xe, 0xed, 0xa8, 0x1e)

имя MyOleDlg.MyDialog_Auto[/warning]

4. Внедрение приложения MyOleClock

Почитать про то как мы создавали MyOleClock вы можете тут.

Все начинается так же само из создания классов контроллеров. Так же само как и для предыдущих проектов заходим в «Окно классов», кликаем правой клавишей мышки, в появившемся контекстном меню выбираем «Добавить» -> «Класс…», в появившемся окошке «Добавление класса» выбираем «MFC класс из TypeLib» и жмем кнопку «Добавить», в появившемся окошке «Мастер добавления классов из библиотеки типов» выбираем tlb-файл внедряемого компонента, а уже из этого файла выбираем нужные контроллеры, у нас в компоненте MyOleClock будет 2 контроллера сгеренировано: «CAlarm», «CMyOleClock».

mfc add class from tlb file

жмем «Готово». У нас мастер создаст два файла

CAlarm.h »

 

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
// Автоматически создаваемые классы-оболочки IDispatch, созданные при помощи мастера добавления класса из библиотеки типов
 
#import "D:\\Visual Studio 2010\\Projects\\MyOleClock\\MyOleClock\\Debug\\MyOleClock.tlb" no_namespace
// CAlarm класс-оболочка
 
class CAlarm : public COleDispatchDriver
{
public:
CAlarm(){} // Вызывает конструктор по умолчанию для COleDispatchDriver
CAlarm(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
CAlarm(const CAlarm& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
 
// Атрибуты
public:
 
// Операции
public:
 
 
// IAlarm методы
public:
 
// IAlarm свойства
public:
DATE GetTime()
{
DATE result;
GetProperty(0x1, VT_DATE, (void*)&result);
return result;
}
void SetTime(DATE propVal)
{
SetProperty(0x1, VT_DATE, propVal);
}
 
};

CMyOleClock.h »

 

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
// Автоматически создаваемые классы-оболочки IDispatch, созданные при помощи мастера добавления класса из библиотеки типов
 
#import "D:\\Visual Studio 2010\\Projects\\MyOleClock\\MyOleClock\\Debug\\MyOleClock.tlb" no_namespace
// CMyOleClock класс-оболочка
 
class CMyOleClock : public COleDispatchDriver
{
public:
CMyOleClock(){} // Вызывает конструктор по умолчанию для COleDispatchDriver
CMyOleClock(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
CMyOleClock(const CMyOleClock& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
 
// Атрибуты
public:
 
// Операции
public:
 
 
// IMyOleClock методы
public:
void ShowWin()
{
InvokeHelper(0x2, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
LPDISPATCH CreateAlarm(DATE Time)
{
LPDISPATCH result;
static BYTE parms[] = VTS_DATE ;
InvokeHelper(0x3, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, parms, Time);
return result;
}
void RefreshWin()
{
InvokeHelper(0x4, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
VARIANT get_Figure(short n)
{
VARIANT result;
static BYTE parms[] = VTS_I2 ;
InvokeHelper(0x5, DISPATCH_PROPERTYGET, VT_VARIANT, (void*)&result, parms, n);
return result;
}
void put_Figure(short n, VARIANT& newValue)
{
static BYTE parms[] = VTS_I2 VTS_VARIANT ;
InvokeHelper(0x5, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms, n, &newValue);
}
 
// IMyOleClock свойства
public:
DATE GetTime()
{
DATE result;
GetProperty(0x1, VT_DATE, (void*)&result);
return result;
}
void SetTime(DATE propVal)
{
SetProperty(0x1, VT_DATE, propVal);
}
 
};

дальше добавляем в меню новый пункт, назовем его MyOleClock, вот какой будет у него вид

mfc menu dddd

Добавим обработчики событий к каждому пункту меню, и заполним их. Вот код заполненных обработчиков событий

Показать »

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
void CMyOleClientView::OnMyoleclockLoad()
{
// TODO: добавьте свой код обработчика команд
if(!m_clock.CreateDispatch(L"MyOleClock.Document33")) {
AfxMessageBox(L"MyOleClock.Document33.Document component not found");
return;
}
m_clock.put_Figure(0, COleVariant(L"XII"));
m_clock.put_Figure(1, COleVariant(L"III"));
m_clock.put_Figure(2, COleVariant(L"VI"));
m_clock.put_Figure(3, COleVariant(L"IX"));
OnMyoleclockRefres();//вызываем функцию меню обработчика Refresh, так как он недоступен
m_clock.ShowWin();
}
 
 
void CMyOleClientView::OnUpdateMyoleclockLoad(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_clock.m_lpDispatch == NULL);
}
 
 
void CMyOleClientView::OnMyoleclockCreatealarm()
{
// TODO: добавьте свой код обработчика команд
CAlarmDialog dlg;
int res=dlg.DoModal();
if (res == IDOK) {
TRACE("ОК\n");
COleDateTime dt(1998, 12, 23, dlg.m_nHours, dlg.m_nMinutes,
dlg.m_nSeconds);
LPDISPATCH pAlarm = m_clock.CreateAlarm(dt);
m_alarm.AttachDispatch(pAlarm);  // releases prior object!
m_clock.RefreshWin();
}
else if(res==IDCANCEL)
{
TRACE("ОТмена\n");
}
}
 
 
void CMyOleClientView::OnUpdateMyoleclockCreatealarm(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_clock.m_lpDispatch != NULL);
}
 
 
void CMyOleClientView::OnMyoleclockRefres()
{
// TODO: добавьте свой код обработчика команд
COleDateTime now = COleDateTime::GetCurrentTime();
m_clock.SetTime(now);
m_clock.RefreshWin();
}
 
 
void CMyOleClientView::OnUpdateMyoleclockRefres(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_clock.m_lpDispatch != NULL);
}
 
 
void CMyOleClientView::OnMyoleclockUnload()
{
// TODO: добавьте свой код обработчика команд
m_clock.ReleaseDispatch();
}
 
 
void CMyOleClientView::OnUpdateMyoleclockUnload(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_clock.m_lpDispatch != NULL);
}

Добавляем к классу вида две закрытые переменные:

1
2
CAlarm m_alarm;
CMyOleClock m_clock;

Подключаем в виде два заголовочных файла с контроллерами

1
2
#include "CAlarm.h"
#include "CMyOleClock.h"

Все нам осталось создать диалоговое окошко, в котором мы будем вводить данные для будильника. Заходим в «Окно ресурсов», добавляем диалог вот такой как на рисунке ниже

mfc dialog

теперь добавим к этому диалогу класс, кликнем по нему правой клавишей мышки и из контекстного меню выберем «Добавить класс…», в появившемся окошке «мастер добавления классов MFC» выставляем следующие настройки

mfc add class mfc

жмем «Готово», у нас мастер создал два файла с классом

AlarmDialog.h »

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once
 
 
// диалоговое окно CAlarmDialog
 
class CAlarmDialog : public CDialog
{
DECLARE_DYNAMIC(CAlarmDialog)
 
public:
CAlarmDialog(CWnd* pParent = NULL);   // стандартный конструктор
virtual ~CAlarmDialog();
 
// Данные диалогового окна
enum { IDD = IDD_DIALOG1 };
 
protected:
virtual void DoDataExchange(CDataExchange* pDX);    // поддержка DDX/DDV
 
DECLARE_MESSAGE_MAP()
};

AlarmDialog.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
// AlarmDialog.cpp: файл реализации
//
 
#include "stdafx.h"
#include "MyOleClient.h"
#include "AlarmDialog.h"
#include "afxdialogex.h"
 
 
// диалоговое окно CAlarmDialog
 
IMPLEMENT_DYNAMIC(CAlarmDialog, CDialog)
 
CAlarmDialog::CAlarmDialog(CWnd* pParent /*=NULL*/)
: CDialog(CAlarmDialog::IDD, pParent)
{
 
}
 
CAlarmDialog::~CAlarmDialog()
{
}
 
void CAlarmDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
 
 
BEGIN_MESSAGE_MAP(CAlarmDialog, CDialog)
END_MESSAGE_MAP()
 
 
// обработчики сообщений CAlarmDialog

Добавим к диалогу 3 переменных

1
2
3
4
public:
int m_nHours;
int m_nMinutes;
int m_nSeconds;

соответствующих элементам управления на диалоге, для этого кликнем правой клавишей мышки на диалоге, из контекстного меню выберем «Добавить переменную…», в появившемся окошке «Мастер добавления переменной-члена» выставляем

mfc add member

и так для трех элементов управления IDC_EDIT1, IDC_EDIT2, IDC_EDIT3, соответственно переменные int m_nHours, int m_nMinutes, int m_nSeconds.

Подключаем наш диалог в файле вида MyOleClientView.cpp

1
#include "AlarmDialog.h"

Все дальше компилируем приложение и тестим, у нас когда мы нажимаем Load загружается компонент и появляется окошко часов, когда жмем Create Alarm появляется диалоговое окошко в котором мы вводим данные будильника, при нажатии на Refresh у нас обновляется окошко с часами, при нажатии на Unload выгружаются компонент.

[warning]и так как получили мы progID для компонента, мы его создавали и он находится не там как для двух предыдущих примеров, а находится он в ресурсах в строковом параметре IDR_MAINFRAME

mfc stringtable

[/warning]

5. Внедрение excel в наше приложение

И так ребятки настало время попытаться внедрить в наше приложение excel. Алгоритм тот же самый как и для троих приложений выше. Мы должны создать контроллеры. Как внедряется excel я этот пример глубоко не разбирал, там есть свои нюансы и функции. В общем так же само мы должны найти библиотеку типов. У меня установлен Office14 и excel 2010. Библиотека типов у меня находится в самом exe файле, а не в tlb, просто в exe в ресурсах может хранится и tlb файл, мастер в visual studio это все извлекает из exe. Я буду описывать как я подключаю excel для своего компа, у вам это мб. будет отличатся, да и версия видимо другая может быть.

Создавать контроллеры будем для 5 классов и их мы должны добавить в качестве переменных к классу вида

Объект/класса Переменная-член класса «вид»
_Application m_app
Range m_range[5]
_Worksheet m_worksheet
Workbooks m_workbooks
Worksheets m_worksheets

Так заходим в «Окно классов», кликаем правой клавишей мышки по корню, в появившемся контекстном меню выбираем «Добавить»->»Класс…», в появившемся окошке «Добавление класса» выбираем «MFC класс из TypeLib», жмем «Добавить». В появившемся окошке «Мастер добавления классов из библиотеки типов» выставляем путь к нашей библиотеке типов, в данном случае у меня это exe файл находящийся по адресу C:\Program Files\Microsoft Office\Office14\EXCEL.EXE, выбираем нужные 5 нам интерфейсов

mfc excel interface

их как мы видим очень много, нажимаем кнопку «Готово» и у нас мастер создал 5 новых заголовочных файлов: CAplication.h, CRange.h, CWorkscheet.h, CWorkbooks.h, CWorkscheets.h. Их код я приводить не буду, потому что там очень много функций и нету смысла их приводить.

Теперь переходим к ресурсам и создаем в меню пункт для нашего компонента, назовем его Excel, вот как он выглядит

mfc menu excel

Добавим обработчики к подпунктам меню, приведу их код полностью заполненный

Показать »

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
void CMyOleClientView::OnExcelLoad()
{
// TODO: добавьте свой код обработчика команд
LPDISPATCH pDisp;
LPUNKNOWN pUnk;
CLSID clsid;
TRACE("Entering CEx25dView::OnExcelLoad\n");
BeginWaitCursor();
::CLSIDFromProgID(L"Excel.Application.14", &clsid); // from registry
if(::GetActiveObject(clsid, NULL, &pUnk) == S_OK) {
VERIFY(pUnk->QueryInterface(IID_IDispatch,
(void**) &pDisp) == S_OK);
m_app.AttachDispatch(pDisp);
pUnk->Release();
TRACE(" attach complete\n");
}
else {
if(!m_app.CreateDispatch(L"Excel.Application.14")) {
AfxMessageBox(L"Excel 14 program not found");
}
TRACE(" create complete\n");
}
EndWaitCursor();
}
 
 
void CMyOleClientView::OnUpdateExcelLoad(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_app.m_lpDispatch == NULL);
}
 
 
void CMyOleClientView::OnExcelExecut()
{
// TODO: добавьте свой код обработчика команд
LPDISPATCH pRange, pWorkbooks;
    
   CWnd* pWnd = CWnd::FindWindow(L"XLMAIN", NULL);
   if (pWnd != NULL) {
     TRACE("Excel window found\n");
     pWnd->ShowWindow(SW_SHOWNORMAL);
     pWnd->UpdateWindow();
     pWnd->BringWindowToTop();
   }
 
   m_app.put_SheetsInNewWorkbook(1);
  
  
   VERIFY(pWorkbooks = m_app.get_Workbooks());
   m_workbooks.AttachDispatch(pWorkbooks);
   //m_workbooks.get_Count();
   LPDISPATCH pWorkbook = NULL;
   if (m_workbooks.get_Count() == 0) {
      // Add returns a Workbook pointer, but we
      //  don't have a Workbook class
      pWorkbook = m_workbooks.Add(); // Save the pointer for
                                     //  later release
   }
   LPDISPATCH pWorksheets = m_app.get_Worksheets();
   ASSERT(pWorksheets != NULL);
   m_worksheets.AttachDispatch(pWorksheets);
   LPDISPATCH pWorksheet = m_worksheets.get_Item(COleVariant((short) 1));
 
   m_worksheet.AttachDispatch(pWorksheet);
   m_worksheet.Select();
 
   VERIFY(pRange = m_worksheet.get_Range(COleVariant(L"A1")));
   m_range[0].AttachDispatch(pRange);
   m_worksheet.get_Range(COleVariant(L"A2"));
   VERIFY(pRange = m_worksheet.get_Range(COleVariant(L"A2")));
   m_range[1].AttachDispatch(pRange);
  
   VERIFY(pRange = m_worksheet.get_Range(COleVariant(L"A3")));
   m_range[2].AttachDispatch(pRange);
 
   VERIFY(pRange = m_worksheet.get_Range(COleVariant(L"A3"),
   COleVariant(L"C5")));
   m_range[3].AttachDispatch(pRange);
 
   VERIFY(pRange = m_worksheet.get_Range(COleVariant(L"A6")));
   m_range[4].AttachDispatch(pRange);
  // m_range[4].put_Value2(COleVariant(COleDateTime(1998, 4, 24, 15, 47, 8)));
   m_range[4].put_Value2(COleVariant(COleDateTime(1998, 4, 24, 15, 47, 8)));
   // retrieve the stored date and print it as a string
   COleVariant vaTimeDate = m_range[4].get_Value2();
   TRACE("returned date type = %d\n", vaTimeDate.vt);
   COleVariant vaTemp;
   vaTemp.ChangeType(VT_BSTR, &vaTimeDate);
   CString str = vaTemp.bstrVal;
   TRACE("date = %S\n",  str);
 
   m_range[0].put_Value2(COleVariant(L"test string"));
  
   COleVariant vaResult0 = m_range[0].get_Value2();
   if (vaResult0.vt == VT_BSTR) {
     CString str = vaResult0.bstrVal;
     TRACE("vaResult0 = %S\n", str);
   }
 
   m_range[1].put_Value2(COleVariant(3.14159));
  
   COleVariant vaResult1 = m_range[1].get_Value2();
   if (vaResult1.vt == VT_R8) {
     TRACE("vaResult1 = %f\n", vaResult1.dblVal);
   }
  
   m_range[2].put_Formula(COleVariant(L"=$A2*2.0"));
  
   COleVariant vaResult2 = m_range[2].get_Value2();
   if (vaResult2.vt == VT_R8) {
     TRACE("vaResult2 = %f\n", vaResult2.dblVal);
   }
  
   COleVariant vaResult2a = m_range[2].get_Formula();
   if (vaResult2a.vt == VT_BSTR) {
     CString str = vaResult2a.bstrVal;
     TRACE("vaResult2a = %S\n", str);
   }
  
   m_range[3].FillRight();
   m_range[3].FillDown();
  
// cleanup  
    if (pWorkbook != NULL) {
    pWorkbook->Release();
   }
 
}
 
 
void CMyOleClientView::OnUpdateExcelExecut(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
pCmdUI->Enable(m_app.m_lpDispatch != NULL);
}

Добавим в класс вида 5 закрытых переменных членов

1
2
3
4
5
6
private:
CApplication m_app;
CRange    m_range[5];
CWorksheet   m_worksheet;
CWorkbooks   m_workbooks;
CWorksheets   m_worksheets;

и подключим 5 заголовочных файлов в виде

1
2
3
4
5
#include "CApplication.h"
#include "CRange.h"
#include "CWorksheet.h"
#include "CWorkbooks.h"
#include "CWorksheets.h"

Все на этом. Если мы нажмем F5 и запустим щас программу у нас появится очень много ошибок, первая ошибка:

1>d:\visual studio 2010\projects\myoleclient\myoleclient\debug\excel.tlh(1595): error C2371: FontPtr: переопределение; различные базовые типы
1> c:\program files\microsoft visual studio 10.0\vc\include\comdef.h(314): см. объявление «FontPtr»

вылазит потому что у нас два раза определена структура и класс, в общем нам нужно в заголовочных файлах CAplication.h, Range.h, CWorkscheet.h, CWorkbooks.h, CWorkscheets.h закомментировать строчку в самом начале файла:

1
#import "C:\\Program Files\\Microsoft Office\\Office14\\EXCEL.EXE" no_namespace

Закомментируем ее для всех 5 контроллеров excel.

Нажимаем F5 и снова  4 ошибки:

1>d:\visual studio 2010\projects\myoleclient\myoleclient\crange.h(335): error C2059: синтаксическая ошибка: ,
1>d:\visual studio 2010\projects\myoleclient\myoleclient\myoleclientview.cpp(404): error C2660: CWorkbooks::Add: функция не принимает 0 аргументов
1>d:\visual studio 2010\projects\myoleclient\myoleclient\myoleclientview.cpp(413): error C2660: CWorksheet::Select: функция не принимает 0 аргументов
1>d:\visual studio 2010\projects\myoleclient\myoleclient\myoleclientview.cpp(415): error C2660: CWorksheet::get_Range: функция не принимает 1 аргументов

первая ошибка в crange.h в 335 строке, там находится определение функции

1
2
3
4
5
6
VARIANT DialogBox()
{
VARIANT result;
InvokeHelper(0xf5, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL);
return result;
}

тут получилось так что макрос MFC совпал с названием функции, чтобы этой ошибки не было, переименуем эту функцию допустим в DialogBox1. Нажимаем F5 и этой ошибки уже нету синтаксической. Но остается ошибка:

d:\visual studio 2010\projects\myoleclient\myoleclient\myoleclientview.cpp(404): error C2660: CWorkbooks::Add: функция не принимает 0 аргументов

это означает что у нас нету такой функции, посмотрим 404 строчку

1
pWorkbook = m_workbooks.Add(); // Save the pointer for

идем в класс СWorkbook и смотрим определение функции Add()

1
2
3
4
5
6
7
LPDISPATCH Add(VARIANT& Template)
{
LPDISPATCH result;
static BYTE parms[] = VTS_VARIANT ;
InvokeHelper(0xb5, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, parms, &Template);
return result;
}

как видим она принимает 1 аргумент. Мы просто в этот класс добавим функцию Add которая не будет принимать аргументов, вот ее определение:

1
2
3
4
5
6
LPDISPATCH Add() // added
{
LPDISPATCH result;
InvokeHelper(0xb5, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, NULL);
return result;
}

просто добавьте это определение в класс CWorkboks. Нажимаем F5 у нас уже этой ошибки нету, но осталось 2 ошибки:

1>d:\visual studio 2010\projects\myoleclient\myoleclient\myoleclientview.cpp(413): error C2660: CWorksheet::Select: функция не принимает 0 аргументов
1>d:\visual studio 2010\projects\myoleclient\myoleclient\myoleclientview.cpp(415): error C2660: CWorksheet::get_Range: функция не принимает 1 аргументов

они связаны с тем что в классе CWorksheet нету функций Select без аргументов и get_Range принимает 1 аргумент, добавим их в этот класс, вот их определение

1
2
3
4
5
6
7
8
9
10
11
12
13
void Select() // added
{
InvokeHelper(0xeb, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
LPDISPATCH get_Range(const VARIANT& Cell1) // added
{
LPDISPATCH result;
static BYTE parms[] =
VTS_VARIANT;
InvokeHelper(0xc5, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result,
parms,&Cell1);
return result;
}

[tip]Так как я не сильно шарю excel и эти интерфейсы то я просто сделал чтобы программа работала. тут смысл в том что мы можем свои функции добавлять, там есть функция например get_Range без параметра, а мы из нее делаем функция без параметра или там функция с двумя параметрами, а мы делаем с одним, там можно если знать excel и что делают функции, то добавлять в эти интерфейсы свои функции. [/tip]

Снова нажимаем F5 и у нас на этот раз запустилось наше приложение. Нажимаем Load, затем Execut, у нас запустилось окошко excel и нарисовалась от такая таблица

excel

на этом пожалуй все, мы подключили excel. Да еще поговорим о некоторых деталях, например о том как мы определили progID для excel, это пример из книги там был progID написан excel.Application8, по идее этот progID трудно определить, это походу делается методом тыка. заходим в реестр набрав в меню «Пуск» -> «Выполнить…» команду «regedit» и у нас запускается редактор реестра. Там заходим в раздел HKEY_CLASSES_ROOT и ищем что то что похоже на excel. Там в подразделе CLSID находятся все GUID установленных программ, и сами названия папок являются в большинстве своем progID, там очень много progID для excel, так как в книге я увидел что там находится excel.Applicatio.8, то у меня похоже это будет excel.Applicatio.14

excel regedit

 

Это такое дело неясное. Так же есть код неясный от он

1
2
3
4
5
6
7
CWnd* pWnd = CWnd::FindWindow("XLMAIN", NULL);
   if (pWnd != NULL) {
     TRACE("Excel window found\n");
     pWnd->ShowWindow(SW_SHOWNORMAL);
     pWnd->UpdateWindow();
     pWnd->BringWindowToTop();
   }

строка «XLMAIN» это класс окна excel, от здесь я разобрался, чтобы его получить — узнать его имя мы запускаем приложение Spy++, запускаем окошко excel и смотрим данные окна

microsoft spy++

так же можно посмотреть его свойства кликнув правой клавишей мышки на строке и из контекстного меню выбрав «Свойства…»

spy++ properties

На этом пожалуй все, у нас получилось создать многомодульное приложение MFC SDI с использованием технологии OLE Автоматизации. Приложение клиент.

[youtube]https://www.youtube.com/watch?v=jKrnTFV8kFk[/youtube]

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

Ваш адрес 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 Двоичное дерево Задачи С++ Игры С++ Исключения С++ О-большое Операторы_С++ Перегрузка операторов С++ Поиск С++ Потоки Проектирование_С++ С++ Типы_С++ Типы С++ Шаблоны С++ библиотеки локализация макросы С++ сортировка С++

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

  • RA3PKJ к записи visual C++, создание диалоговых окон.
  • JasonReant к записи Создание и использование статических библиотек .lib в visual studio.
  • MyWin2020 к записи Программка для заполнения форума на vBulletin 3.8.7
  • ScottJip к записи Создание и использование статических библиотек .lib в visual studio.
  • ArnoldKig к записи Создание и использование статических библиотек .lib в visual studio.
©2021 Kselax.ru Theme by ThemeGiant