Форум программистов, компьютерный форум, киберфорум
C++: COM, OLE, ActiveX
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
652 / 211 / 21
Регистрация: 20.05.2016
Сообщений: 879
Записей в блоге: 15
1

Отследить события Excel C++

01.08.2020, 11:08. Просмотров 1434. Ответов 7
Метки нет (Все метки)

Мое почтение, джентльмены.
Стоит задача отследить события: открытия нового файла, сохранения файла (до/после) в Excel.
Пока в этом не спец. Собрал код из разных источников сети.
В Word отрабатывает, в Excel вызываются TranslateMessage(&msg); DispatchMessage(&msg); и тишина.
Вопрос, что делаю неправильно, а возможно так - что правильно или все в топку?
Возможно ли узнать какая книга генерирует нужное событие?
Пишу на C ++ без MFC, ATL, #import (желателен этот путь, но и другие можно рассмотреть)

Кликните здесь для просмотра всего текста
C++
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include "pch.h"
#include <windows.h>
#include <stdio.h>
#include "OCIdl.h"
 
 
#ifndef _OFFICEEVENTHANDLER_H_
#define _OFFICEEVENTHANDLER_H_
 
// 000209FE-0000-0000-C000-000000000046
//static const GUID IID_IApplicationEvents2 ={ 0x000209FE,0x0000,0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; //word
static const GUID IID_IApplicationEvents2 ={ 0x00024413,0x000,0x0000,{0xc0,0x00,0x0,0x00,0x00,0x00,0x00,0x46 } }; //excel
 
struct IApplicationEvents2 : public IDispatch // Pretty much copied from typelib
{
    /*
     * IDispatch methods
     */
    STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj) = 0;
    STDMETHODIMP_(ULONG) AddRef() = 0;
    STDMETHODIMP_(ULONG) Release() = 0;
    STDMETHODIMP GetTypeInfoCount(UINT *iTInfo) = 0;
    STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) = 0;
    STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames,    UINT cNames, LCID lcid, DISPID *rgDispId) = 0;
    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,    WORD wFlags, DISPPARAMS* pDispParams,   VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) = 0;
 
    /*
     * IApplicationEvents2 methods
     */
    //STDMETHODIMP Startup();
    //STDMETHODIMP Quit();
    //STDMETHODIMP DocumentChange();
};
 
 
class COfficeEventHandler : IApplicationEvents2
{
 
public:
    DWORD m_dwEventCookie;
 
    COfficeEventHandler
    (
    ) :
        m_cRef(1),
        m_dwEventCookie(0)
    {
    }
 
    STDMETHOD_(ULONG, AddRef)()
    {
        InterlockedIncrement(&m_cRef);
 
        return m_cRef;
    }
 
    STDMETHOD_(ULONG, Release)()
    {
        InterlockedDecrement(&m_cRef);
 
        if (m_cRef == 0)
        {
            delete this;
            return 0;
        }
 
        return m_cRef;
    }
 
    STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj)
    {
        if (riid == IID_IUnknown) {
            *ppvObj = static_cast<IApplicationEvents2*>(this);
        }
 
        else if (riid == IID_IApplicationEvents2) {
            *ppvObj = static_cast<IApplicationEvents2*>(this);
        }
        else if (riid == IID_IDispatch) {
            *ppvObj = static_cast<IApplicationEvents2*>(this);
        }
 
        else
        {
            char clsidStr[256];
            WCHAR wClsidStr[256];
            char txt[512];
 
            StringFromGUID2(riid, (LPOLESTR)&wClsidStr, 256);
 
            // Convert down to ANSI
            WideCharToMultiByte(CP_ACP, 0, wClsidStr, -1, clsidStr, 256, NULL, NULL);
 
            sprintf_s(txt, 512, "riid is : %s: Unsupported Interface", clsidStr);
 
            *ppvObj = NULL;
            return E_NOINTERFACE;
        }
 
        static_cast<IUnknown*>(*ppvObj)->AddRef();
 
        return S_OK;
    }
 
    STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
        LCID lcid, DISPID* rgdispid)
    {
        return E_NOTIMPL;
    }
 
    STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,   EXCEPINFO* pexcepinfo, UINT* puArgErr);
    //{
    //  return E_NOTIMPL;
    //}
 
    // IApplicationEvents2 methods
    void Startup();
    void Quit();
    void DocumentChange();
 
 
protected:
    LONG                        m_cRef;
};
 
