Skip to content

Host Adaptation Guide - VB6/Excel/Access Multi-Host Integration

📖 Table of Contents


Overview

cWebView2Host needs to embed the WebView2 child window into the host application's window and bridge events through message interception. Different host environments (VB6, Excel UserForm, Access Form) have significantly different window mechanisms, so an adapter layer is designed to abstract away these differences.

✨ Core Features

  • 🔄 Auto-Detection - Automatically selects adapter based on Windows class name
  • 🖥️ Seamless Adaptation - VB6/Excel/Access use exactly the same API
  • 🛡️ Access Safety - Message window adapter avoids Access window subclassing crashes
  • 📡 Event Bridging - Unified HostMouse/HostKey event model

Adapter Architecture

IHostAdapter Interface

vb
Interface IHostAdapter
    Sub Attach(hostHWnd As LongPtr, core As WebView2Core)
    Sub Detach()
    Sub ScheduleOnMainThread(core As WebView2Core)
    Sub EnsureChildVisible(childHWnd As LongPtr, width As Long, height As Long)
    Sub SyncChildSize(childHWnd As LongPtr, width As Long, height As Long)
    Function FindAndSubclassWv2Child() As LongPtr
    Sub CleanupChildSubclass()
    Property Get Wv2ChildHWnd() As LongPtr
    Property Get AdapterName() As String
End Interface

Auto-Selection Logic

Initialize(HostOrHwnd, HttpOrDir)

    ├── Get host window hWnd

    ├── GetClassName(hWnd) == "OForm" ?
    │   ├── Yes → Create MessageWindowAdapter
    │   │         (Access window, cannot be safely subclassed)
    │   │
    │   └── No  → Create HostSubclassAdapter
                (VB6/Excel/UserForm, can be safely subclassed)

Adapter Responsibility Comparison

ResponsibilityHostSubclassAdapterMessageWindowAdapter
Host window subclassingDirect subclassingNo subclassing (creates message window)
Message windowNot neededCreates HWND_MESSAGE message window
Size synchronizationWM_SIZE interception200ms timer polling
Focus managementWM_SETFOCUS/KILLFOCUSTimer check + focus guardian
Host mouse eventsFully supportedNot supported
Host keyboard eventsFully supportedNot supported
WV2 child right-click captureSubclasses Chrome_WidgetWin_0Subclasses Chrome_WidgetWin_0
Child window visibilityAutomaticForce TOP+VISIBLE (Access occlusion issue)

Subclassing Adapter (VB6/Excel)

How It Works

VB6 Form (hWnd)
  │ [SetWindowSubclass] → SubclassProc

  ├── WM_SIZE → Adjust WV2 Controller Bounds + SyncChildSize
  ├── WM_SETFOCUS → Fire HostFocus event
  ├── WM_KILLFOCUS → Fire HostBlur event
  ├── WM_KEYDOWN/UP → Fire HostKeyDown/Up event
  ├── WM_CHAR → Fire HostKeyPress event
  ├── WM_xBUTTONDOWN/UP/DBLCLK → Fire HostMouseDown/Up/DblClick
  ├── WM_MOUSEMOVE → Fire HostMouseMove (requires EnableMouseMoveEvents)
  ├── WM_MOUSEWHEEL → Fire HostMouseWheel
  ├── WM_CONTEXTMENU → Fire HostContextMenu
  ├── WM_DESTROY → AdapterTriggerCleanup
  └── WM_WV2_DEFERRED_CALLBACK → ProcessDeferredCallbacks

Chrome_WidgetWin_0 (WV2 child window)
  │ [SetWindowSubclass] → ChildSubclassProc

  ├── WM_RBUTTONDOWN → Forward to Core
  ├── WM_RBUTTONUP → Forward to Core
  ├── WM_CONTEXTMENU → Fire HostContextMenu
  └── WM_DESTROY → Cleanup subclassing

Usage Limitations

  • Cannot use other third-party window subclassing tools during subclassing (potential conflicts)
  • AddressOf may return different thunks in VB6, but the adapter saves it once during Attach

Message Window Adapter (Access)

How It Works

Access OForm windows are managed by the Access runtime — direct subclassing causes crashes. MessageWindowAdapter creates an independent hidden message window to work around this issue.

Access OForm (cannot be subclassed)

  ├── Create Message-Only Window (HWND_MESSAGE parent)
  │   │ [SetWindowSubclass] → SubclassProc (safe: we own this window)
  │   │
  │   ├── WM_WV2_DEFERRED_CALLBACK → ProcessDeferredCallbacks
  │   ├── WM_TIMER →
  │   │   ├── 200ms polling: check host size change → SyncChildSize
  │   │   └── 5-tick focus guardian: check GetFocus()==0 → restore focus
  │   └── WM_DESTROY → Cleanup

  └── Chrome_WidgetWin_0 (WV2 child window)
      │ [SetWindowSubclass] → ChildSubclassProc

      ├── WM_RBUTTONDOWN/UP → Forward to Core
      └── WM_CONTEXTMENU → Forward to Core

