IBrowserPool — Reg-Free VBA WebView2 Multi-Browser Manager
Reg-Free Mode — programmatic multi-browser pool; every method takes browserIndex As Long as the first parameter
Works in VBA (Excel, Access, Word, Outlook, PowerPoint, Visio, Project), VB6, VB.NET, C#, C++, Delphi, Python, PowerShell, AutoIt — and any COM host.
The Setup Module — paste once, forget it
When you add LiteView2 in no-admin mode, you paste one standard module into your VBA project. You do this once, the same way you'd paste a utility module full of string functions.
The module does three things when your database first opens:
- Tells Windows where to find the OCX file (it's next to your .accdb)
- Loads the OCX without registering it in the Windows registry
- Creates the browser engine and makes it available to all your forms
After you paste it, you never look at it again. Every form uses it with one line:
Dim pool As Object
Set pool = GetPool() ' that's all — the browser engine is ready
Works without IT involvement
Most ActiveX controls need to be "registered" with Windows — which means running a program as Administrator, or asking IT. LiteView2 doesn't need this. Copy two files next to your .accdb file and it runs. When you copy your database to another PC, copy the OCX files too. No installation, no admin rights, no IT ticket — it just works.
IBrowserPool mirrors most of ILiteView2Ctrl's functionality but adds browserIndex As Long as the first parameter to every method. This page documents only the pool-specific methods. For shared methods (Navigate, ExecuteScript, PushRecordset, etc.), see the ILiteView2Ctrl reference — just add browserIndex as the first argument.
Canonical lifecycle template — Reg-Free Mode
The lifecycle pattern below eliminates the friction every customer hits the first time they use the pool from a VBA form. The Quick Start gets a browser running in 30 seconds; the full template adds buttons (with the first-click MouseDown mirror), host objects, error handlers, and inline comments explaining each line.
Quick Start (30 seconds)
- Add a Frame control named
fraBrowserto the form. - Open the
modLV2Poolbootstrap module that ships with LiteView2. InsideGetPool(), edit them_Pool.ActivateLicense "Your Company", "YOUR-LICENSE-KEY"line — replace the two string literals with your real company name andV1|...activation key (see the full module below). Every form then picks the licence up automatically viaGetPool(). - Paste this into the form's code module:
Option Explicit
Private pool As Object
Private idx As Long
Private Sub Form_Load()
Set pool = GetPool() ' GetPool activates the license once per process
idx = pool.CreateInControl("about:blank", Me.fraBrowser)
pool.SetReadyCallback idx, Me, "OnBrowserReady"
End Sub
Public Sub OnBrowserReady()
pool.SetLocalContentRoot idx, CurrentProject.Path
pool.Navigate idx, "https://lv2.example/index.html"
End Sub
Private Sub Form_Unload(Cancel As Integer)
pool.DestroyBrowserSync idx, 2000
End Sub
If your form just needs to display a page, the Quick Start is enough. Otherwise the full template below adds the rest. The activation key never appears in per-form code — it lives in modLV2Pool.bas once, and every form inherits it via GetPool().
The full modLV2Pool bootstrap module
There is no second module in Reg-Free Mode. modLV2Pool is the bootstrap module that ships with LiteView2 and exports GetPool(). Use the module exactly as shown below — to activate your purchased license, edit the two string literals ("Your Company" and "YOUR-LICENSE-KEY") inside the single ActivateLicense line. Comment that one line out to keep the 30-day Trial Period.
Option Explicit
' ============================================================================
' LiteView2 Reg-Free Pool bootstrap
' No regsvr32 required. The matching LiteView2_x64.ocx / LiteView2_x86.ocx
' must sit in the same folder as the .accdb / .xlsm.
' ============================================================================
#If Win64 Then
Private Declare PtrSafe Function SetDllDirectory Lib "kernel32" _
Alias "SetDllDirectoryW" (ByVal lpPathName As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_ActivateManifest _
Lib "LiteView2_x64.ocx" (ByVal path As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_CreateBrowserPool _
Lib "LiteView2_x64.ocx" () As Object
#Else
Private Declare PtrSafe Function SetDllDirectory Lib "kernel32" _
Alias "SetDllDirectoryW" (ByVal lpPathName As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_ActivateManifest _
Lib "LiteView2_x86.ocx" (ByVal path As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_CreateBrowserPool _
Lib "LiteView2_x86.ocx" () As Object
#End If
Private m_Pool As Object
Private m_Initialized As Boolean
Public Function GetPool() As Object
If Not m_Initialized Then
Dim p As String: p = CurrentProject.Path
SetDllDirectory StrPtr(p)
#If Win64 Then
LiteView2_ActivateManifest StrPtr(p & "\LiteView2_x64.ocx")
#Else
LiteView2_ActivateManifest StrPtr(p & "\LiteView2_x86.ocx")
#End If
Set m_Pool = LiteView2_CreateBrowserPool()
' Edit the two strings below: your registered company name and your
' V1|... activation key from the purchase email. Comment this line
' out to keep the 30-day Trial Period.
m_Pool.ActivateLicense "Your Company", "YOUR-LICENSE-KEY"
m_Initialized = True
End If
Set GetPool = m_Pool
End Function
Activation is process-wide and happens automatically the first time any form calls GetPool(). Forms never need to call ActivateLicense themselves.
Per-form code — full canonical template
' ============================================================================
' Reg-Free Mode — canonical lifecycle template (per form)
' ============================================================================
' Form prerequisites:
' - A Frame control named fraBrowser
' - modLV2Pool (bootstrap module shipped with LiteView2; the
' ActivateLicense line inside GetPool() holds your activation key)
' with your activation key edited into ActivateLicense. GetPool() then
' activates the license automatically on its first call in the process.
'
' When you add buttons users may click while focus is inside the browser,
' mirror Click into MouseDown — see the focus-transfer section below.
' ============================================================================
Option Compare Database
Option Explicit
Private pool As Object
Private idx As Long
Private Sub Form_Load()
On Error GoTo ErrH
If Me.CurrentView = 0 Then Exit Sub ' Skip in design view
' GetPool() handles license activation once per process -- see modLV2Pool.bas.
Set pool = GetPool()
idx = pool.CreateInControl("about:blank", Me.fraBrowser)
pool.SetReadyCallback idx, Me, "OnBrowserReady"
Exit Sub
ErrH:
MsgBox "Form_Load: " & Err.Number & " " & Err.Description, vbCritical
End Sub
' Public — invoked by the pool by name when the browser is ready.
Public Sub OnBrowserReady()
On Error GoTo ErrH
pool.SetLocalContentRoot idx, CurrentProject.Path
pool.SetAreHostObjectsAllowed idx, True
pool.AddHostObjectToScript idx, "vba", Me
pool.Navigate idx, "https://lv2.example/index.html"
Exit Sub
ErrH:
MsgBox "OnBrowserReady: " & Err.Number & " " & Err.Description, vbCritical
End Sub
' Called by the page via window.chrome.webview.hostObjects.sync.vba.OnReady()
Public Sub OnReady()
End Sub
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
If Not pool Is Nothing And idx <> 0 Then
pool.Stop idx ' halt any in-flight navigation
pool.ClearReadyCallback idx ' detach callback so it can't fire after teardown
pool.DestroyBrowserSync idx, 2000 ' synchronous teardown (max 2 s wait) -- REQUIRED
idx = 0
End If
Set pool = Nothing ' release the pool reference
End Sub
Lifecycle rules
- The activation key lives in
modLV2Pool.bas, not in per-form code.GetPool()activates the license automatically on the first call in the process. Forms simply callSet pool = GetPool()and inherit the licensed state. - Everything else waits for
OnBrowserReady.SetLocalContentRoot, host-object registration, and the firstNavigatebelong inOnBrowserReady. Calling them inForm_LoadafterCreateInControlraces with async init. - Host objects must be added before the navigation that uses them. Order:
SetLocalContentRoot→SetAreHostObjectsAllowed→AddHostObjectToScript→Navigate. - Buttons need a
MouseDownmirror when focus may be inside the browser. KeepClickfor keyboard activation; addMouseDownfor the first physical click. Form_Unloadteardown is required. CallClearReadyCallback,DestroyBrowserSync idx, 2000, thenSet pool = Nothing. WithoutDestroyBrowserSync, the browser process keeps Access alive after the form closes.
Activation key placement
- ✅ The activation key lives inside the single
ActivateLicenseline inGetPool()inmodLV2Pool.bas. Forms just callSet pool = GetPool()— no key string in the form. - ❌ Never paste the activation string into per-form code. Rotating the key would mean editing every form.
- ❌ Never call
ActivateLicenseAFTER the firstNavigate. The watermark may already have rendered. - ❌ Never call
ActivateLicenseinsideOnBrowserReady. By then the navigation decision has already used the license state.
Multiple browser instances
ActivateLicense is process-wide, not per-form and not per-browser:
- ONE successful
ActivateLicensecall activates every browser the pool creates afterwards in the same Access (or Office) session. - The pool shares the activated license across every
CreateInControlcall automatically — you do not register the license per browser-index. - Activation does not persist across Access restarts. Each fresh process must call
ActivateLicenseonce — that's whatGetPool()handles for you on the first form that calls it.
That is why the recommended pattern stores the key in modLV2Pool.bas: the activation key appears in exactly one place, the bootstrap module. Whichever form opens first calls GetPool() which triggers activation; every later form's GetPool() call is a cheap no-op (the singleton is already initialised). You change the key once, in one file, and every form picks it up automatically.
Never do this in Form_Load
' ❌ WRONG — the browser isn't ready right after CreateInControl.
' These calls race with async init or hit an unmapped lv2.example.
Private Sub Form_Load()
Set pool = GetPool()
idx = pool.CreateInControl("about:blank", Me.fraBrowser)
pool.SetLocalContentRoot idx, CurrentProject.Path ' ❌ wait for OnBrowserReady
pool.AddHostObjectToScript idx, "vba", Me ' ❌ wait for OnBrowserReady
pool.Navigate idx, "https://lv2.example/index.html" ' ❌ wait for OnBrowserReady
End Sub
' ✅ CORRECT — Form_Load does setup; OnBrowserReady does the rest.
' GetPool() activates the license internally (key lives in modLV2Pool.bas).
Private Sub Form_Load()
Set pool = GetPool()
idx = pool.CreateInControl("about:blank", Me.fraBrowser)
pool.SetReadyCallback idx, Me, "OnBrowserReady"
End Sub
Public Sub OnBrowserReady()
pool.SetLocalContentRoot idx, CurrentProject.Path
pool.SetAreHostObjectsAllowed idx, True
pool.AddHostObjectToScript idx, "vba", Me
pool.Navigate idx, "https://lv2.example/index.html"
End Sub
Lifecycle timeline
TIME EVENT WHAT YOUR CODE DOES HERE
──── ───────────────────────────────── ──────────────────────────────────────────
t0 Form_Load Set pool = GetPool() (modLV2Pool activates
the license internally)
idx = pool.CreateInControl("about:blank", fra)
pool.SetReadyCallback idx, Me, "OnBrowserReady"
↓
(WebView2 starts up — async) (you do nothing)
↓
t1 Public Sub OnBrowserReady pool.SetLocalContentRoot idx, CurrentProject.Path
pool.SetAreHostObjectsAllowed idx, True
pool.AddHostObjectToScript idx, "vba", Me
pool.Navigate idx, "https://lv2.example/index.html"
↓
t2 Page loads → DOMContentLoaded JavaScript runs in the page
Page calls window.chrome.webview
.hostObjects.sync.vba.OnReady()
↓
t3 Public Sub OnReady() in VBA Your post-page-load logic runs
↓
(user interacts...)
↓
tN Form_Unload pool.Stop idx
pool.ClearReadyCallback idx
pool.DestroyBrowserSync idx, 2000
Set pool = Nothing
Exit lifecycle — closing the form safely
The loading sequence has a clear order; the unloading sequence does too. Following it cleanly prevents three real problems:
- A navigation in flight at the moment the form closes can fire
NavigationCompletedagainst a half-destroyed browser. - An async ready callback that hasn't fired yet can trigger after VBA references are gone.
- Reg-Free Mode only — the WebView2 host process (
msedgewebview2.exe) keeps Access alive after the form closes if it isn't explicitly torn down.
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
If Not pool Is Nothing And idx <> 0 Then
pool.Stop idx ' halt any in-flight navigation
pool.ClearReadyCallback idx ' detach callback so it can't fire after teardown
pool.DestroyBrowserSync idx, 2000 ' synchronous teardown (max 2 s wait) -- REQUIRED
idx = 0
End If
Set pool = Nothing ' release the pool reference
End Sub
What each line does:
pool.Stop idx— halts a navigation that might still be loading when the user closes the form. Without it, the page can fireNavigationCompletedwhile the browser is being destroyed.pool.ClearReadyCallback idx— removes theOnBrowserReadycallback so it cannot fire on a form that's already unloading. Without this, an async ready callback can call back into VBA after the form's references are gone (Type mismatch / Object required).pool.DestroyBrowserSync idx, 2000— the critical one for Reg-Free Mode. Tears down the browser instance synchronously, waiting up to 2 seconds for in-process cleanup to complete. Without this call, the WebView2 host process keeps running and Access cannot exit cleanly — Task Manager will show a lingeringmsedgewebview2.exeandMSACCESS.EXEuntil the OS finally kills them.idx = 0— sentinel so a stray callback hitting this form sees an invalid handle and exits cleanly.Set pool = Nothing— releases your VBA reference to the pool singleton.On Error Resume Next— if the form is closing because of an earlier error, we still want the teardown attempt to complete; a second error during shutdown produces a half-stuck form customers struggle to dismiss.
SetLocalContentRoot path mapping
pool.SetLocalContentRoot idx, folder maps a folder on disk to the https://lv2.example/ virtual host. The mapping is one-to-one per browser: the folder you pass becomes the URL root.
| Disk path you pass | URL root | Example file on disk | URL to navigate to |
|---|---|---|---|
C:\Apps\MyDB\ | https://lv2.example/ | C:\Apps\MyDB\index.html | https://lv2.example/index.html |
C:\Apps\MyDB\ | https://lv2.example/ | C:\Apps\MyDB\pages\admin.html | https://lv2.example/pages/admin.html |
CurrentProject.Path | https://lv2.example/ | the form's folder | https://lv2.example/<any-file> |
Common path-mapping mistakes:
- Wrong root level. You map
C:\Apps\but your HTML lives inC:\Apps\MyDB\index.html. The URL must then behttps://lv2.example/MyDB/index.html, not/index.html. - Subfolder confusion. You pass
CurrentProject.Path & "\html"and then navigate tohttps://lv2.example/html/index.html. The\htmlpart already became the new root. - Backslash in URL. Use forward slashes only:
https://lv2.example/index.html. - Missing target file. The mapping is correct but
index.htmldoesn't actually exist in the mapped folder. WebView2 shows its own "page can't be reached" error.
Minimal HTML page (the bridge from the page side)
What index.html should look like to successfully call back into VBA:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>LiteView2 page</title>
</head>
<body>
<h1>Page loaded</h1>
<p id="status"></p>
<button onclick="notifyVBA()">Tell VBA hello</button>
<script>
// "vba" matches the third argument of pool.AddHostObjectToScript in VBA.
// Calling sync.vba.<name>() invokes a Public Sub on the VBA form.
function notifyVBA() {
try {
window.chrome.webview.hostObjects.sync.vba.OnReady();
document.getElementById('status').textContent = 'Reached VBA.';
} catch (e) {
document.getElementById('status').textContent = 'Bridge error: ' + e.message;
}
}
</script>
</body>
</html>
The VBA pool.AddHostObjectToScript idx, "vba", Me call (in OnBrowserReady) registered the form as the host object named vba. The page's sync.vba.OnReady() then invokes the form's Public Sub OnReady().
Access form-button "first-click does nothing" caveat
When focus is inside the embedded browser, Access uses the FIRST click on any external form button to move focus to that button. The button's Click event does NOT fire on that click; only the second click runs the handler. This is long-standing Access behavior with any embedded ActiveX control (legacy WebBrowser, Microsoft DatePicker, TreeView all have it), not a LiteView2 bug.
Mirror Click into MouseDown — MouseDown fires the instant the mouse goes down regardless of focus state. Keep Click for keyboard activation. The full template above shows the pattern on cmdGo.
Copy-Paste Checklist
Before reporting a problem, verify each of these:
- ☐
modLV2Pool.basis imported into the VBA project, with your real company name andV1|...activation key edited into them_Pool.ActivateLicenseline insideGetPool() - ☐ The form's
Form_LoadcallsSet pool = GetPool()(this is what triggers activation) - ☐
index.html(or whatever filename the code navigates to) physically exists in the folder you pass toSetLocalContentRoot - ☐
SetLocalContentRootis called BEFORE the firstNavigate - ☐
AddHostObjectToScriptis called BEFORE theNavigatethat loads the page that uses the host object - ☐ The form has an
OnBrowserReadyhandler registered viaSetReadyCallback— that handler is where the setup calls live, notForm_Load - ☐ Every Public Sub the page calls via
hostObjects.sync.vba.<name>()exists in the form's code module (includingOnReadyif your page calls it) - ☐ Any button reachable while focus is inside the WebView2 has BOTH a
Clickhandler AND aMouseDownmirror that runs the same action - ☐
Form_Unloadcallspool.ClearReadyCallback idxandpool.DestroyBrowserSync idx, 2000
Troubleshooting
| Symptom | Most likely cause | Fix |
|---|---|---|
| Watermark renders despite a valid key | Either the m_Pool.ActivateLicense line in GetPool() still has the placeholder "YOUR-LICENSE-KEY", or that line is commented out, or GetPool() isn't being called from Form_Load. | Open modLV2Pool.bas — confirm the ActivateLicense line inside GetPool() holds your real company name and your V1|... activation key, and that the line is not commented out. |
| Local files don't load — "Can't reach this page" or 404 | SetLocalContentRoot not called, called with the wrong folder, or the URL points outside the mapped folder | Map CurrentProject.Path; verify index.html exists in that folder; the URL must use forward slashes. |
| Local files exist but still won't load | Navigate executed before SetLocalContentRoot | Call SetLocalContentRoot BEFORE the first Navigate inside OnBrowserReady. |
window.chrome.webview.hostObjects.sync.vba is undefined in JS | AddHostObjectToScript was called AFTER Navigate. Host objects only bind on the NEXT navigation. | Inside OnBrowserReady the order must be: SetLocalContentRoot → SetAreHostObjectsAllowed → AddHostObjectToScript → Navigate. |
| First click on a form button does nothing; second click works | Access uses the first click on an external button to move focus to that button. The Click event doesn't fire on that click. | Mirror Click into a MouseDown handler for any button reachable while focus is inside the browser. Keep Click for keyboard activation. |
| WebView2 process lingers in Task Manager; Access hangs on exit | DestroyBrowserSync not called in Form_Unload. The browser process keeps Access alive. | Add pool.ClearReadyCallback idx, pool.DestroyBrowserSync idx, 2000, then Set pool = Nothing to Form_Unload. |
Getting Started — Reg-Free Setup
Before you can use IBrowserPool, add this standard module to your project. It declares the Win32 API calls needed to load the OCX without COM registration, then exposes a GetPool() singleton you can call from any form.
Place the OCX in the same folder as your .accdb or .xlsm.
modLV2Pool.bas — add once per project
Option Explicit
' --- Win32 + OCX declarations (64-bit / 32-bit) ---
#If Win64 Then
Private Declare PtrSafe Function SetDllDirectory Lib "kernel32" _
Alias "SetDllDirectoryW" (ByVal lpPathName As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_ActivateManifest _
Lib "LiteView2_x64.ocx" (ByVal path As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_CreateBrowserPool _
Lib "LiteView2_x64.ocx" () As Object
#Else
Private Declare PtrSafe Function SetDllDirectory Lib "kernel32" _
Alias "SetDllDirectoryW" (ByVal lpPathName As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_ActivateManifest _
Lib "LiteView2_x86.ocx" (ByVal path As LongPtr) As Long
Private Declare PtrSafe Function LiteView2_CreateBrowserPool _
Lib "LiteView2_x86.ocx" () As Object
#End If
Private m_Pool As Object
Public Function GetPool() As Object
If m_Pool Is Nothing Then
Dim p As String
p = CurrentProject.Path ' Access (Excel: ThisWorkbook.Path)
SetDllDirectory StrPtr(p) ' Tell Windows where the OCX lives
#If Win64 Then
LiteView2_ActivateManifest StrPtr(p & "\LiteView2_x64.ocx")
#Else
LiteView2_ActivateManifest StrPtr(p & "\LiteView2_x86.ocx")
#End If
Set m_Pool = LiteView2_CreateBrowserPool()
m_Pool.ActivateLicense "Your Company", "YOUR-LICENSE-KEY" ' omit this line during 30-day trial
End If
Set GetPool = m_Pool
End Function
Usage from any form
Private pool As Object
Private idx As Long
Private Sub Form_Load()
Set pool = GetPool()
idx = pool.CreateInControl("about:blank", Me.Frame1)
pool.SetReadyCallback idx, Me, "OnBrowserReady"
End Sub
' LiteView2 calls this on the UI thread when the browser is ready
Public Sub OnBrowserReady()
pool.SetLocalContentRoot idx, CurrentProject.Path & "\html"
pool.Navigate idx, "https://lv2.local/dashboard.html"
End Sub
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
If Not pool Is Nothing And idx <> 0 Then
pool.ClearReadyCallback idx
pool.DestroyBrowserSync idx, 2000
idx = 0
End If
End Sub
SetLocalContentRoot maps a folder on disk to the virtual hostname https://lv2.local/. Files in that folder are then accessible via URLs like https://lv2.local/dashboard.html. This avoids file:// URLs (which have security restrictions) and gives your local HTML files a proper HTTPS origin. See ILiteView2Ctrl › Local Content Mapping for details.
Licensing
ActivateLicense is called once per process, before creating any browser instances. The recommended place is inside GetPool(), right after LiteView2_CreateBrowserPool():
m_Pool.ActivateLicense "Your Company", "YOUR-LICENSE-KEY"
A 30-day trial starts automatically � all features are fully functional with no limitations. After trial expiry, the control displays a watermark and API methods return E_ACCESSDENIED. Add the ActivateLicense line with your purchased key to activate immediately. No license files, no registry entries � just one line of VBA code.
Reg-Free (IBrowserPool)
' Inside GetPool(), right after LiteView2_CreateBrowserPool()
m_Pool.ActivateLicense "My Company", "LICENSE-KEY-HERE"
Registered (Design-Time Control)
' In your Form_Load or WebViewReady event
m_lv.ActivateLicense "My Company", "LICENSE-KEY-HERE"
License Status Properties
' Works on both pool and control objects
Debug.Print "Status: " & obj.LicenseStatus
Debug.Print "Type: " & obj.LicenseType
Debug.Print "State: " & obj.LicenseState ' 0=Valid, 1=Trial, 2=Expired, 3=Invalid
Debug.Print "Days: " & obj.TrialDaysRemaining
Key Difference
Every ILiteView2Ctrl method gains a browserIndex As Long first parameter on IBrowserPool:
' ILiteView2Ctrl (design-time OCX — single browser)
m_lv.Navigate "https://example.com"
m_lv.PushRecordset rs, "onData"
' IBrowserPool (multi-browser pool — add browserIndex)
pool.Navigate browserIndex, "https://example.com"
pool.PushRecordset browserIndex, rs, "onData"
Create and destroy browser instances in the pool. Each Create call returns a unique index (1, 2, 3...) or 0 on failure.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| Create | hwndParent As Long, url As String, x As Long, y As Long, width As Long, height As Long | Long | Create browser, returns index (1,2,3...) or 0 on failure |
| Destroy | browserIndex As Long | Destroy browser (fire and forget) | |
| DestroySync | browserIndex As Long | Destroy synchronously (no timeout) | |
| DestroyBrowserSync | browserIndex As Long, timeoutMs As Long | Destroy synchronously with a timeout — blocks until destroyed or timeout expires. Recommended for Form_Unload. | |
| CreateWithProfile | hwndParent As Long, url As String, x As Long, y As Long, w As Long, h As Long, profileName As String | Long | Create with named profile |
| CreateWithProfileInPrivate | hwndParent As Long, url As String, x As Long, y As Long, w As Long, h As Long, profileName As String | Long | Create with InPrivate profile |
Create & Destroy Example
Source: frmLifecycleCore_Code.txt
' Create a browser in the pool
Dim idx As Long
idx = pool.Create(Me.hwnd, "about:blank", 0, 0, 800, 600)
If idx = 0 Then
MsgBox "Failed to create browser"
Exit Sub
End If
' Map local folder to https://lv2.local/ (call once per browser)
pool.SetLocalContentRoot idx, CurrentProject.Path & "\html"
' Navigate to a local HTML file
pool.Navigate idx, "https://lv2.local/dashboard.html"
' Cleanup
pool.Destroy idx
Park browsers to hide them while preserving state for later reuse, or destroy all parked browsers at once.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| Park | browserIndex As Long | Hide browser (park) — preserves state for reuse | |
| DestroyAllParked | Long | Destroy all parked browsers, returns count destroyed | |
| GetParkedBrowserCount | Long | Count of currently parked browsers |
Parking Example
' Park a browser to free resources but keep state
pool.Park browserIndex
Debug.Print "Parked browsers: " & pool.GetParkedBrowserCount
' Later: destroy all parked browsers
Dim freed As Long
freed = pool.DestroyAllParked
Debug.Print "Freed " & freed & " browsers"
Embed browsers into VBA Frame controls or reparent them to different windows.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| EmbedInControl | browserIndex As Long, control As Object | Embed browser in VBA Frame control | |
| CreateInControl | url As String, control As Object | Long | Create + embed in one call, returns index |
| CreateInControlWithProfile | url As String, control As Object, profileName As String | Long | Create + embed with named profile |
| Reparent | browserIndex As Long, hwndNewParent As Long, x As Long, y As Long, w As Long, h As Long | Move browser to new parent window |
Embedding Example
Source: src\frmBrowser.cls
' Map local folder first (required for lv2.local URLs)
pool.SetLocalContentRoot idx, CurrentProject.Path & "\html"
' Create and embed in an Access Frame control in one call
Dim idx As Long
idx = pool.CreateInControl("https://lv2.local/app.html", Me.fraWebView)
If idx > 0 Then
m_browserIndex = idx
End If
Manage browser profiles, InPrivate mode, and browsing data per browser instance.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| GetProfileName | browserIndex As Long | String | Get profile name for browser |
| IsInPrivateMode | browserIndex As Long | Boolean | Check if browser is InPrivate |
| GetProfilePath | browserIndex As Long | String | On-disk profile folder path |
| ClearProfileBrowsingData | browserIndex As Long, dataKinds As Long | Clear browsing data by kind flags | |
| ClearProfileBrowsingDataAll | browserIndex As Long | Clear all browsing data for profile |
Manage browser lifecycle, visibility, sizing, and suspension state.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| IsValidIndex | browserIndex As Long | Boolean | Check if browser index is still valid |
| GetBrowserCount | Long | Count of active browsers in pool | |
| Resize | browserIndex As Long, x As Long, y As Long, width As Long, height As Long | Resize browser | |
| SetVisible | browserIndex As Long, visible As Boolean | Set browser visibility | |
| TrySuspend | browserIndex As Long | Suspend browser to save resources | |
| ResumeBrowser | browserIndex As Long | Resume suspended browser | |
| IsSuspended | browserIndex As Long | Boolean | Check if browser is suspended |
These methods do NOT take a browserIndex parameter — they query the system.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| IsWebView2RuntimeInstalled | Boolean | Check if WebView2 runtime is installed | |
| GetWebView2RuntimeVersion | String | Get installed runtime version string | |
| GetWebView2RuntimePath | String | Get runtime installation path |
Runtime Detection Example
' Check runtime before creating browsers
If Not pool.IsWebView2RuntimeInstalled Then
MsgBox "WebView2 runtime not found. Please install it."
Exit Sub
End If
Debug.Print "Runtime version: " & pool.GetWebView2RuntimeVersion
Register a VBA method to be called when a browser is fully initialised. LiteView2 fires the callback on the UI thread via deferred PostMessage — no timer polling required.
Previously, Reg-Free Mode required a Form_Timer loop to call IsReady() every 100 ms. SetReadyCallback is event-driven: LiteView2 calls your named VBA method exactly once, as soon as the browser is ready — even if the environment is reused from a previous session.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| SetReadyCallback | browserIndex As Long, callbackObject As Object, methodName As String | Register a VBA object method to be called when the browser is ready. Works from any COM host (VBA, VB6, Delphi, C#). Fires exactly once; call ClearReadyCallback to reset. | |
| ClearReadyCallback | browserIndex As Long | Unregister the ready callback and reset the fired flag. Always call this in Form_Unload before DestroyBrowserSync. |
Ready Callback Example
Private pool As Object
Private idx As Long
Private Sub Form_Load()
Set pool = GetPool()
idx = pool.CreateInControl("about:blank", Me.fraBrowser)
pool.SetReadyCallback idx, Me, "OnBrowserReady"
End Sub
Public Sub OnBrowserReady()
pool.SetLocalContentRoot idx, CurrentProject.Path
pool.SetAreHostObjectsAllowed idx, True
Set m_callbacks = New clsCallbacks
pool.AddHostObjectToScript idx, "vba", m_callbacks
pool.Navigate idx, "https://lv2.local/myForm.html"
End Sub
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
If Not pool Is Nothing And idx <> 0 Then
pool.ClearReadyCallback idx ' always before DestroyBrowserSync
pool.DestroyBrowserSync idx, 2000
idx = 0
End If
End Sub
SetReadyCallback is dispatch ID 439; ClearReadyCallback is dispatch ID 444. The callback uses IDispatch::GetIDsOfNames + Invoke — it resolves your method name at call time, so any public Sub on any COM-visible object works as the target.
Allow JavaScript in the browser to call VBA macros directly, without manual WebMessageReceived routing.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| EnableAutoDispatch | browserIndex As Long, enabled As Boolean | Enable or disable auto-dispatch of HTML/JS calls to VBA macros | |
| IsAutoDispatchEnabled | browserIndex As Long | Boolean | Check whether auto-dispatch is currently enabled for this browser |
| SetAllowedVBAMacros | browserIndex As Long, macroList As String | Set comma-separated whitelist of VBA macro names that JS is allowed to call | |
| ClearAllowedVBAMacros | browserIndex As Long | Clear the VBA macro whitelist (blocks all auto-dispatch calls) | |
| RegisterVbaCallback | browserIndex As Long, jsName As String, callbackObject As Object, methodName As String | Register a VBA object method as a callable function from JavaScript. jsName is the name JS uses to call it. | |
| UnregisterVbaCallback | browserIndex As Long | Unregister all VBA callbacks for this browser |
Query and control audio playback state for a browser instance.
| Member | Parameters | Returns | Description |
|---|---|---|---|
| GetIsDocumentPlayingAudio | browserIndex As Long | Boolean | Check if the document is currently playing audio |
| GetIsMuted | browserIndex As Long | Boolean | Get the current mute state of the browser |
| SetIsMuted | browserIndex As Long, muted As Boolean | Mute or unmute the browser audio |
Additional methods available only on IBrowserPool (not on ILiteView2Ctrl).
| Member | Parameters | Returns | Description |
|---|---|---|---|
| GetUserAgent | browserIndex As Long | String | Get the current User-Agent string for this browser |
| SetDefaultBackgroundColor | browserIndex As Long, argbColor As Long | Set the default background color as ARGB (e.g. &HFF000000 for opaque black) | |
| ShowSaveAsDialog | browserIndex As Long | Show the browser's native Save As dialog | |
| GetLastError | browserIndex As Long | String | Get the last error message for this browser instance |
| GetLastErrorCode | browserIndex As Long | Long | Get the last error code (HRESULT) for this browser instance |