WebView2、登場秘話
登場秘話
〜半年前に自分で埋めた種と、たーぼーさんからの一通の報告〜
このツールの誕生秘話の「半年前に埋めた種を掘り起こす」の章でも触れた通り、WebView2対応(v3.0.0)の種は、実は2026年3月頃とほぼ同じ時期――にすでに蒔かれていました。ここでは、その種がなぜ一度は本体と分離し、どうやって半年越しに復活したのかを、もう少し詳しく振り返ります。
Accessへの嫉妬
全ての始まりは、Accessに関する業務(タスク)が飛び込んできたことです。Accessに関する知識も多少はあったので快く引き受け、作業をしていきました。で、ふと見てしまったのです。

ん、これってもしや🫨
そうです。Accessには、最新のブラウザのChromiumを動かせる仕組み、WebView2機能が備わっていたのです。
実際、既にこれを駆使した自動化制御を行ってる例がSNS等で見かけました。
例えば下記です。
URL判定してページを巡回する処理ができた。ロジックはデスクトップアプリのスコアマネージャーと殆ど同一。 https://t.co/RH5j4miF8s
— たーぼー(インコ) (@fenblen_puyo) November 30, 2023
しかし、このWebView2OnAccessは
- 365のサブスクリプションバージョンじゃないと動かない
- Access買い切りの場合は2024から
という金銭的な壁がありました🥲
「Excelには権限がないのか!?」という嫉妬と絶望の中、私は決意しました。
「公式が用意してくれないなら、今のExcel環境だけでWebView2を埋め込んで、自力で完全制御する仕組みを作ってやる!」
一度は、妥協案で始まった物から、ある方の一報を受けて、完全なWebView2埋め込みまでのストーリーを綴ります。
とりあえずまずは、簡単なルートを試したかった🥲
VBAで複雑なことをする際、最も簡単に解決する方法の1つに、「参照設定」というのがあります。
それをベースにしたExcelにWebView2を載せるPOCはすでにありました。
が、残念ながら更新が止まっていて、尚且つ32bit向けという壁ですぐには試せませんでした。
今の時代は、64Bitが主流。うちのOfficeも64Bitとしてインストールされていました。
32bitにしたら、動いてる光景が見れるかも🥺
可能性はあるかもしれませんが、「まぁ、動いたところで外部依存だしな~🙃」という気持ちになる予想は付くので結局、この目で見ることはまだありませんでした。
次に、AIに聞いた
するとこんな回答が来ました。
Edgeをkioskモードで起動して、
SetParentで、UserFormに埋め込んじゃおう🤠
てっきり、「無理です」と言われると思いきや、ちゃんとルートを教えてくれました。
というのもこの質問は、新規で訪ねたものではありません。開発秘話でも述べた通り、AIをふんだんに駆使してます。つまり、続きとして訊いてます。
当然、会話の履歴には、CDPのやり取りがいっぱい詰まってます。つまり
Excel (VBA) ↔ CDP via Pipe(--remote-debugging-pipe) ↔ Edge.exe(UserForm内)という経路が成り立ち、
- 外部起動だけど、CDPという制御コアが整ってるので、
SetParentで、UserFormに無理やり誘拐しても違和感がない
という風に成り立つのです🤠

▲ Google ページが UserForm 内に表示された様子。アドレスバーなし・タブなし = 完全 WebView2 ルック
この辺の詳細は下記にて別途語っております。
どうしても本物のWebView2として使いたい🥲
しかし、やはり心のどこかでは満足してはいませんでした
あれはあくまでも「Edge.exe」で埋め込んでるに過ぎない🙃「msedgewebview2.exe」という本物のWebView2じゃないと嫌だ
しかし、探しても探してもやはり、VBA単体でWebView2の記事は、今まで出てきませんでした。
プリインストール環境縛りであればあることはありました。