Access-Specific Handling

Child Window Visibility Enforcement

Access's rendering engine may draw over the WV2 child window, causing content to be obscured. EnsureChildVisible() forces the child window to TOP + VISIBLE:

vb
' Internal implementation
SetWindowPos childHWnd, HWND_TOP, 0, 0, width, height, _
    SWP_NOMOVE Or SWP_NOZORDER Or SWP_SHOWWINDOW

Focus Guardian

Access may unexpectedly steal focus, preventing WebView2 from receiving keyboard input. The adapter checks focus state once per second:

Every 5 timer cycles (approximately 1 second):
    If GetFocus() == 0  ' No window has focus
        SetFocus(hostHWnd)  ' Restore focus to host window
        Cooldown 3 seconds to avoid focus fighting

Size Synchronization

Since OForm's WM_SIZE cannot be intercepted, a 200ms timer polling is used:

vb
' Timer callback
GetClientRect hostHWnd, rc
If rc.Width <> lastWidth Or rc.Height <> lastHeight Then
    Controller.Bounds = rc  ' Update WV2 control size
    SyncChildSize            ' Sync child window
End If

Host Usage Guides

VB6 Standard Form

vb
Dim WithEvents wv As cWebView2Host

Private Sub Form_Load()
    Set wv = New cWebView2Host
    wv.Initialize Me.hWnd, "https://vb6.pro"
    ' Automatically uses HostSubclassAdapter
End Sub

Private Sub Form_Resize()
    ' Subclassing adapter already handles WM_SIZE automatically
    ' Usually no need to call Resize manually
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set wv = Nothing
End Sub

VB6 MDI Child Form

vb
Dim WithEvents wv As cWebView2Host
Dim ThisUrl As String

Public Sub Init(Optional ByVal Url As String)
    Me.Show
    If Url = "" Then Url = "https://vb6.pro"
    ThisUrl = Url
    Set wv = New cWebView2Host
    wv.Initialize Me       ' Auto-gets Me.hWnd
End Sub

Private Sub wv_Ready()
    wv.Navigate ThisUrl
End Sub

Excel UserForm

vb
' In UserForm code module
Dim WithEvents wv As cWebView2Host

Private Sub UserForm_Initialize()
    Set wv = New cWebView2Host
    wv.Initialize Me.hWnd, "https://example.com"
End Sub

Private Sub UserForm_Terminate()
    Set wv = Nothing
End Sub

Access Form

vb
' In Access form code module
Dim WithEvents wv As cWebView2Host

Private Sub Form_Load()
    Set wv = New cWebView2Host
    wv.Initialize Me.hWnd, "https://example.com"
    ' Auto-detects OForm → Uses MessageWindowAdapter
    ' Host mouse/keyboard events are not available
End Sub

Private Sub Form_Close()
    Set wv = Nothing
End Sub

Embedding in VB6 Frame Control

WebView2 can also be embedded in a Frame control instead of the entire Form:

vb
Dim wv As New cWebView2Host

Private Sub Form_Load()
    wv.Initialize Me.Frame1.hWnd, "https://example.com"
End Sub

FAQ

❓ Q1: How to determine which adapter is currently in use?

vb
Debug.Print wv.HostAdapterName
' Outputs "HostSubclassAdapter" or "MessageWindowAdapter"

❓ Q2: Host mouse events not firing in Access?

Reason: MessageWindowAdapter does not subclass the host window, so it cannot intercept mouse/keyboard messages in the host area.

Solution: Use WebView2 content area events (UserMouse series) instead, or use BindUI to bind DOM events to VB6 methods.


❓ Q3: WebView2 occasionally gets obscured in Access?

Reason: The Access rendering engine draws over the WV2 child window, especially after switching windows.

Solution: MessageWindowAdapter handles this internally (EnsureChildVisible). If occlusion persists, manually call:

vb
wv.Resize  ' Trigger child window refresh

❓ Q4: WebView2 size not syncing after Resize in VB6?

Reason: HostSubclassAdapter automatically handles size synchronization in WM_SIZE, but certain scenarios (e.g., manually resizing the window) may require additional triggering.

Solution:

vb
Private Sub Form_Resize()
    If Not wv Is Nothing Then
        wv.Resize
    End If
End Sub

❓ Q5: Are multiple WebView2 instances supported?

Yes. Each cWebView2Host instance independently manages its own WebView2 control. In MDI applications, each child form can have its own WebView2 instance:

vb
' MDI child form
Dim WithEvents wv As cWebView2Host

Private Sub Init(ByVal Url As String)
    Set wv = New cWebView2Host
    wv.Initialize Me.hWnd, Url
End Sub

Note: Multiple instances should use different UserDataFolder to avoid data conflicts.


Last Updated: 2026-06-24

VB6 and LOGO copyright of Microsoft Corporation