Здорова!
Сегодня разберем пример OLE в котором мы создадим COM объект с применением технологии OLE автоматизации. Пример будет банковская программа. Будем создавать в Visual Studio 10, запускаем ее и создаем самое простое приложение на MFC на основе диалоговых окон. Приложение назовем «OLE_EXE».
на следующем шаге удаляем все галочки
обязательно ставим галочку «Автоматизация»
и жмем кнопку готово, в обозревателе решений мы увидим созданные файлы
Удалим следующие файлы: OLE_EXEDlg.h, OLE_EXEDlg.cpp, DlgProxy.h, DlgProxy.cpp, так же удалим из ресурсов диалог IDD_OLE_EXE_DIALOG.
В файле OLE_EXE.cpp удалим строчки #include «OLE_EXEDlg.h» и #include «OLE_EXEDlg.h»
в файле OLE_EXE.cpp заменим содержимое функции IninInstance
1 2 3 4 5 6 7 8 9 10 11 12 |
TRACE("Cex25a1App::InitInstance\n"); AfxOleInit(); if(RunEmbedded()||RunAutomated()) { //компонент запущен COM COleTemplateServer::RegisterAll(); return TRUE; } //Компонент запущен непосредственно пользователем COleObjectFactory::UpdateRegistryAll(); AfxMessageBox(L"Банковский сервер зарегистрирован"); return FALSE; |
Используя class Wizard добавим класс CBank к нашему проекту. Обязательно поставьте галочку «создать по идентификатору типа», у вас создастся идентификатор класса по которому ваш компонент будет находится в реестре GUID.
Жмем «Готово», у вас создастся два файла
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#pragma once // конечный объект команды CBank class CBank : public CCmdTarget { DECLARE_DYNCREATE(CBank) public: CBank(); virtual ~CBank(); virtual void OnFinalRelease(); protected: DECLARE_MESSAGE_MAP() DECLARE_OLECREATE(CBank) DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP() }; |
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 |
// Bank.cpp: файл реализации // #include "stdafx.h" #include "OLE_EXE.h" #include "Bank.h" // CBank IMPLEMENT_DYNCREATE(CBank, CCmdTarget) CBank::CBank() { EnableAutomation(); // Чтобы обеспечить работу приложения в течение всего периода активности объекта автоматизации OLE, // конструктор вызывает AfxOleLockApp. AfxOleLockApp(); } CBank::~CBank() { // Чтобы прервать работу приложения, когда все объекты созданы // при помощи OLE-автоматизации, деструктор вызывает AfxOleUnlockApp. AfxOleUnlockApp(); } void CBank::OnFinalRelease() { // Когда будет освобождена последняя ссылка на объект автоматизации, // вызывается OnFinalRelease. Базовый класс автоматически // удалит объект. Перед вызовом базового класса добавьте // дополнительную очистку, необходимую вашему объекту. CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CBank, CCmdTarget) END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CBank, CCmdTarget) END_DISPATCH_MAP() // Примечание: мы добавили поддержку для IID_IBank, чтобы обеспечить безопасную с точки зрения типов привязку // из VBA. Этот IID должен соответствовать GUID, связанному с // disp-интерфейсом в файле .IDL. // {AA6D9C56-813D-45FF-99FA-E3E1B5B85DEB} static const IID IID_IBank = { 0xAA6D9C56, 0x813D, 0x45FF, { 0x99, 0xFA, 0xE3, 0xE1, 0xB5, 0xB8, 0x5D, 0xEB } }; BEGIN_INTERFACE_MAP(CBank, CCmdTarget) INTERFACE_PART(CBank, IID_IBank, Dispatch) END_INTERFACE_MAP() // {91ED4E19-C337-463C-B93E-FF83FFB14FA2} IMPLEMENT_OLECREATE_FLAGS(CBank, "OLE_EXE.Bank", afxRegApartmentThreading, 0x91ed4e19, 0xc337, 0x463c, 0xb9, 0x3e, 0xff, 0x83, 0xff, 0xb1, 0x4f, 0xa2) // обработчики сообщений CBank |
Как видим создалось два идентификатора GUID, один для интерфейса IID_IBank, а второй GUID этот тот GUID который регистрирует модуль в реестре windows.
В «окне классов» у нас появился подраздел новый где находится интерфейс IBank
Кликаем правой клавишей на IBank, выбираем «добавить»=>»Добавить метод…» и мы попадаем в окошко добавления методов
жмем «Далее» в появившемся окошке ничего не меняем и жмем «Готово» и у нас добавился в файле Bank.cpp в карту диспетчеризации новый метод, так же создалась сам метод в классе CBank заполнился также файл OLE_EXE.idl — это файл в котором на языке IDL записан OLE интерфейс.
Таким же способом добавим еще один метод Deposit возвращающий значение типа void и принимающий в качестве параметра тип DOUBLE
Добавим еще свойство Balance
теперь добавим к самому классу CBank переменную член m_dBalance типа double, у нас предыдущий мастер не создал переменную потому что мы выбрали параметр «get/set Methods». Поэтому мы ее создаем через обычный мастер добавления свойств к классу.
заполним сгенерированые функции кодом, я полностью приведу файл Bank.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 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 |
// Bank.cpp: файл реализации // #include "stdafx.h" #include "OLE_EXE.h" #include "Bank.h" // CBank IMPLEMENT_DYNCREATE(CBank, CCmdTarget) CBank::CBank() : m_dBalance(0) { EnableAutomation(); // Чтобы обеспечить работу приложения в течение всего периода активности объекта автоматизации OLE, // конструктор вызывает AfxOleLockApp. AfxOleLockApp(); } CBank::~CBank() { // Чтобы прервать работу приложения, когда все объекты созданы // при помощи OLE-автоматизации, деструктор вызывает AfxOleUnlockApp. AfxOleUnlockApp(); } void CBank::OnFinalRelease() { // Когда будет освобождена последняя ссылка на объект автоматизации, // вызывается OnFinalRelease. Базовый класс автоматически // удалит объект. Перед вызовом базового класса добавьте // дополнительную очистку, необходимую вашему объекту. CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CBank, CCmdTarget) END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CBank, CCmdTarget) DISP_FUNCTION_ID(CBank, "Withdrawal", dispidWithdrawal, Withdrawal, VT_R8, VTS_R8) DISP_FUNCTION_ID(CBank, "Deposit", dispidDeposit, Deposit, VT_EMPTY, VTS_R8) DISP_PROPERTY_EX_ID(CBank, "Balance", dispidBalance, GetBalance, SetBalance, VT_R8) END_DISPATCH_MAP() // Примечание: мы добавили поддержку для IID_IBank, чтобы обеспечить безопасную с точки зрения типов привязку // из VBA. Этот IID должен соответствовать GUID, связанному с // disp-интерфейсом в файле .IDL. // {AA6D9C56-813D-45FF-99FA-E3E1B5B85DEB} static const IID IID_IBank = { 0xAA6D9C56, 0x813D, 0x45FF, { 0x99, 0xFA, 0xE3, 0xE1, 0xB5, 0xB8, 0x5D, 0xEB } }; BEGIN_INTERFACE_MAP(CBank, CCmdTarget) INTERFACE_PART(CBank, IID_IBank, Dispatch) END_INTERFACE_MAP() // {91ED4E19-C337-463C-B93E-FF83FFB14FA2} IMPLEMENT_OLECREATE_FLAGS(CBank, "OLE_EXE.Bank", afxRegApartmentThreading, 0x91ed4e19, 0xc337, 0x463c, 0xb9, 0x3e, 0xff, 0x83, 0xff, 0xb1, 0x4f, 0xa2) // обработчики сообщений CBank DOUBLE CBank::Withdrawal(DOUBLE dAmount) { AFX_MANAGE_STATE(AfxGetAppModuleState()); // TODO: добавьте код обработчика отправки TRACE("CBank::Withdrawl dAmount=%f, m_dBalance=%f ",dAmount,m_dBalance); if(dAmount<0.0) { return 0.0; } if(dAmount<=m_dBalance) { m_dBalance-=dAmount; return m_dBalance; } //если больше возвращаем то что есть на счету double dTemp=m_dBalance; m_dBalance=0.0; return dTemp; } void CBank::Deposit(DOUBLE dAmount) { AFX_MANAGE_STATE(AfxGetAppModuleState()); if(dAmount<0.0) { return; } m_dBalance+=dAmount; } DOUBLE CBank::GetBalance(void) { AFX_MANAGE_STATE(AfxGetAppModuleState()); return m_dBalance; } void CBank::SetBalance(DOUBLE newVal) { AFX_MANAGE_STATE(AfxGetAppModuleState()); TRACE("К сожалению, это невозможно!\n"); } |
Собираем программу и запускаем один раз чтобы зарегистрировать.
Дальше подготавливаем 4 макроса 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 |
Dim Bank As Object Sub LoadBank() Set Bank = CreateObject("OLE_EXE.Bank") End Sub Sub UnloadBank() Set Bank = Nothing End Sub Sub DoDeposit() Range("D4").Select Bank.Deposit (ActiveCell.Value) End Sub Sub DoWithdrawal() Range("E4").Select Dim amt amt = Bank.Withdrawal(ActiveCell.Value) Range("E5").Select ActiveCell.Value = amt End Sub Sub DoInquiry() Dim amt amt = Bank.Balance() Range("G4").Select ActiveCell.Value = amt End Sub |
Запускаем excel, создаем книгу новую, добавляем 5 кнопки и добавляем макросы excel к книге. Каждой кнопке присваиваем свой макрос. Как добавить макрос и кнопку к excel читайте тут. Вот скрин приложения excel:
Дальше нажимаем кнопку «Load Bank Program» у нас загружается модуль, затем нажимаем «Deposit» и вводим сумму которую хотим получить на счет, например мы ввели 500 и нажали 3 раза на «Deposit» у нас положится на счет 1500. Проверить сколько на счету нажмите кнопку «Balance Inqury». Чтобы снять нажмите «Withdrawal» и оно будет снимать введенную сумму.
Отладка OLE объекта или COM объекта.
И так ребятки рассмотрим как можно отладить наш объект. Для этого заходим в visual studio 2010 в «свойства проекта» и на вкладке отладка выставляем следующие настройки:
Нажимаем кнопку отладка или F5 и у нас VS запускается в режиме ожидания, дальше мы заходим в excel, подгружаем наш модуль и в отладчике смотрим что происходит, отладчик должен реагировать на действия. На этом в принципе все.
[youtube]https://www.youtube.com/watch?v=zPWlSsDUIQw[/youtube]