▲ PowerShellで、WebView2を起動して、そのWebView2をSetWindowLongPtr
でも、制御コアは、ps1という別ソースにて書かないといけないという別言語の知識も必要になり
動くけど、ps1コードを充実させる気力はない🫠
なんというか、もう外部依存そのものが嫌という気持ちです。
もう一度、思い出してください。
IE時代なら
CreateObject("InternetExplorer.Application")宣言で、すぐにブラウザ制御が始まる- UserForm内への埋め込みも、「Microsoft Web Browser」コントロール埋め込みで、すぐにブラウザ制御が始まる
昔は、両方できてたのに今は、片方はできなくなった
それが嫌だったのです。
だからと言って、じゃ~どうすれば、UserFormにExcelから呼び出した本物のWebView2を召喚すればいいのかも分からない八方塞がりでした...
Qiitaに落ちていた「ブレイクスルー」
そしてついに、見つけました。
🔗 Excel VBAだけでWebView2を動かす(Qiita)
「外部DLLの登録も、TLBの参照設定も要らない。純粋なExcel VBAのメモリ空間だけで、本物のWebView2が動く」
初め読んだときは正直、よくわかりませんでした😇
- Vtable、COM、参照カウント、CoTaskMemAlloc……
最初は完全に呪文でした😇
「なんでマクロ動かすだけでC言語の教科書みたいな単語と戦わなきゃいけないんだ!?」と。
でも、AIを壁打ち相手にして、仕組みを解剖していくうちに、点と点が一本の線で繋がっていきました。
- なぜ外部DLLが要らないのか? 👉 Windowsに最初から入っている
DispCallFuncというAPIを使えば、C++の仮想関数テーブル(vtable)の番地を手計算して、VBAから直接ノックできるから。 - なぜ参照設定(TLB)が要らないのか? 👉 設計図(タイプライブラリ)をコンパイラに読ませる代わりに、自分自身がコンパイラになってメモリ上に直接インターフェースの配線をハンダ付けしているから。
「あ、これ……黒魔術に見えて、Windowsの仕組み(COMとWin32 API)を極限までしゃぶり尽くした超・正統派の力技なんだ!」
そう理解できた瞬間、目の前がパーッと開けました。
この辺の技術的な仕組みは、こちらのページにて解説してます。
しかし、そこは「さらなる巨大な沼」の入り口だった……
3月15日、さっそくAIと一緒に、手を動かし始めます。
2026-03-15 WebView2を動かす基盤を作成
2026-03-15 QueryInterface が E_NOINTERFACE を返していた問題を修正
2026-03-15 vtable オフセットが間違っている影響でクラッシュする問題を修正
2026-03-15 UserFormに埋め込むウィンドウを用意しそこに埋め込むように改良数日で、UserFormにWebView2を埋め込んで動かすところまでは辿り着きました。
UserFormの真ん中に、最新のChromium(WebView2)がサクッと表示されたときの感動は、今でも忘れられません🥹
ただし、ここで大きな壁にぶつかります。当時の本体(main)には、まだ RaiseEvent による非同期イベント配信の仕組みがありませんでした。 それが整うのは、通信経路の拡張はどうしたの?セクションで CDPCore.cls に RaiseEvent CDPBrowserEvent 等が生まれる5月末〜6月のことで、この時点ではまだ2ヶ月以上先の話です。
共有できる土台がない以上、やれることは1つでした🥺
2026-03-17 `CDPBrowser`にあったmethodの一部を移植
2026-03-17 別ツールで分けるため、セル定義の整理
2026-03-21 `CDPBrowser`にあるほとんど機能を一旦そのまま移植
2026-03-21 `CDPBrowser`→`WebView2Browser`へ置き換えCDPBrowser にあった機能を、ほぼそのまま WebView2Browser というクラスにコピーする形で移植しました。動きはします。しかし、結果として生まれたのは、同じ根から生えた、しかし物理的には完全に別の2本のツールでした。
- Chromiumブラウザ制御ツール(本体)
- WebView2専用制御ツール(新顔)
コードは似ているのに、修正は毎回2箇所。片方を直せば、もう片方も直さないと辻褄が合わない。保守が、単純につらい。 この時点の自分には、2本を統合し直す体力も、正しい設計も持ち合わせていませんでした。
一旦、諦めました
4月4日の「リファクタリング」を最後に、WebView2ブランチへのコミットは止まります。ここから約4ヶ月半、このブランチは誰にも触られません。 悔しさより、「今の本体を育てるほうが先だ」という判断が勝ちました。
本体だけが、どんどん育っていく数ヶ月
WebView2を脇に置いている間、Chromium制御ツールの方は劇的に進化していきます。
5月末〜6月、God クラス解体で CDPBrowser / CDPContext / CDPCore に責務が割れ、RaiseEvent ベースの配信基盤が整いました。これがどれだけ効いたかは、7月の v2.3.0 で証明されます。WinSock を自力実装し、WebSocket という2本目の通信路を、既存クラスにほとんど手を入れずに増設できたのです。
皮肉なことに、「複数の通信路を素直に増やせる土台」は、まさにWebView2に一番欲しかったものでした。それが3月には無く、7月には当たり前のようにできていました。
転機 — たーぼーさんからの一通の報告
そろそろプログラミング作業から一区切り置こうかと考えていた、8月のある日。WebView2記事の書き手であるたーぼーさんから、こんな報告をいただきました。
「ページ自動制御の土台ができました」
その一文を読んだ瞬間、こう思いました。
「いまなら、あのWebView2ブランチ、復活できそうじゃね😳😳」
ちょうど新作ゲームスプラトゥーン レイダースにどっぷり浸かり始めていた時期でしたが、そっちのけでWebView2の再配線工事に取りかかることにしました。
再配線工事 — 実質、1からやり直し
いざブランチを掘り起こしてみると、想像以上の作業になりました。3月から半年近く経つ間に、本体側は
CDPBrowser/CDPContext/CDPCoreへの God クラス解体BiDiCDPJsonによるJSONゼロコピー化- WinSock自力実装
と、原型を留めないほど作り変えられていました。3月に書いた WebView2Browser を、その上にそのまま接ぎ木することはできません。コード構成としては、実質1からのやり直しでした。
救いだったのは、この半年でAIを使ったコーディングの精度が上がっていたことです。CDPコマンドの送受信を担う CallDevToolsProtocolMethodForSession まわりの部品調達は、AIに相談しながら比較的スムーズに揃えられました。
もう1つ、WebView2ならではの壁がありました。Pipe や WebSocket は「バイト列の断片が何回かに分かれて届く」前提でバッファを組んでいましたが、WebView2はCOMコールバック経由で 「1つの完成したJSONが一発で丸ごと届く」 という、全く違う配送のされ方をします。
2026-08-25 バインバイン以外の拡張ロジックにも対応させるこのコミットで、CDPCore.cls のバッファ拡張ロジックに、WebView2のこの配送パターンにも対応できる分岐を追加しました。「足りなくなったら倍々に拡張する」という、これまで通用していた前提が、WebView2相手には必ずしも当てはまらなかったということです。
第三のルート、開通
そうして、Pipe・WebSocketに続く3つ目の通信路として、WebView2がこのツールに合流しました。

