Skip to content

Commit 6cc6c50

Browse files
committed
Win32 WebView2 C++ Implementation (GCC)
1 parent 3d60bcc commit 6cc6c50

File tree

1 file changed

+252
-64
lines changed

1 file changed

+252
-64
lines changed

src/webview/win32_wv2.cpp

Lines changed: 252 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,43 @@
1313

1414
#include "win32_wv2.hpp"
1515
#include "WebView2.h"
16-
#include <wrl.h>
1716
#include <cstdio>
1817

19-
using namespace Microsoft::WRL;
18+
#ifdef _MSC_VER
19+
// MSVC: Use Windows Runtime Library
20+
#include <wrl.h>
21+
using namespace Microsoft::WRL;
22+
#else
23+
// MinGW: Define our own ComPtr template
24+
template<typename T>
25+
class ComPtr {
26+
T* ptr;
27+
public:
28+
ComPtr() : ptr(nullptr) {}
29+
~ComPtr() { Reset(); }
30+
ComPtr(const ComPtr&) = delete;
31+
ComPtr& operator=(const ComPtr&) = delete;
32+
33+
void Reset() {
34+
if (ptr) {
35+
ptr->Release();
36+
ptr = nullptr;
37+
}
38+
}
39+
40+
T* Get() const { return ptr; }
41+
T** GetAddressOf() { Reset(); return &ptr; }
42+
T* operator->() const { return ptr; }
43+
operator bool() const { return ptr != nullptr; }
44+
45+
ComPtr& operator=(T* p) {
46+
Reset();
47+
ptr = p;
48+
if (ptr) ptr->AddRef();
49+
return *this;
50+
}
51+
};
52+
#endif
2053

2154
class WebView2Instance {
2255
public:
@@ -37,73 +70,219 @@ class WebView2Instance {
3770
}
3871
};
3972

