Skip to content

Commit 3d60bcc

Browse files
committed
Win32 WebView2 C++ Implementation
1 parent 718158c commit 3d60bcc

File tree

2 files changed

+324
-0
lines changed

2 files changed

+324
-0
lines changed

src/webview/win32_wv2.cpp

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
/*
2+
WebUI Library
3+
Win32 WebView2 C++ Implementation
4+
https://webui.me
5+
https://github.com/webui-dev/webui
6+
Copyright (c) 2020-2025 Hassan Draga.
7+
Licensed under MIT License.
8+
All rights reserved.
9+
Canada.
10+
*/
11+
12+
#ifdef _WIN32
13+
14+
#include "win32_wv2.hpp"
15+
#include "WebView2.h"
16+
#include <wrl.h>
17+
#include <cstdio>
18+
19+
using namespace Microsoft::WRL;
20+
21+
class WebView2Instance {
22+
public:
23+
ComPtr<ICoreWebView2Environment> webviewEnvironment;
24+
ComPtr<ICoreWebView2Controller> webviewController;
25+
ComPtr<ICoreWebView2> webviewWindow;
26+
HWND hwnd;
27+
wchar_t* url;
28+
bool navigate, size, position, stop;
29+
int width, height, x, y;
30+
31+
WebView2Instance()
32+
: hwnd(nullptr), url(nullptr), navigate(false), size(false)
33+
, position(false), stop(false), width(800), height(600), x(0), y(0) {}
34+
35+
~WebView2Instance() {
36+
if (url) free(url);
37+
}
38+
};
39+
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);
52+
}
53+
}
54+
return S_OK;
55+
}
56+
};
57+
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
77+
}
78+
79+
RECT bounds = {0, 0, instance->width, instance->height};
80+
controller->put_Bounds(bounds);
81+
82+
auto titleHandler = Make<TitleChangedHandler>(instance);
83+
EventRegistrationToken token;
84+
instance->webviewWindow->add_DocumentTitleChanged(titleHandler.Get(), &token);
85+
86+
if (instance->url) {
87+
instance->webviewWindow->Navigate(instance->url);
88+
}
89+
}
90+
return S_OK;
91+
}
92+
};
93+
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());
103+
}
104+
return S_OK;
105+
}
106+
};
107+
108+
extern "C" {
109+
110+
_webui_win32_wv2_handle _webui_win32_wv2_create(void) {
111+
return static_cast<_webui_win32_wv2_handle>(new WebView2Instance());
112+
}
113+
114+
void _webui_win32_wv2_free(_webui_win32_wv2_handle handle) {
115+
if (!handle) return;
116+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
117+
if (instance->webviewWindow) instance->webviewWindow.Reset();
118+
if (instance->webviewController) instance->webviewController.Reset();
119+
if (instance->webviewEnvironment) instance->webviewEnvironment.Reset();
120+
delete instance;
121+
}
122+
123+
bool _webui_win32_wv2_navigate(_webui_win32_wv2_handle handle, wchar_t* url) {
124+
if (!handle) return false;
125+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
126+
if (instance->webviewWindow && url) {
127+
return SUCCEEDED(instance->webviewWindow->Navigate(url));
128+
}
129+
return false;
130+
}
131+
132+
bool _webui_win32_wv2_set_position(_webui_win32_wv2_handle handle, int x, int y) {
133+
if (!handle) return false;
134+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
135+
return instance->hwnd && SetWindowPos(instance->hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
136+
}
137+
138+
bool _webui_win32_wv2_set_size(_webui_win32_wv2_handle handle, int width, int height) {
139+
if (!handle) return false;
140+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
141+
return instance->hwnd && SetWindowPos(instance->hwnd, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOREPOSITION);
142+
}
143+
144+
bool _webui_win32_wv2_maximize(_webui_win32_wv2_handle handle) {
145+
if (!handle) return false;
146+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
147+
return instance->hwnd && ShowWindow(instance->hwnd, SW_MAXIMIZE);
148+
}
149+
150+
bool _webui_win32_wv2_minimize(_webui_win32_wv2_handle handle) {
151+
if (!handle) return false;
152+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
153+
return instance->hwnd && ShowWindow(instance->hwnd, SW_MINIMIZE);
154+
}
155+
156+
HWND _webui_win32_wv2_get_hwnd(_webui_win32_wv2_handle handle) {
157+
return handle ? static_cast<WebView2Instance*>(handle)->hwnd : nullptr;
158+
}
159+
160+
void _webui_win32_wv2_set_hwnd(_webui_win32_wv2_handle handle, HWND hwnd) {
161+
if (handle) static_cast<WebView2Instance*>(handle)->hwnd = hwnd;
162+
}
163+
164+
void _webui_win32_wv2_set_stop(_webui_win32_wv2_handle handle, bool stop) {
165+
if (handle) static_cast<WebView2Instance*>(handle)->stop = stop;
166+
}
167+
168+
bool _webui_win32_wv2_get_stop(_webui_win32_wv2_handle handle) {
169+
return handle ? static_cast<WebView2Instance*>(handle)->stop : false;
170+
}
171+
172+
void _webui_win32_wv2_set_navigate_flag(_webui_win32_wv2_handle handle, bool navigate) {
173+
if (handle) static_cast<WebView2Instance*>(handle)->navigate = navigate;
174+
}
175+
176+
void _webui_win32_wv2_set_size_flag(_webui_win32_wv2_handle handle, bool size) {
177+
if (handle) static_cast<WebView2Instance*>(handle)->size = size;
178+
}
179+
180+
void _webui_win32_wv2_set_position_flag(_webui_win32_wv2_handle handle, bool position) {
181+
if (handle) static_cast<WebView2Instance*>(handle)->position = position;
182+
}
183+
184+
bool _webui_win32_wv2_get_navigate_flag(_webui_win32_wv2_handle handle) {
185+
return handle ? static_cast<WebView2Instance*>(handle)->navigate : false;
186+
}
187+
188+
bool _webui_win32_wv2_get_size_flag(_webui_win32_wv2_handle handle) {
189+
return handle ? static_cast<WebView2Instance*>(handle)->size : false;
190+
}
191+
192+
bool _webui_win32_wv2_get_position_flag(_webui_win32_wv2_handle handle) {
193+
return handle ? static_cast<WebView2Instance*>(handle)->position : false;
194+
}
195+
196+
void _webui_win32_wv2_set_url(_webui_win32_wv2_handle handle, wchar_t* url) {
197+
if (!handle) return;
198+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
199+
if (instance->url) free(instance->url);
200+
if (url) {
201+
size_t len = wcslen(url) + 1;
202+
instance->url = (wchar_t*)malloc(len * sizeof(wchar_t));
203+
if (instance->url) wcscpy_s(instance->url, len, url);
204+
} else {
205+
instance->url = nullptr;
206+
}
207+
}
208+
209+
wchar_t* _webui_win32_wv2_get_url(_webui_win32_wv2_handle handle) {
210+
return handle ? static_cast<WebView2Instance*>(handle)->url : nullptr;
211+
}
212+
213+
void _webui_win32_wv2_set_dimensions(_webui_win32_wv2_handle handle, int x, int y, int width, int height) {
214+
if (!handle) return;
215+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
216+
instance->x = x;
217+
instance->y = y;
218+
instance->width = width;
219+
instance->height = height;
220+
}
221+
222+
void _webui_win32_wv2_get_dimensions(_webui_win32_wv2_handle handle, int* x, int* y, int* width, int* height) {
223+
if (!handle) return;
224+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
225+
if (x) *x = instance->x;
226+
if (y) *y = instance->y;
227+
if (width) *width = instance->width;
228+
if (height) *height = instance->height;
229+
}
230+
231+
bool _webui_win32_wv2_create_environment(_webui_win32_wv2_handle handle, wchar_t* cacheFolder) {
232+
if (!handle) return false;
233+
WebView2Instance* instance = static_cast<WebView2Instance*>(handle);
234+
235+
_wputenv(L"WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--enable-features=msWebView2EnableDraggableRegions");
236+
237+
typedef HRESULT (__stdcall *CreateCoreWebView2EnvironmentWithOptionsFunc)(
238+
PCWSTR, PCWSTR, ICoreWebView2EnvironmentOptions*,
239+
ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler*);
240+
241+
HMODULE webviewLib = LoadLibraryA("WebView2Loader.dll");
242+
if (!webviewLib) return false;
243+
244+
CreateCoreWebView2EnvironmentWithOptionsFunc createEnv =
245+
(CreateCoreWebView2EnvironmentWithOptionsFunc)GetProcAddress(webviewLib, "CreateCoreWebView2EnvironmentWithOptions");
246+
if (!createEnv) {
247+
FreeLibrary(webviewLib);
248+
return false;
249+
}
250+
251+
auto environmentHandler = Make<EnvironmentCompletedHandler>(instance);
252+
if (!environmentHandler) {
253+
FreeLibrary(webviewLib);
254+
return false;
255+
}
256+
257+
HRESULT hr = createEnv(NULL, cacheFolder, NULL, environmentHandler.Get());
258+
return SUCCEEDED(hr);
259+
}
260+
261+
void* _webui_win32_wv2_get_controller(_webui_win32_wv2_handle handle) {
262+
return handle ? static_cast<WebView2Instance*>(handle)->webviewController.Get() : nullptr;
263+
}
264+
265+
}
266+
267+
#endif

src/webview/win32_wv2.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
WebUI Library
3+
Win32 WebView2 C++ Implementation
4+
https://webui.me
5+
https://github.com/webui-dev/webui
6+
Copyright (c) 2020-2025 Hassan Draga.
7+
Licensed under MIT License.
8+
All rights reserved.
9+
Canada.
10+
*/
11+
12+
#ifndef WEBUI_WIN32_WV2_HPP
13+
#define WEBUI_WIN32_WV2_HPP
14+
15+
#ifdef _WIN32
16+
17+
#include <windows.h>
18+
#include <wchar.h>
19+
#include <stdbool.h>
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
25+
typedef struct _webui_window_t _webui_window_t;
26+
typedef void* _webui_win32_wv2_handle;
27+
28+
_webui_win32_wv2_handle _webui_win32_wv2_create(void);
29+
void _webui_win32_wv2_free(_webui_win32_wv2_handle handle);
30+
bool _webui_win32_wv2_navigate(_webui_win32_wv2_handle handle, wchar_t* url);
31+
bool _webui_win32_wv2_set_position(_webui_win32_wv2_handle handle, int x, int y);
32+
bool _webui_win32_wv2_set_size(_webui_win32_wv2_handle handle, int width, int height);
33+
bool _webui_win32_wv2_maximize(_webui_win32_wv2_handle handle);
34+
bool _webui_win32_wv2_minimize(_webui_win32_wv2_handle handle);
35+
HWND _webui_win32_wv2_get_hwnd(_webui_win32_wv2_handle handle);
36+
void _webui_win32_wv2_set_hwnd(_webui_win32_wv2_handle handle, HWND hwnd);
37+
void _webui_win32_wv2_set_stop(_webui_win32_wv2_handle handle, bool stop);
38+
bool _webui_win32_wv2_get_stop(_webui_win32_wv2_handle handle);
39+
void _webui_win32_wv2_set_navigate_flag(_webui_win32_wv2_handle handle, bool navigate);
40+
void _webui_win32_wv2_set_size_flag(_webui_win32_wv2_handle handle, bool size);
41+
void _webui_win32_wv2_set_position_flag(_webui_win32_wv2_handle handle, bool position);
42+
bool _webui_win32_wv2_get_navigate_flag(_webui_win32_wv2_handle handle);
43+
bool _webui_win32_wv2_get_size_flag(_webui_win32_wv2_handle handle);
44+
bool _webui_win32_wv2_get_position_flag(_webui_win32_wv2_handle handle);
45+
void _webui_win32_wv2_set_url(_webui_win32_wv2_handle handle, wchar_t* url);
46+
wchar_t* _webui_win32_wv2_get_url(_webui_win32_wv2_handle handle);
47+
void _webui_win32_wv2_set_dimensions(_webui_win32_wv2_handle handle, int x, int y, int width, int height);
48+
void _webui_win32_wv2_get_dimensions(_webui_win32_wv2_handle handle, int* x, int* y, int* width, int* height);
49+
bool _webui_win32_wv2_create_environment(_webui_win32_wv2_handle handle, wchar_t* cacheFolder);
50+
void* _webui_win32_wv2_get_controller(_webui_win32_wv2_handle handle);
51+
52+
#ifdef __cplusplus
53+
}
54+
#endif
55+
56+
#endif // _WIN32
57+
#endif // WEBUI_WIN32_WV2_HPP

0 commit comments

Comments
 (0)