#endif // _OFFICEEVENTHANDLER_H_
// IApplicationEvents2 methods
void COfficeEventHandler::Startup()
{
    printf("In Startup\n");
}
 
void COfficeEventHandler::Quit()
{
    printf("In Quit\n");
}
 
void COfficeEventHandler::DocumentChange()
{
    printf("In DocumentChnage\n");
}
 
STDMETHODIMP COfficeEventHandler::Invoke(DISPID dispIdMember, REFIID riid,  LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,   EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
    //Validate arguments
    if ((riid != IID_NULL))
        return E_INVALIDARG;
 
    HRESULT hr = S_OK;  // Initialize
 
    /* To see what Word sends as dispid values */
    static char myBuf[80];
    memset(&myBuf, '\0', 80);
    sprintf_s((char*)&myBuf, 80, " Dispid: %d :", dispIdMember);
 
    switch (dispIdMember) {
    case 0x01:    // Startup
        Startup();
        break;
    case 0x02:    // Quit
        Quit();
        break;
    case 0x03:    // DocumentChange
        DocumentChange();
        break;
    }
 
    return S_OK;
}
 
int main()
{
    CLSID clsid;                   // CLSID of automation object 
    HRESULT hr;
    LPUNKNOWN punk = NULL;         // IUnknown of automation object 
    LPDISPATCH pdisp = NULL;       // IDispatch of automation object 
    IConnectionPointContainer *pConnPntCont;
    IConnectionPoint *pConnPoint;
    IUnknown *iu;
    IID id;
    COfficeEventHandler *officeEventHandler = new COfficeEventHandler;
 
    CoInitialize(NULL);
 
    //hr = CLSIDFromProgID(OLESTR("Word.Application"), &clsid);
    hr = CLSIDFromProgID(L"Excel.Application", &clsid);
    
    hr = GetActiveObject( clsid, NULL, &punk );
     
    //hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IUnknown, (void FAR* FAR*)&punk);
 
    hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont);
 
    // IID for ApplicationEvents2 
    //hr = IIDFromString(L"{000209FE-0000-0000-C000-000000000046}", &id);
    hr = IIDFromString(L"{00024413-0000-0000-C000-000000000046}", &id);
 
    hr = pConnPntCont->FindConnectionPoint(id, &pConnPoint);
 
    hr = officeEventHandler->QueryInterface(IID_IUnknown, (void FAR* FAR*)&iu);
 
    hr = pConnPoint->Advise(iu, &officeEventHandler->m_dwEventCookie);
 
    MSG   msg;
    BOOL  bRet;
 
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
 
        if (msg.message == WM_QUERYENDSESSION || msg.message == WM_QUIT || msg.message == WM_DESTROY)
        {
            break;
        }
    }
 
    hr = pConnPoint->Unadvise(officeEventHandler->m_dwEventCookie);
    if (punk) punk->Release();
    if (pdisp) pdisp->Release();
 
    CoUninitialize();
 
    return hr;
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.08.2020, 11:08
Ответы с готовыми решениями:

Возможно ли отследить выполнение события от компонента билдера ?
Такой вопрос: можно ли отследить выполнение события от компонента билдера ? Вот такого вида:...

Не удается отследить события на textfield
Добрый день! Есть задача, при нажатии на текстовое поле типа &quot;input&quot;, вывести на экран три...

Как отследить события на USB?
Здравствуйте. Есть подозрение, что какой-то драйвер или программа перехватывает USB порты на...

Отследить наступление события разворачивания подтаблицы
Здравствуйте! Подскажите пожалуйста как можно отследить, что пользователь нажал на &quot;+&quot; для...

