Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,139
Записей в блоге: 22

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

01.08.2020, 11:08. Показов 20288. Ответов 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
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.08.2020, 11:08
Ответы с готовыми решениями:

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

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

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

7
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
01.08.2020, 12:40
Цитата Сообщение от bedvit Посмотреть сообщение
Пишу на C ++ без MFC, ATL, #import (желателен этот путь, но и другие можно рассмотреть)
#import лучше использовать, чтоб не брать неизвестно откуда интерфейсы и guidы.
И проверяй, что возвращают функции, SUCCEDED(hr)/FAILED(hr)
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,139
Записей в блоге: 22
01.08.2020, 18:03  [ТС]
Здесь пишут, что бывают проблемы со счетчиком ссылок в #import.
Что посоветуете по отслеживанию события сохранения в Excel?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
01.08.2020, 18:07
Цитата Сообщение от bedvit Посмотреть сообщение
Здесь пишут, что бывают проблемы со счетчиком ссылок в #import.
Причём здесь счётчик ссылок? Импорт просто создаст просто создаст заголовки с интерфейсами, guid-ами и прочим.
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,139
Записей в блоге: 22
01.08.2020, 19:27  [ТС]
oleg-m1973, пока не понял вашу мысль. Не могли бы вы привести неболшой пример и пояснить, как это использовать в контексте моей проблемы?
0
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,139
Записей в блоге: 22
18.08.2020, 12:04  [ТС]
Без обработок ошибок, как-то так:
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
 Аватар для bedvit
1208 / 259 / 22
Регистрация: 20.05.2016
Сообщений: 1,139
Записей в блоге: 22
20.08.2020, 17:41  [ТС]
Вообщем с exe более-менее разобрался.
Далее, реализовал данный алгоритм в dll, который подгружает Excel.
Текущее решение не взлетает, даже в отдельном потоке.
Видимо нужен отдельный процесс.
Вопрос к знатокам, как сделать красиво, обработку событий Excel в dll, загружаемой самой Excel на С++ без MFC?
Выгружать из ресурсов dll - exe файл (с данным алгоритмом) и через CreateProcess запускать, кажется, что создаю костыли ненужные.

Добавлено через 3 часа 55 минут
Удалось разрулить с потоками и с IDispatch на COfficeEventHandler и IDispatch на Excel (допилил свои ошибки).
Взлетело, костыли не пригодились, всем спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
20.08.2020, 17:41
Помогаю со студенческими работами здесь

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

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

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

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

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


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

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

Новые блоги и статьи
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru