Skip to content

Commit 620b86b

Browse files
committed
Adding docs strings
1 parent 3b4f03a commit 620b86b

2 files changed

Lines changed: 201 additions & 4 deletions

File tree

docs/stdWebView.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# `stdWebView`
2+
3+
`stdWebView` embeds the Microsoft Edge **WebView2** control in a Win32 parent window. It is aimed at **Excel VBA UserForms**: host the browser inside an `MSForms.Frame` (or any HWND you obtain) to show HTML, open sites, and run JavaScript with optional async callbacks.
4+
5+
**Platform:** Windows only. Requires the [WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) and `WebView2Loader.dll` (same loader used by the WebView2 SDK) available to the host process.
6+
7+
**Implementation note:** Environment and controller callbacks are implemented with in-process vtables and executable thunks (similar patterns appear elsewhere in stdVBA). See the class header in `src/stdWebView.cls` for attribution to prior WebView2/VBA work.
8+
9+
## Spec
10+
11+
### Constructors
12+
13+
#### `CreateFromHwnd(ByVal hwnd As LongPtr, Optional ByVal OnReady As stdICallable = Nothing) As stdWebView`
14+
15+
Creates a `stdWebView` bound to an existing window handle. The WebView fills the **client area** of that window.
16+
17+
`OnReady`, if provided, is invoked once the controller and `CoreWebView2` are ready. The callback is called via `stdICallable.RunEx` with a single-element array: the `stdWebView` instance (`Array(Me)`).
18+
19+
```vb
20+
Dim wv As stdWebView
21+
Set wv = stdWebView.CreateFromHwnd(SomeHwnd, stdLambda.Create("$1.Navigate ""https://example.com"""))
22+
```
23+
24+
Construction is **synchronous from the caller’s perspective**: the factory polls `DoEvents` until initialization finishes or times out (raises `WebView2 initialization failed or timed out`).
25+
26+
#### `CreateFromFrame(ByVal frm As Object, Optional ByVal OnReady As stdICallable = Nothing) As stdWebView`
27+
28+
Same as `CreateFromHwnd`, but resolves the HWND from an **`MSForms.Frame`**. Raises if `frm` is not a `Frame`.
29+
30+
```vb
31+
UserForm1.Show vbModeless
32+
Dim wv As stdWebView
33+
Set wv = stdWebView.CreateFromFrame(UserForm1.FrameWeb)
34+
wv.Navigate "https://example.com"
35+
```
36+
37+
### Instance properties
38+
39+
#### `Html() As String` (Get)
40+
41+
Returns the document’s `document.documentElement.outerHTML`. Uses an internal synchronous script; requires `IsReady`.
42+
43+
#### `Html(ByVal rhs As String)` (Let)
44+
45+
Loads HTML into the view via WebView2’s string navigation (`NavigateToString`). Requires `IsReady`.
46+
47+
### Instance methods
48+
49+
#### `IsReady() As Boolean`
50+
51+
`True` when `CoreWebView2` is available. `Navigate`, `Html`, `JavaScriptRun`, and `JavaScriptRunSync` require a ready view.
52+
53+
#### `Quit()`
54+
55+
Tears down the controller reference and frees internal handler allocations. Safe to call when already shut down.
56+
57+
#### `Navigate(ByVal url As String)`
58+
59+
Navigates to a URL. Requires `IsReady`.
60+
61+
#### `Back()` / `Forward()`
62+
63+
History navigation implemented by running `history.back()` / `history.forward()` synchronously in the page.
64+
65+
#### `JavaScriptRunSync(ByVal script As String) As String`
66+
67+
Executes `script` in the page context and **blocks** until the result is delivered, pumping messages with `DoEvents`.
68+
69+
* Only **one** synchronous script may run at a time; a second call raises.
70+
* The return value is the **JSON-encoded** result string from the WebView2 script API (e.g. quoted strings, `null`, numbers as JSON). Parse or unwrap as needed.
71+
72+
```vb
73+
Debug.Print wv.JavaScriptRunSync("document.title") ' e.g. returns JSON string including quotes
74+
```
75+
76+
#### `JavaScriptRun(ByVal script As String, Optional ByVal callback As stdICallable = Nothing)`
77+
78+
Queues script execution without blocking. If `callback` is set, it is invoked with `RunEx(Array(errorCode, resultJson))` when execution completes.
79+
80+
```vb
81+
wv.JavaScriptRun "console.log(1)", stdLambda.Create("Debug.Print $1, $2") ' errorCode, resultJson
82+
```
83+
84+
### Checklist (quick reference)
85+
86+
**Constructors**
87+
88+
* [X] `CreateFromHwnd(hwnd, OnReady?)`
89+
* [X] `CreateFromFrame(frm, OnReady?)`
90+
91+
**Instance**
92+
93+
* [X] `IsReady()`
94+
* [X] `Quit()`
95+
* [X] `Navigate(url)`
96+
* [X] `Back()` / `Forward()`
97+
* [X] `Html` Get/Let
98+
* [X] `JavaScriptRunSync(script)`
99+
* [X] `JavaScriptRun(script, callback?)`
100+
101+
### Protected / Friend API
102+
103+
`protCreate`, `protEnvCompleted`, `protCtrlCompleted`, and `protScriptCompleted` are **not** part of the public contract; they exist for the COM callback thunks. Do not call them from application code.
104+
105+
## stdVBA developer notes
106+
107+
* A per-instance user data folder is created under `%TEMP%` (`stdWebView_*`) for the WebView2 profile.
108+
* If `CreateCoreWebView2EnvironmentWithOptions` fails, the error is raised with the HRESULT from the loader.
109+
* `zzProtWebView_*` entry points must remain `Public` so thunk code can dispatch into the instance; they are not user APIs.

src/stdWebView.cls

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,27 @@ Attribute VB_Exposed = False
1212
'@description Standalone WebView2 host for Excel UserForms (primary). Requires WebView2Loader.dll,
1313
' Microsoft Edge WebView2 Runtime. Handler vtables use executable thunks (see AddressOfThunkForComProc/VBA7/CMonitors.cls).
1414
'@attribution https://github.com/tarboh/WebView2-For-Excel-VBA - Heavily inspired by this project.
15+
'@example:
16+
' Dim wv As stdWebView
17+
' Sub UserForm_Initialize()
18+
' Set wv = stdWebView.CreateFromFrame(UserForm1.Frame1, stdLambda.Create("$1.Navigate ""https://example.com"""))
19+
' wv.Navigate "https://example.com"
20+
' Debug.Print wv.JavaScriptRunSync("document.title")
21+
' End Sub
22+
'
23+
'Spec:
24+
' CONSTRUCTORS
25+
' [X] CreateFromHwnd(hwnd, OnReady?) as stdWebView
26+
' [X] CreateFromFrame(frm as MSForms.Frame, OnReady?) as stdWebView
27+
' INSTANCE METHODS / PROPERTIES
28+
' [X] IsReady() as Boolean
29+
' [X] Quit()
30+
' [X] Navigate(url)
31+
' [X] Back()
32+
' [X] Forward()
33+
' [X] Get/Let Html() as String
34+
' [X] JavaScriptRunSync(script) as String
35+
' [X] JavaScriptRun(script, callback?)
1536

1637
Option Explicit
1738

@@ -273,12 +294,18 @@ Private Function PtrToStrW(ByVal pWStr As LongPtr) As String
273294
End Function
274295

275296
' ============================================================================
276-
' WebView2 handler vtables (IUnknown + Invoke)
277-
' These six Public methods must remain the first Public members in this class:
278-
' GetComProcAddress(Me, 0..5) depends on that. Do not move other Public methods
297+
' IMPORTANT - DO NOT MOVE THESE METHODS,
298+
' AND DO NOT ADD ANY NEW PUBLIC METHODS ABOVE
299+
' OR INBETWEEN THEM!!
300+
' This is because the WebView2 handler vtables (IUnknown + Invoke)
301+
' depend on the order of the Public methods.
302+
'
303+
' `GetComProcAddress(Me, 0..5)` depends on that. Do not move other Public methods
279304
' above them without adjusting the indexes.
280305
' ============================================================================
281306

307+
'WebView2 QueryInterface Thunk Implementation. DO NOT CALL THIS METHOD.
308+
'@protected
282309
Public Function zzProtWebView_QI( _
283310
ByVal callbackThis As LongPtr, _
284311
ByVal riid As LongPtr, _
@@ -288,14 +315,20 @@ Public Function zzProtWebView_QI( _
288315
zzProtWebView_QI = 0&
289316
End Function
290317

318+
'WebView2 AddRef Thunk Implementation. DO NOT CALL THIS METHOD.
319+
'@protected
291320
Public Function zzProtWebView_AddRef(ByVal callbackThis As LongPtr) As Long
292321
zzProtWebView_AddRef = 1&
293322
End Function
294323

324+
'WebView2 Release Thunk Implementation. DO NOT CALL THIS METHOD.
325+
'@protected
295326
Public Function zzProtWebView_Release(ByVal callbackThis As LongPtr) As Long
296327
zzProtWebView_Release = 1&
297328
End Function
298329

330+
'WebView2 Environment Invoke Thunk Implementation. DO NOT CALL THIS METHOD.
331+
'@protected
299332
Public Function zzProtWebView_EnvInvoke( _
300333
ByVal callbackThis As LongPtr, _
301334
ByVal errorCode As Long, _
@@ -306,6 +339,8 @@ Public Function zzProtWebView_EnvInvoke( _
306339
zzProtWebView_EnvInvoke = 0&
307340
End Function
308341

342+
'WebView2 Controller Invoke Thunk Implementation. DO NOT CALL THIS METHOD.
343+
'@protected
309344
Public Function zzProtWebView_CtrlInvoke( _
310345
ByVal callbackThis As LongPtr, _
311346
ByVal errorCode As Long, _
@@ -316,6 +351,8 @@ Public Function zzProtWebView_CtrlInvoke( _
316351
zzProtWebView_CtrlInvoke = 0&
317352
End Function
318353

354+
'WebView2 Script Invoke Thunk Implementation. DO NOT CALL THIS METHOD.
355+
'@protected
319356
Public Function zzProtWebView_ScriptInvoke( _
320357
ByVal callbackThis As LongPtr, _
321358
ByVal errorCode As Long, _
@@ -332,26 +369,37 @@ End Function
332369

333370
' ============================================================================
334371

372+
'Create a stdWebView from a window handle.
335373
'@constructor
374+
'@param hwnd - Parent window handle that will host the WebView2 client area.
336375
'@param OnReady as stdICallable<(stdWebView)=>void> - Optional callback run when WebView2 controller/CoreWebView2 is ready.
376+
'@returns - Created stdWebView instance.
377+
'@remark - Initialization blocks and pumps DoEvents until WebView2 is ready or times out.
337378
Public Function CreateFromHwnd(ByVal hwnd As LongPtr, Optional ByVal OnReady As stdICallable = Nothing) As stdWebView
338379
Dim w As New stdWebView
339380
Call w.protCreate(hwnd, OnReady)
340381
Set CreateFromHwnd = w
341382
End Function
342383

384+
'Create a stdWebView from an MSForms.Frame.
343385
'@constructor
344-
'@param OnReady as stdICallable<(stdWebView)=>void> - Optional callback run when WebView2 controller/CoreWebView2 is ready.
386+
'@param frm - MSForms.Frame used as the host container.
387+
'@param OnReady as stdICallable<(wv as stdWebView)=>void> - Optional callback run when WebView2 controller/CoreWebView2 is ready.
388+
'@returns - Created stdWebView instance.
389+
'@remark - Resolves the frame HWND and delegates to CreateFromHwnd.
345390
Public Function CreateFromFrame(ByVal frm As Object, Optional ByVal OnReady As stdICallable = Nothing) As stdWebView
346391
If frm Is Nothing Then Err.Raise 5, "stdWebView::CreateFromFrame", "frm is Nothing"
347392
If TypeName(frm) <> "Frame" Then Err.Raise 5, "stdWebView::CreateFromFrame", "Expected MSForms.Frame"
348393
Set CreateFromFrame = CreateFromHwnd(FrameToHwnd(frm), OnReady)
349394
End Function
350395

396+
'Check whether the WebView2 is ready to be used.
397+
'@returns - `True` when CoreWebView2 is available and navigation/script APIs can be used.
351398
Public Function IsReady() As Boolean
352399
IsReady = (This.ppWebView2 <> 0)
353400
End Function
354401

402+
'@remark - Releases controller/environment state and frees COM handler allocations. Safe to call more than once.
355403
Public Sub Quit()
356404
On Error Resume Next
357405
If This.pController <> 0 Then
@@ -364,30 +412,48 @@ Public Sub Quit()
364412
Call FreeHandlerAllocs
365413
End Sub
366414

415+
'Navigate to a URL.
416+
'@param url - URL to navigate to.
417+
'@remark - Raises if the WebView is not ready.
418+
'@TODO: Add a callback parameter.
367419
Public Sub Navigate(ByVal url As String)
368420
If Not IsReady Then Err.Raise 5, "stdWebView::Navigate", "WebView not ready"
369421
Call CallVT(This.ppWebView2, 5, vbLong, StrPtr(url))
370422
End Sub
371423

424+
'Nagivate backward
425+
'@remark - Navigates backward using injected `history.back()`.
372426
Public Sub Back()
373427
Call JavaScriptRunSync("history.back(); void 0")
374428
End Sub
375429

430+
'Navigate forward
431+
'@remark - Navigates forward using injected `history.forward()`.
376432
Public Sub Forward()
377433
Call JavaScriptRunSync("history.forward(); void 0")
378434
End Sub
379435

436+
'Get the current document outer HTML.
437+
'@returns - Current document outer HTML (`document.documentElement.outerHTML`).
438+
'@remark - Raises if the WebView is not ready.
380439
Public Property Get Html() As String
381440
If Not IsReady Then Err.Raise 5, "stdWebView::Html [Get]", "WebView not ready"
382441
Html = JsonUnquoteString(JavaScriptRunSync("(function(){try{return document.documentElement?document.documentElement.outerHTML:'';}catch(e){return '';}})()"))
383442
End Property
384443

444+
'Set the current document outer HTML.
445+
'@param rhs - HTML content loaded with WebView2 `NavigateToString`.
446+
'@remark - Raises if the WebView is not ready.
385447
Public Property Let Html(ByVal rhs As String)
386448
If Not IsReady Then Err.Raise 5, "stdWebView::Html [Let]", "WebView not ready"
387449
This.lastHtml = rhs
388450
Call CallVT(This.ppWebView2, 6, vbLong, StrPtr(rhs))
389451
End Property
390452

453+
'Execute a JavaScript script synchronously.
454+
'@param script - JavaScript executed in the page context.
455+
'@returns - JSON-encoded result string returned by WebView2 script execution.
456+
'@remark - Blocks with DoEvents until completion. Only one synchronous run can be active at a time.
391457
Public Function JavaScriptRunSync(ByVal script As String) As String
392458
If Not IsReady Then Err.Raise 5, "stdWebView::JavaScriptRunSync", "WebView not ready"
393459
If This.syncWaitRequestId <> 0 Then
@@ -410,7 +476,10 @@ Public Function JavaScriptRunSync(ByVal script As String) As String
410476
JavaScriptRunSync = This.scriptResult
411477
End Function
412478

479+
'Execute a JavaScript script asynchronously.
480+
'@param script - JavaScript executed in the page context.
413481
'@param callback as stdICallable<(errorCode as long, resultJson as string)=>void> - Optional callback invoked when script execution completes.
482+
'@remark - Runs asynchronously. Callback receives `Array(errorCode, resultJson)`.
414483
Public Sub JavaScriptRun(ByVal script As String, Optional ByVal callback As stdICallable = Nothing)
415484
If Not IsReady Then Err.Raise 5, "stdWebView::JavaScriptRun", "WebView not ready"
416485
Call SweepCompletedPendingScripts
@@ -419,6 +488,10 @@ Public Sub JavaScriptRun(ByVal script As String, Optional ByVal callback As stdI
419488
End If
420489
End Sub
421490

491+
'Protected method to handle the environment creation callback.
492+
'@protected
493+
'@param errorCode - HRESULT from environment creation callback.
494+
'@param pEnvironment - IWebView2Environment pointer returned by WebView2.
422495
Friend Sub protEnvCompleted(ByVal errorCode As Long, ByVal pEnvironment As LongPtr)
423496
If errorCode <> 0 Then
424497
This.waitingInit = False
@@ -432,6 +505,10 @@ Friend Sub protEnvCompleted(ByVal errorCode As Long, ByVal pEnvironment As LongP
432505
Call CallVT(pEnvironment, 3, vbLong, This.parentHwnd, This.pCtrlHandlerObj)
433506
End Sub
434507

508+
'Protected method to handle the controller creation callback.
509+
'@protected
510+
'@param errorCode - HRESULT from controller creation callback.
511+
'@param pController - IWebView2Controller pointer returned by WebView2.
435512
Friend Sub protCtrlCompleted(ByVal errorCode As Long, ByVal pController As LongPtr)
436513
If errorCode <> 0 Then
437514
This.waitingInit = False
@@ -457,6 +534,11 @@ Friend Sub protCtrlCompleted(ByVal errorCode As Long, ByVal pController As LongP
457534
End If
458535
End Sub
459536

537+
'Protected method to handle the script completion callback.
538+
'@protected
539+
'@param errorCode - HRESULT from script completion callback.
540+
'@param resultJson - JSON result string returned by WebView2.
541+
'@param requestId - Internal request identifier for queued script work.
460542
Friend Sub protScriptCompleted(ByVal errorCode As Long, ByVal resultJson As String, ByVal requestId As Long)
461543
Dim idx As Long
462544
Dim cb As stdICallable
@@ -486,6 +568,12 @@ Friend Sub protScriptCompleted(ByVal errorCode As Long, ByVal resultJson As Stri
486568
End If
487569
End Sub
488570

571+
'Protected method to create the stdWebView instance.
572+
'@constructor
573+
'@protected
574+
'@param hwnd - Parent window handle used to host WebView2.
575+
'@param OnReady as stdICallable<(stdWebView)=>void> - Optional callback run when initialization completes.
576+
'@remark - Internal creation entry point used by public constructors.
489577
Friend Sub protCreate(ByVal hwnd As LongPtr, Optional ByVal OnReady As stdICallable = Nothing)
490578
If hwnd = 0 Then Err.Raise 5, "stdWebView::CreateFromHwnd", "hwnd is 0"
491579
This.parentHwnd = hwnd

0 commit comments

Comments
 (0)