7
5855 / 3984 / 1635
Регистрация: 07.05.2019
Сообщений: 12,374
Записей в блоге: 1
01.08.2020, 12:40 2
Цитата Сообщение от bedvit Посмотреть сообщение
Пишу на C ++ без MFC, ATL, #import (желателен этот путь, но и другие можно рассмотреть)
#import лучше использовать, чтоб не брать неизвестно откуда интерфейсы и guidы.
И проверяй, что возвращают функции, SUCCEDED(hr)/FAILED(hr)
0
652 / 211 / 21
Регистрация: 20.05.2016
Сообщений: 879
Записей в блоге: 15
01.08.2020, 18:03  [ТС] 3
Здесь пишут, что бывают проблемы со счетчиком ссылок в #import.
Что посоветуете по отслеживанию события сохранения в Excel?
0
5855 / 3984 / 1635
Регистрация: 07.05.2019
Сообщений: 12,374
Записей в блоге: 1
01.08.2020, 18:07 4
Цитата Сообщение от bedvit Посмотреть сообщение
Здесь пишут, что бывают проблемы со счетчиком ссылок в #import.
Причём здесь счётчик ссылок? Импорт просто создаст просто создаст заголовки с интерфейсами, guid-ами и прочим.
0
652 / 211 / 21
Регистрация: 20.05.2016
Сообщений: 879
Записей в блоге: 15
01.08.2020, 19:27  [ТС] 5
oleg-m1973, пока не понял вашу мысль. Не могли бы вы привести неболшой пример и пояснить, как это использовать в контексте моей проблемы?
0
652 / 211 / 21
Регистрация: 20.05.2016
Сообщений: 879
Записей в блоге: 15
18.08.2020, 12:04  [ТС] 7
Без обработок ошибок, как-то так:
C++
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
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "pch.h"
#include <iostream>
#include "OCIdl.h"
 
static const GUID IID_IApplicationEvents2 = { 0x00024413,0x000,0x0000,{0xc0,0x00,0x0,0x00,0x00,0x00,0x00,0x46 } }; 
 
struct IApplicationEvents2 : public IDispatch
{
    STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj) = 0;
    STDMETHODIMP_(ULONG) AddRef() = 0;
    STDMETHODIMP_(ULONG) Release() = 0;
    STDMETHODIMP GetTypeInfoCount(UINT *iTInfo) = 0;
    STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) = 0;
    STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames,    UINT cNames, LCID lcid, DISPID *rgDispId) = 0;
    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,    WORD wFlags, DISPPARAMS* pDispParams,   VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) = 0;
};
 
 
class COfficeEventHandler : IApplicationEvents2
{
 
public:
    DWORD m_dwEventCookie;
 
    COfficeEventHandler
    (
    ) :
        m_cRef(1),
        m_dwEventCookie(0)
    {
    }
 
    STDMETHOD_(ULONG, AddRef)()
    {
        InterlockedIncrement(&m_cRef);
        return m_cRef;
    }
 
    STDMETHOD_(ULONG, Release)()
    {
        InterlockedDecrement(&m_cRef);
        if (m_cRef == 0)
        {
            delete this;
            return 0;
        }
        return m_cRef;
    }
 
    STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj)
    {
        if (riid == IID_IUnknown) { *ppvObj = static_cast<IApplicationEvents2*>(this);  }
 
        else if (riid == IID_IApplicationEvents2) { *ppvObj = static_cast<IApplicationEvents2*>(this);  }
        else if (riid == IID_IDispatch) {   *ppvObj = static_cast<IApplicationEvents2*>(this);  }
        else    {
            char clsidStr[256];
            WCHAR wClsidStr[256];
            char txt[512];
            StringFromGUID2(riid, (LPOLESTR)&wClsidStr, 256);
            WideCharToMultiByte(CP_ACP, 0, wClsidStr, -1, clsidStr, 256, NULL, NULL);   // Convert down to ANSI
            sprintf_s(txt, 512, "riid is : %s: Unsupported Interface", clsidStr);
            *ppvObj = NULL;
            return E_NOINTERFACE;
        }
 
        static_cast<IUnknown*>(*ppvObj)->AddRef();
        return S_OK;
    }
 
    STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) { return E_NOTIMPL; }
    STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return E_NOTIMPL; }
    STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return E_NOTIMPL; }
    STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr);
 
protected:
    LONG m_cRef;
};
 
STDMETHODIMP COfficeEventHandler::Invoke(DISPID dispIdMember, REFIID riid,  LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,   EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
    if ((riid != IID_NULL)) { return E_INVALIDARG; }
 
    HRESULT hr = S_OK;  // Initialize
    static char myBuf[80];
    memset(&myBuf, '\0', 80);
    sprintf_s((char*)&myBuf, 80, " Dispid: %d :", dispIdMember);
 
 
    switch (dispIdMember) {
    case 1571:    // Workbook_BeforeSave
        printf("Workbook_BeforeSave\n"); break;
    case 2911:    // Workbook_AfterSave
        printf("Workbook_AfterSave\n"); //ReferenceBedvitCOMAddRemove(1);
        break;
    case 1565:    // Workbook_New
        printf("Workbook_New\n"); //ReferenceBedvitCOMAddRemove(0);
        break;
    case 1567:    // Workbook_Open
        printf("Workbook_Open\n"); //ReferenceBedvitCOMAddRemove(0);
        break;
    case 1558:    // Workbook_Open
        printf("Cell_Select\n"); //ReferenceBedvitCOMAddRemove(0);
        break;
    default:
        std::wcout << L"Event: "<< dispIdMember << L"\n";
        break;
    }
    return S_OK;
}
 