▲ Excel.exe の配下に直接 WebView2 プロセスが生成されています

▲ Access.exe の配下にも直接 WebView2 プロセスが生成されています
特にAccessはシュールです🤠
「Access公式の表ルート」 と 「vtableハックによる裏ルート」 という、本来絶対に交わらないはずの2つの世界が同時に生きて動いています。
1. 🟠 公式ルート(Access純正 Edgeブラウザコントロール)
- 仕組み: Accessのリボンにある公式の地球儀アイコン(Edgeブラウザコントロール)をフォームにペタッと配置した正規ルート。
- 表示しているページ: なぜか 「Selenium」 の公式サイト。
2. 🟢 非公式ルート(密輸UserForm + WebView2Thunks.bas)
- 仕組み: Excelから密輸したUserFormに、動的FrameハックでHWNDを掴み、C++の仮想関数テーブル(vtable)を直撃して召喚した完全な裏口ルート。
- 表示しているページ: なぜか 「Playwright」 のドキュメント。
タスクマネージャーが語る「動かぬ証拠」
右側のタスクマネージャーを見てください。
- 緑枠:
WebView2: Selenium➔ 公式Edgeコントロールが抱えるWebView2プロセス群 - オレンジ枠:
WebView2: WebView2 | Playwright➔ 私がvtableハックで呼び出した真WebView2プロセス群
Microsoft Access というたった1つのアプリの胃袋の中で、 「公式の安全なおもちゃ(Selenium表示)」 と 「素手でハックした生WebView2(Playwright表示)」 が、 お互いに干渉することもなく平然と2系統並走しています。
「公式コントロールがあるなら、公式を使えばいいじゃない」 ……普通の人はそう思います。
でも、左下の起動引数を見てください。
AutomationDeclaration(自動化サイン)BotDetectionAvoidance(ボット検知回避)--test-type=AccessVBA(任意の起動引数)
公式コントロールでは絶対に触らせてもらえない「CDP(生DevTools)による深淵の制御」 をやるためには、この非公式ルート(vtableハック)で真のWebView2を召喚するしかなかったのです。
公式の表玄関から入ったSeleniumと、
床をブチ抜いて地下から侵入したPlaywright。
Accessの画面上でこの2つが仲良く並んでブラウジングしている光景、 何度見ても技術的シュールさの極みでニヤニヤが止まりません。
到達点
あくまでもCDPツールとして作っているため、WebView2固有の高レベルメソッドはほとんど用意していません。ですが正直なところ、CDPだけでほぼ賄えます。 CDPContext.navigate や CDPElement.getElementByQuery など、Pipe / WebSocket でおなじみの操作が、埋め込んだWebView2に対してもそのまま使えます。
唯一CDPの外側にあるのが、ICoreWebView2Settings(コンテキストメニューの有効/無効など)や ICoreWebView2Controller(表示サイズ・位置)のような、「Web領域の外側」の設定です。CDPはあくまでWeb(ページの中身)を制御するプロトコルなので、こういったホスト側の挙動までは届きません。
とはいえ、これも大した負担ではありませんでした。必要になるたびAIに頼んで、数行のプロシージャを1つ足すだけ。Visible / DevToolsEnabled / ContextMenuEnabled といったプロパティは、そうやって都度増設したものです。
そう思っていた矢先、開通したばかりの第三のルートに、最初の穴が見つかります。
拡張機能という落とし穴(v3.1.0)
v3.0.0 をマージした直後、いろいろ試していた中で気づきました。拡張機能まわりのCDPコマンドだけ、WebView2経路で軒並みMethod not availableになる。
2026-09-01 拡張機能インストール経路を確保
2026-09-01 拡張機能のアンインストール経路を確保Pipe・WebSocketでは何の問題もなく通る Extensions.loadUnpacked が、WebView2相手だとエラーで弾かれる。おそらく内部的に Page 単位のセッションとして実行されているせいだろう、というのが実機を触っての推測でした。CDPで完結しないなら、WebView2 SDK側が持つ拡張機能専用のAPIを直接叩くしかありません。
ところが、そのAPIを使うには「拡張機能を有効化する」という設定を、WebView2プロセスを起動する前に渡しておく必要がありました。しかもその設定の渡し方が厄介でした。ICoreWebView2EnvironmentOptions という、これまた IUnknown ベースのCOMインターフェースを、こちらから丸ごと実装してWebView2側に渡す必要があったのです。
2026-09-01 `EnvironmentOptions`の実装
2026-09-01 `TargetCompatibleBrowserVersion`の既定値を設定するようにするこの物語の前半で組み上げたvtable偽造の技法を、今度は「コールバックを受け取る側」ではなく「設定を聞かれたら答える側」として使う番でした。空文字のままだとE_INVALIDARGで即死するTargetCompatibleBrowserVersionのような、実機で1つずつ踏んで確かめた落とし穴もありましたが、WebView2EnvOptions.clsとして無事に形にできました。