40-
class TitleChangedHandler : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICoreWebView2DocumentTitleChangedEventHandler> {
41-
WebView2Instance* instance;
42-
public:
43-
TitleChangedHandler(WebView2Instance* inst) : instance(inst) {}
44-
HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2* sender, IUnknown* args) override {
45-
(void)args;
46-
if (sender && instance->hwnd) {
47-
LPWSTR newTitle = nullptr;
48-
sender->get_DocumentTitle(&newTitle);
49-
if (newTitle) {
50-
SetWindowTextW(instance->hwnd, newTitle);
51-
CoTaskMemFree(newTitle);
73+
#ifdef _MSC_VER
74+
// MSVC: Use WRL RuntimeClass
75+
class TitleChangedHandler : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICoreWebView2DocumentTitleChangedEventHandler> {
76+
WebView2Instance* instance;
77+
public:
78+
TitleChangedHandler(WebView2Instance* inst) : instance(inst) {}
79+
HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2* sender, IUnknown* args) override {
80+
(void)args;
81+
if (sender && instance->hwnd) {
82+
LPWSTR newTitle = nullptr;
83+
sender->get_DocumentTitle(&newTitle);
84+
if (newTitle) {
85+
SetWindowTextW(instance->hwnd, newTitle);
86+
CoTaskMemFree(newTitle);
87+
}
5288
}
89+
return S_OK;
90+
}
91+
};
92+
#else
93+
// MinGW: Manual COM implementation
94+
class TitleChangedHandler : public ICoreWebView2DocumentTitleChangedEventHandler {
95+
ULONG refCount;
96+
WebView2Instance* instance;
97+
public:
98+
TitleChangedHandler(WebView2Instance* inst) : refCount(1), instance(inst) {}
99+
100+
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override {
101+
if (!ppvObject) return E_POINTER;
102+
*ppvObject = nullptr;
103+
if (riid == IID_IUnknown || riid == __uuidof(ICoreWebView2DocumentTitleChangedEventHandler)) {
104+
*ppvObject = static_cast<ICoreWebView2DocumentTitleChangedEventHandler*>(this);
105+
AddRef();
106+
return S_OK;
107+
}
108+
return E_NOINTERFACE;
53109
}
54-
return S_OK;
55-
}
56-
};
57110

58-
class ControllerCompletedHandler : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICoreWebView2CreateCoreWebView2ControllerCompletedHandler> {
59-
WebView2Instance* instance;
60-
public:
61-
ControllerCompletedHandler(WebView2Instance* inst) : instance(inst) {}
62-
HRESULT STDMETHODCALLTYPE Invoke(HRESULT result, ICoreWebView2Controller* controller) override {
63-
if (SUCCEEDED(result) && controller) {
64-
instance->webviewController = controller;
65-
controller->get_CoreWebView2(&instance->webviewWindow);
66-
67-
ComPtr<ICoreWebView2Settings> settings;
68-
if (SUCCEEDED(instance->webviewWindow->get_Settings(&settings))) {
69-
settings->put_IsScriptEnabled(TRUE);
70-
settings->put_AreDefaultScriptDialogsEnabled(TRUE);
71-
settings->put_IsWebMessageEnabled(TRUE);
72-
#ifdef WEBUI_LOG
73-
settings->put_AreDevToolsEnabled(TRUE);
74-
#else
75-
settings->put_AreDevToolsEnabled(FALSE);
76-
#endif
111+
ULONG STDMETHODCALLTYPE AddRef() override {
112+
return ++refCount;
113+
}
114+
115+
ULONG STDMETHODCALLTYPE Release() override {
116+
ULONG count = --refCount;
117+
if (count == 0) delete this;
118+
return count;
119+
}
120+
121+
HRESULT STDMETHODCALLTYPE Invoke(ICoreWebView2* sender, IUnknown* args) override {
122+
(void)args;
123+
if (sender && instance->hwnd) {
124+
LPWSTR newTitle = nullptr;
125+
sender->get_DocumentTitle(&newTitle);
126+
if (newTitle) {
127+
SetWindowTextW(instance->hwnd, newTitle);
128+
CoTaskMemFree(newTitle);
129+
}
77130
}
131+
return S_OK;
132+
}
133+
};
134+
#endif
78135

79-
RECT bounds = {0, 0, instance->width, instance->height};
80-
controller->put_Bounds(bounds);
136+
#ifdef _MSC_VER
137+
class ControllerCompletedHandler : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICoreWebView2CreateCoreWebView2ControllerCompletedHandler> {
138+
WebView2Instance* instance;
139+
public:
140+
ControllerCompletedHandler(WebView2Instance* inst) : instance(inst) {}
141+
HRESULT STDMETHODCALLTYPE Invoke(HRESULT result, ICoreWebView2Controller* controller) override {
142+
if (SUCCEEDED(result) && controller) {
143+
instance->webviewController = controller;
144+
controller->get_CoreWebView2(&instance->webviewWindow);
145+
146+
ComPtr<ICoreWebView2Settings> settings;
147+
if (SUCCEEDED(instance->webviewWindow->get_Settings(&settings))) {
148+
settings->put_IsScriptEnabled(TRUE);
149+
settings->put_AreDefaultScriptDialogsEnabled(TRUE);
150+
settings->put_IsWebMessageEnabled(TRUE);
151+
#ifdef WEBUI_LOG
152+
settings->put_AreDevToolsEnabled(TRUE);
153+
#else
154+
settings->put_AreDevToolsEnabled(FALSE);
155+
#endif
156+
}
157+
158+
RECT bounds = {0, 0, instance->width, instance->height};
159+
controller->put_Bounds(bounds);
160+
161+
auto titleHandler = Make<TitleChangedHandler>(instance);
162+
EventRegistrationToken token;
163+
instance->webviewWindow->add_DocumentTitleChanged(titleHandler.Get(), &token);
164+
165+
if (instance->url) {
166+
instance->webviewWindow->Navigate(instance->url);
167+
}
168+
}
169+
return S_OK;
170+
}
171+
};
172+
#else
173+
class ControllerCompletedHandler : public ICoreWebView2CreateCoreWebView2ControllerCompletedHandler {
174+
ULONG refCount;
175+
WebView2Instance* instance;
176+
public:
177+
ControllerCompletedHandler(WebView2Instance* inst) : refCount(1), instance(inst) {}
178+
179+
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override {
180+
if (!ppvObject) return E_POINTER;
181+
*ppvObject = nullptr;
182+
if (riid == IID_IUnknown || riid == __uuidof(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler)) {
183+
*ppvObject = static_cast<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler*>(this);
184+
AddRef();
185+
return S_OK;
186+
}
187+
return E_NOINTERFACE;
188+
}
81189

82-
auto titleHandler = Make<TitleChangedHandler>(instance);
83-
EventRegistrationToken token;
84-
instance->webviewWindow->add_DocumentTitleChanged(titleHandler.Get(), &token);
190+
ULONG STDMETHODCALLTYPE AddRef() override {
191+
return ++refCount;
192+
}
85193

86-
if (instance->url) {
87-
instance->webviewWindow->Navigate(instance->url);
194+
ULONG STDMETHODCALLTYPE Release() override {
195+
ULONG count = --refCount;
196+
if (count == 0) delete this;
197+
return count;
198+
}
199+
200+
HRESULT STDMETHODCALLTYPE Invoke(HRESULT result, ICoreWebView2Controller* controller) override {
201+
if (SUCCEEDED(result) && controller) {
202+
instance->webviewController = controller;
203+
controller->get_CoreWebView2(instance->webviewWindow.GetAddressOf());
204+
205+
ICoreWebView2Settings* settings = nullptr;
206+
if (SUCCEEDED(instance->webviewWindow->get_Settings(&settings)) && settings) {
207+
settings->put_IsScriptEnabled(TRUE);
208+
settings->put_AreDefaultScriptDialogsEnabled(TRUE);
209+
settings->put_IsWebMessageEnabled(TRUE);
210+
#ifdef WEBUI_LOG
211+
settings->put_AreDevToolsEnabled(TRUE);
212+
#else
213+
settings->put_AreDevToolsEnabled(FALSE);
214+
#endif
215+
settings->Release();
216+
}
217+
218+
RECT bounds = {0, 0, instance->width, instance->height};
219+
controller->put_Bounds(bounds);
220+
221+
TitleChangedHandler* titleHandler = new TitleChangedHandler(instance);
222+
EventRegistrationToken token;
223+
instance->webviewWindow->add_DocumentTitleChanged(titleHandler, &token);
224+
225+
if (instance->url) {
226+
instance->webviewWindow->Navigate(instance->url);
227+
}
88228
}
229+
return S_OK;
89230
}
90-
return S_OK;
91-
}
92-
};
231+
};
232+
#endif
93233

94-
class EnvironmentCompletedHandler : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler> {
95-
WebView2Instance* instance;
96-
public:
97-
EnvironmentCompletedHandler(WebView2Instance* inst) : instance(inst) {}
98-
HRESULT STDMETHODCALLTYPE Invoke(HRESULT result, ICoreWebView2Environment* env) override {
99-
if (SUCCEEDED(result) && env) {
100-
instance->webviewEnvironment = env;
101-
auto controllerHandler = Make<ControllerCompletedHandler>(instance);
102-
env->CreateCoreWebView2Controller(instance->hwnd, controllerHandler.Get());
234+
#ifdef _MSC_VER
235+
class EnvironmentCompletedHandler : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler> {
236+
WebView2Instance* instance;
237+
public:
238+
EnvironmentCompletedHandler(WebView2Instance* inst) : instance(inst) {}
239+
HRESULT STDMETHODCALLTYPE Invoke(HRESULT result, ICoreWebView2Environment* env) override {
240+
if (SUCCEEDED(result) && env) {
241+
instance->webviewEnvironment = env;
242+
auto controllerHandler = Make<ControllerCompletedHandler>(instance);
243+
env->CreateCoreWebView2Controller(instance->hwnd, controllerHandler.Get());
244+
}
245+
return S_OK;
246+
}
247+
};
248+
#else
249+
class EnvironmentCompletedHandler : public ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler {
250+
ULONG refCount;
251+
WebView2Instance* instance;
252+
public:
253+
EnvironmentCompletedHandler(WebView2Instance* inst) : refCount(1), instance(inst) {}
254+
255+
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override {
256+
if (!ppvObject) return E_POINTER;
257+
*ppvObject = nullptr;
258+
if (riid == IID_IUnknown || riid == __uuidof(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler)) {
259+
*ppvObject = static_cast<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler*>(this);
260+
AddRef();
261+
return S_OK;
262+
}
263+
return E_NOINTERFACE;
264+
}
265+
266+
ULONG STDMETHODCALLTYPE AddRef() override {
267+
return ++refCount;
103268
}
104-
return S_OK;
105-
}
106-
};
269+
270+
ULONG STDMETHODCALLTYPE Release() override {
271+
ULONG count = --refCount;
272+
if (count == 0) delete this;
273+
return count;
274+
}
275+
276+
HRESULT STDMETHODCALLTYPE Invoke(HRESULT result, ICoreWebView2Environment* env) override {
277+
if (SUCCEEDED(result) && env) {
278+
instance->webviewEnvironment = env;
279+
ControllerCompletedHandler* controllerHandler = new ControllerCompletedHandler(instance);
280+
env->CreateCoreWebView2Controller(instance->hwnd, controllerHandler);
281+
}
282+
return S_OK;
283+
}
284+
};
285+
#endif
107286

108287
extern "C" {
109288

@@ -248,13 +427,22 @@ bool _webui_win32_wv2_create_environment(_webui_win32_wv2_handle handle, wchar_t
248427
return false;
249428
}
250429

251-
auto environmentHandler = Make<EnvironmentCompletedHandler>(instance);
252-
if (!environmentHandler) {
253-
FreeLibrary(webviewLib);
254-
return false;
255-
}
430+
#ifdef _MSC_VER
431+
auto environmentHandler = Make<EnvironmentCompletedHandler>(instance);
432+
if (!environmentHandler) {
433+
FreeLibrary(webviewLib);
434+
return false;
435+
}
436+
HRESULT hr = createEnv(NULL, cacheFolder, NULL, environmentHandler.Get());
437+
#else
438+
EnvironmentCompletedHandler* environmentHandler = new EnvironmentCompletedHandler(instance);
439+
if (!environmentHandler) {
440+
FreeLibrary(webviewLib);
441+
return false;
442+
}
443+
HRESULT hr = createEnv(NULL, cacheFolder, NULL, environmentHandler);
444+
#endif
256445

257-
HRESULT hr = createEnv(NULL, cacheFolder, NULL, environmentHandler.Get());
258446
return SUCCEEDED(hr);
259447
}
260448

0 commit comments

Comments
 (0)