int main()
{
 
    CLSID clsid;   
    HRESULT hr;
    LPUNKNOWN punk = NULL; 
    LPDISPATCH pdisp = NULL; 
    IConnectionPointContainer *pConnPntCont;
    IConnectionPoint *pConnPoint;
    IDispatch *pXlApp;
    IID id;
    COfficeEventHandler *officeEventHandler = new COfficeEventHandler;
 
    CoInitialize(NULL);
    hr = CLSIDFromProgID(L"Excel.Application", &clsid);
    hr = GetActiveObject(clsid, NULL, (IUnknown**)&punk);
    hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont);
    hr = IIDFromString(L"{00024413-0000-0000-C000-000000000046}", &id);
    hr = officeEventHandler->QueryInterface(IID_IDispatch, (void **)&pXlApp);
    {
        VARIANT x;
        x.vt = VT_I4;
        x.lVal = 1;
        AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, (OLECHAR*)L"Visible", 1, x);
    }
 
    hr = pConnPntCont->FindConnectionPoint(id, &pConnPoint);
    hr = pConnPoint->Advise(pXlApp, &officeEventHandler->m_dwEventCookie);
 
    MSG   msg;
    int  bRet;
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        auto x = 0;
        if (bRet == -1) { 
            break; }// handle the error and possibly exit
        if (TranslateMessage(&msg) == 0) { DispatchMessage(&msg); }
 
        if (msg.message == WM_QUERYENDSESSION || msg.message == WM_QUIT || msg.message == WM_DESTROY)   {
            break;
        }
    }
 
    hr = pConnPoint->Unadvise(officeEventHandler->m_dwEventCookie);
    if (punk) punk->Release();
    if (pdisp) pdisp->Release();
    if (pXlApp) pXlApp->Release();
    if (pConnPntCont) pConnPntCont->Release();
    CoUninitialize();
    delete officeEventHandler;
 
    return hr;
}
Не срабатывает условие
C++
1
2
3
        if (msg.message == WM_QUERYENDSESSION || msg.message == WM_QUIT || msg.message == WM_DESTROY)   {
            break;
        }
, что не позволяет выполнится коду после while (подчистить за собой)
0
652 / 211 / 21
Регистрация: 20.05.2016
Сообщений: 879
Записей в блоге: 15
20.08.2020, 17:41  [ТС] 8
Вообщем с exe более-менее разобрался.
Далее, реализовал данный алгоритм в dll, который подгружает Excel.
Текущее решение не взлетает, даже в отдельном потоке.
Видимо нужен отдельный процесс.
Вопрос к знатокам, как сделать красиво, обработку событий Excel в dll, загружаемой самой Excel на С++ без MFC?
Выгружать из ресурсов dll - exe файл (с данным алгоритмом) и через CreateProcess запускать, кажется, что создаю костыли ненужные.

Добавлено через 3 часа 55 минут
Удалось разрулить с потоками и с IDispatch на COfficeEventHandler и IDispatch на Excel (допилил свои ошибки).
Взлетело, костыли не пригодились, всем спасибо!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.08.2020, 17:41

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Отследить события сразу нескольких полей
Для нескольких полей EditText я использую один слушатель CustTxtWatcher_1. Как отследить чтобы...

Отследить события ленты MS office interopt
Здравствуйте. Запускаю excel Dim WithEvents xlApp As Excel.Application xlApp = New...

Отследить возникновение события из другого метода
При выполнении одного из методов мне необходимо знать, вызывалось ли одно из событий формы. Можно...

Отследить срабатывание события над элементом с заданным id
Здравствуйте. Есть форма &lt;form id=&quot;formfiles&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt; ...

Как визуально отследить изменение переменной в одном обработчике события?
Всем здравствуйте. При клике по Button1 через 3 сек в метке Label1 появится сообщение 'конец'....

Как отследить в JTable события Начала/Конца редактирования ячейки?
Добрый день. Как отследить в JTable события Начала/Конца редактированя ячейки??? В CellEditor...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.