ついでに全部載せてしまう🤪
vtableを1つ組み上げる大変さを味わったあとだと、不思議な達観が生まれます。
「ここまでやったんだから、他のインターフェースも、スカラー値だけならついでに全部繋いじゃえばいいのでは😳」
2026-09-05 `ICoreWebView2Environment`にてスカラー値で取れるプロパティメソッドを追加
2026-09-05 残りの`ICoreWebView2`で取れるスカラー値系プロパティメソッドを追加
2026-09-05 残りの`ICoreWebView2Profile`で取れるスカラー値系プロパティメソッドを追加
2026-09-05 残りの`ICoreWebView2Controller`で取れるスカラー値系プロパティメソッドを追加ICoreWebView2 / ICoreWebView2Controller / ICoreWebView2Environment / ICoreWebView2Settings / ICoreWebView2Profile ――拡張機能のために触ったインターフェース群のvtableさえ整えば、コールバックもイベントも要らないただのGet/Letプロパティは、驚くほど追加コストが低いとわかったのです。ズーム倍率、既定ダウンロード先、プロファイル名、ステータスバーの文言……気づけば、CDPの外側にあるWebView2固有の設定が一通り触れるようになっていました。
もちろん、際限なく広げたわけではありません。線引きはこの3つです。
- 完了コールバックが必要なメソッド
- イベント系(CDPの
Page.*等で代替できるため) - 他のインターフェースへネストして依存するもの
到達点(v3.1.0)
1週間前に「CDPだけでほぼ賄えます」と書いたばかりでしたが、その「ほぼ」の穴(拡張機能)を塞ぎに行ったら、ついでに6つのインターフェースが全部繋がってしまいました。AddBrowserExtension / GetBrowserExtensionIds / RemoveBrowserExtension という3つの専用APIと、EnvironmentOptionsという起動前設定の窓口。詳しい使い方は WebView2モードでできること にまとめています。
結論 — 半年寝かせた種は、腐っていなかった
3月に諦めかけたブランチは、8月にはちゃんと芽を出し、その1週間後には拡張機能というおまけまで持ってきました。理由は単純です。本体側が、新しい通信路を受け止められるだけの土台に育っていたから。 蒔いた種そのものより、畑(本体の設計)を耕し続けたことのほうが、結果的にものを言った気がしています。
フィナーレ
ブレイクスルーの記事を教えてくれ、Wv2Thunks.bas という土台まで公開してくれた、たーぼーさんに改めて感謝します。あなたの一言の報告がなければ、このブランチはもうしばらく凍ったままだったはずです。
次に読む
- このツールの誕生秘話 — 半年前に埋めた種を掘り起こす(v3.0.0)
- WebView2モードの設計思想について — 機械語サンク・vtableの技術詳細
- WebView2モードでできること — 拡張機能・
EnvironmentOptionsの使い方 - Excel単独で「真のWebView2」を完全制御する

