WebView2
WebView2
The Microsoft Edge WebView2 control enables you to host web content in your application using Microsoft Edge (Chromium) as the rendering engine. For more information, see Overview of Microsoft Edge WebView2 and Getting Started with WebView2.
The WebView2 Runtime is built into Win10(latest version) and Win11 and can be easily used in AHK.
This library contains all the interfaces of webview2(version 1.0.992.28).
Download on GitHub
The WebView2 Runtime is built into Win10(latest version) and Win11 and can be easily used in AHK.
This library contains all the interfaces of webview2(version 1.0.992.28).
Download on GitHub
Last edited by thqby on 11 Jan 2023, 19:13, edited 1 time in total.
Re: 2.0-beta.1 - WebView2
Example1: AddHostObjectToEdge, Open with multiple windows
Run code in Edge DevTools
Example2: Open with only one Tab
Example3: Open with multiple Tabs in a window and Auto resize
Example4: PrintToPdf and wait for asynchronous event
Code: Select all
#Include <WebView2\WebView2>
main := Gui('+Resize')
main.OnEvent('Close', (*) => (wvc := wv := 0))
main.Show(Format('w{} h{}', A_ScreenWidth * 0.6, A_ScreenHeight * 0.6))
wvc := WebView2.create(main.Hwnd)
wv := wvc.CoreWebView2
wv.Navigate('https://autohotkey.com')
wv.AddHostObjectToScript('ahk', {str:'str from ahk',func:MsgBox})
wv.OpenDevToolsWindow()
Code: Select all
obj = await window.chrome.webview.hostObjects.ahk;
obj.func('call "MsgBox" from edge\n' + (await obj.str));
Code: Select all
#Include <WebView2\WebView2>
main := Gui("+Resize")
main.OnEvent("Close", ExitApp)
main.Show(Format("w{} h{}", A_ScreenWidth * 0.6, A_ScreenHeight * 0.6))
wvc := WebView2.create(main.Hwnd)
wv := wvc.CoreWebView2
nwr := wv.NewWindowRequested(NewWindowRequestedHandler)
wv.Navigate('https://autohotkey.com')
NewWindowRequestedHandler(handler, wv2, arg) {
argp := WebView2.NewWindowRequestedEventArgs(arg)
deferral := argp.GetDeferral()
argp.NewWindow := wv2
deferral.Complete()
}
Code: Select all
#Include <WebView2\WebView2>
main := Gui("+Resize"), main.MarginX := main.MarginY := 0
main.OnEvent("Close", _exit_)
main.OnEvent('Size', gui_size)
tab := main.AddTab2(Format("w{} h{}", A_ScreenWidth * 0.6, A_ScreenHeight * 0.6), ['tab1'])
tab.UseTab(1), tabs := []
tabs.Push(ctl := main.AddText('x0 y25 w' (A_ScreenWidth * 0.6) ' h' (A_ScreenHeight * 0.6)))
tab.UseTab()
main.Show()
ctl.wvc := wvc := WebView2.create(ctl.Hwnd)
wv := wvc.CoreWebView2
ctl.nwr := wv.NewWindowRequested(NewWindowRequestedHandler)
wv.Navigate('https://autohotkey.com')
gui_size(GuiObj, MinMax, Width, Height) {
if (MinMax != -1) {
tab.Move(, , Width, Height)
for t in tabs {
t.move(, , Width, Height - 23)
try t.wvc.Fill()
}
}
}
NewWindowRequestedHandler(handler, wv2, arg) {
argp := WebView2.NewWindowRequestedEventArgs(arg)
deferral := argp.GetDeferral()
tab.Add(['tab' (i := tabs.Length + 1)])
tab.UseTab(i), tab.Choose(i)
main.GetClientPos(,,&w,&h)
tabs.Push(ctl := main.AddText('x0 y25 w' w ' h' (h - 25)))
tab.UseTab()
ctl.wvc := WebView2.create(ctl.Hwnd, ControllerCompleted_Invoke, WebView2.Core(wv2).Environment)
return 0
ControllerCompleted_Invoke(wvc) {
argp.NewWindow := wv := wvc.CoreWebView2
ctl.nwr := wv.NewWindowRequested(NewWindowRequestedHandler)
deferral.Complete()
}
}
_exit_(*) {
for t in tabs
t.wvc := t.nwr := 0
ExitApp()
}
Code: Select all
#Include <WebView2\WebView2>
g := Gui()
g.Show('w800 h600')
wvc := WebView2.create(g.Hwnd)
wv := wvc.CoreWebView2
wv.Navigate('https://autohotkey.com')
MsgBox('Wait for loading to complete')
PrintToPdf(wv, A_ScriptDir "\11.pdf")
PrintToPdf(wv, path) {
set := wv.Environment.CreatePrintSettings()
set.Orientation := WebView2.PRINT_ORIENTATION.LANDSCAPE
waitting := true, t := A_TickCount
wv.PrintToPdf(A_ScriptDir '\11.pdf', set, WebView2.Handler(handler))
while waitting && A_TickCount - t < 5000
Sleep(20)
if waitting
MsgBox "printtopdf timeout"
else {
Run(A_ScriptDir "\11.pdf")
MsgBox ("printtopdf complete")
}
handler(handlerptr, result, success) {
waitting := false
if (!success)
MsgBox 'PrintToPdf fail`nerr: ' result
}
}
Last edited by thqby on 31 Dec 2021, 08:24, edited 3 times in total.
-
- Posts: 139
- Joined: 26 Jan 2016, 16:05
Re: 2.0-beta.1 - WebView2
@thqby,
This is amazing work! It works great - and im so excited to start building with it!
Any plans to implement:
https://docs.microsoft.com/en-us/dotnet ... ntSettings_
I would be forever in your debt if you could make that possible!
-tre4
This is amazing work! It works great - and im so excited to start building with it!
Any plans to implement:
https://docs.microsoft.com/en-us/dotnet ... ntSettings_
I would be forever in your debt if you could make that possible!
-tre4
Re: 2.0-beta.1 - WebView2
ICoreWebView2Experimental7::PrintToPdf method is implemented in this version 1.0.1018-prerelease.
It is intended to be updated after the official release.
It is intended to be updated after the official release.
-
- Posts: 144
- Joined: 01 Feb 2017, 22:57
Re: 2.0-beta.1 - WebView2
Very nice.
Does WebView2 have any current limitations as compared with the IE webbrowser control?
Does WebView2 have any current limitations as compared with the IE webbrowser control?
Re: 2.0-beta.1 - WebView2
You need to install dependencies, such as edge dev or edge runtime, to support systems above win7.
In win11, runtime is built-in.
In latest win10, runtime may be pre installed by other software. Office 365 began using webview2 to render some gui.
IE webview may not support some modern web technologies, while webview2 does not.
In win11, runtime is built-in.
In latest win10, runtime may be pre installed by other software. Office 365 began using webview2 to render some gui.
IE webview may not support some modern web technologies, while webview2 does not.
Re: 2.0-beta.1 - WebView2
Have you figured out working with AHK arrays in JavaScript via AddHostObjectToScript?
-
- Posts: 139
- Joined: 26 Jan 2016, 16:05
Re: 2.0-beta.1 - WebView2
@kczx3 -
What do you mean by that? Im able to send arrays from JS -> ahk and vice versa using this lib(as JSON strings)
What do you mean by that? Im able to send arrays from JS -> ahk and vice versa using this lib(as JSON strings)
Re: 2.0-beta.1 - WebView2
Sending via JSON is unrelated to sharing of host objects via the AddHostObjectToScript method. JSON is serialized and reconstructed instead of sending an AHK array directly.
-
- Posts: 139
- Joined: 26 Jan 2016, 16:05
Re: 2.0-beta.1 - WebView2
Understood. What would the major benefits be of accessing the ahk arrays directly? Performance? I suppose for my use cases serializing the data is more than sufficient.
Re: 2.0-beta.1 - WebView2
I think one benefit would being able to modify the AHK array from the JS side since its sent ByRef.
-
- Posts: 144
- Joined: 01 Feb 2017, 22:57
Re: 2.0-beta.1 - WebView2
Thanks for the explanation.thqby wrote: ↑20 Oct 2021, 06:05You need to install dependencies, such as edge dev or edge runtime, to support systems above win7.
In win11, runtime is built-in.
In latest win10, runtime may be pre installed by other software. Office 365 began using webview2 to render some gui.
IE webview may not support some modern web technologies, while webview2 does not.
-
- Posts: 144
- Joined: 01 Feb 2017, 22:57
Re: 2.0-beta.1 - WebView2
Tre4shunter wrote: ↑20 Oct 2021, 08:57Understood. What would the major benefits be of accessing the ahk arrays directly? Performance? I suppose for my use cases serializing the data is more than sufficient.
I've tried to get this to work with IE browser control as I needed to reflect some data back into the DOM, motivated by the prospect of increased performance. In the end, it turns out that in my case at least, direct DOM manipulation is more performant when done directly from AHK than from JS, even setting aside the time needed to stringify in AHK and to parse in JS. The exact same set of createElement / appendChild / setAttribute operations take less time to complete in AHK than in JS
Also, FWIW, when I use ObjRegisterActive to share an array between 2 ahk scripts, hoping script A can pass the array to script B and say "do some computation on this so I can be freed to do something else", I found that there's actually a decrease in overall performance, because apparently each time script B accesses an item from the array this is forwarded as a call back to script A, so script A is not actually "freed to do something else". I wonder if that would also be the case if JS accesses the shared array?
Re: 2.0-beta.1 - WebView2
Unless you specifically access the data from the host synchronously, everything from the JS side is asynchronous. The host script obviously has to handle the property get/set or method call though. At some level, the host isn't entirely "freed".
-
- Posts: 144
- Joined: 01 Feb 2017, 22:57
Re: 2.0-beta.1 - WebView2
It looks like one limitation of Webview2 compared to the IE control is .... there's no (native) DOM manipulation any more.
https://github.com/MicrosoftEdge/WebView2Feedback/issues/176
https://github.com/MicrosoftEdge/WebView2Feedback/issues/176
Oops, no DOM access anymore? (Last time I used this was with the IE-based control. I only come back to this when there's a proper HTML engine behind this, what WebView2 seems to be.) I need to disable JavaScript on the content for security reasons. How can I edit and manipulate the HTML content then? Is this impossible? If I wanted to use JavaScript to manipulate the HTML on the page, I'd be using Electron or another framework that lets me write my application in JavaScript altogether.
Last edited by 20170201225639 on 20 Oct 2021, 12:00, edited 1 time in total.
-
- Posts: 144
- Joined: 01 Feb 2017, 22:57
Re: 2.0-beta.1 - WebView2
Thanks. Yes, the JS side computation on the array items is asychronous, it's the accessing of the items that isn't. I do wonder: is there a way, theoretically, to free the host from having to handle get operation for built-in data structures like arrays?
I can see how for a custom object the host script must handle the get calls, because the client script doesn't know how otherwise. But if both host and client are AHK scripts they should both understand arrays from the get-go.
(I wonder about this, because otherwise the performance costs involved in repeated get calls during loops would mean there's a lot less use cases for object sharing between scritps at least for me personally)
-
- Posts: 139
- Joined: 26 Jan 2016, 16:05
Re: 2.0-beta.1 - WebView2
I modifed the Neutron Bootstrap Example just as an exercise to see if i could 'replicate' how it worked. This is what i came up with.
Please correct anything i did grossly incorrect/inneficiently as i am still very green with the whole Webview2 and ahkV2 syntaxes. It does work though.
ah2
html
can grab the other files, css/js etc from the neutron bootstrap github. These are the only things i modified.
Thanks!
Please correct anything i did grossly incorrect/inneficiently as i am still very green with the whole Webview2 and ahkV2 syntaxes. It does work though.
ah2
Code: Select all
Persistent
#SingleInstance
#Include "<JSON>"
#Include WebView2.ahk
main := Gui('+Resize'), main.MarginX := main.MarginY := 0
main.Title := "Webview2 Test"
main.OnEvent('Size', gui_size)
main.OnEvent('Close', (*) => (wvc := wv := 0))
main.Show(Format('w{} h{}', A_ScreenWidth * 0.6, A_ScreenHeight * 0.6))
wvc := WebView2.create(main.Hwnd, , 0, "", A_ScriptDir "\Runtime")
main.GetClientPos(,,&w,&h)
ctl := main.AddText('x0 y25 w' w ' h' (h - 25))
wv := wvc.CoreWebView2
wv.Navigate('file:///' A_ScriptDir '\bootstrap.html')
boundbtns := ButtonsFromHTML.Bind()
boundform := FormFromHTML.Bind()
wv.AddHostObjectToScript('btnsToAHK', {Func:boundbtns})
wv.AddHostObjectToScript('formdataToAHK', {Func:boundform})
ButtonsFromHTML(p*){
msgbox('You clicked: ' p[1])
}
FormFromHTML(p*){
rVal := p[1]
items := JxonDecode(&rVal)
for k,v in items
{
if(v)
msgbox(k "`n" v)
}
msgbox('Now lets send some data From AHK to JS.')
testArr:=['one','two','three']
wv.ExecuteScript("alert(" JxonEncode(testArr) ")",myHandler(wv,arg:=0))
return 0
myHandler(wv,arg){
return(0)
}
}
gui_size(GuiObj, MinMax, Width, Height) {
if (MinMax != -1) {
try ctl.Move(, , Width, Height - 23)
try wvc.Fill()
}
}
_exit_(*) {
ExitApp()
}
Code: Select all
<!DOCTYPE html>
<html>
<head>
<!--
The IE Compatibility flag, while not always necessary, makes sure your page
will always load in IE11+ rendering mode instead of being limited to IE7
features and behaviors. While IE11 is still relatively old as a rendering
engine, it supports the most fundamental parts needed for modern webpages to
function correctly.
Neutron will do its best to enable IE11+ rendering mode regardless of this
tag, but in current releases pages will not render correctly when compiled
unless this tag is present. Because of that and other edge cases, any page
you write to load in Neutron should contain this meta tag.
-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="bootstrap.min.css" rel="stylesheet">
<script src="jquery.min.js"></script>
<script src="bootstrap.min.js"></script>
<style>
html,
body {
width: 100%;
height: 100%;
}
.title-btn {
padding: 0.35em 1.0em;
cursor: pointer;
vertical-align: bottom;
font-family: Webdings;
font-size: 11pt;
}
.title-btn:hover {
background: rgba(0, 0, 0, .2);
}
.title-btn-close:hover {
background: #dc3545;
}
</style>
</head>
<body class="d-flex flex-column">
<!-- Title Bar
<header>
<div class="d-flex align-items-stretch bg-dark text-white">
<span class="flex-grow-1 px-2 py-1" onmousedown="neutron.DragTitleBar()">AutoHotkey</span>
<span class="title-btn" onclick="neutron.Minimize()">0</span>
<span class="title-btn" onclick="neutron.Maximize()">1</span>
<span class="title-btn title-btn-close" onclick="neutron.Close()">r</span>
</div>
</header>
End Title Bar -->
<!-- Window Contents -->
<div class="flex-grow-1 d-flex">
<!-- Sidebar -->
<div class="nav flex-column nav-pills bg-dark text-light" id="v-pills-tab" role="tablist"
aria-orientation="vertical">
<a class="nav-link text-light active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab"
aria-controls="v-pills-home" aria-selected="true">Home</a>
<a class="nav-link text-light" id="v-pills-buttons-tab" data-toggle="pill" href="#v-pills-buttons" role="tab"
aria-controls="v-pills-buttons" aria-selected="false">Buttons</a>
<a class="nav-link text-light" id="v-pills-forms-tab" data-toggle="pill" href="#v-pills-forms" role="tab"
aria-controls="v-pills-forms" aria-selected="false">Forms</a>
<a class="nav-link text-light" id="v-pills-settings-tab" data-toggle="pill" href="#v-pills-settings" role="tab"
aria-controls="v-pills-settings" aria-selected="false">Settings</a>
</div>
<!-- End Sidebar -->
<!-- Page Content -->
<div class="flex-grow-1 overflow-auto">
<div class="tab-content container p-2" id="v-pills-tabContent">
<!-- v-pills-home -->
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
<h1>Welcome to Neutron</h1>
<p>
Neutron provides a powerful set of tools for build HTML-based user interfaces with AutoHotkey. It leverages
the Trident engine, known for its use in Internet Explorer, because of its deep integration with the
Microsoft Windows operating system and its wide availability across systems.
</p>
<p>
This example is designed to show how you can use third party frameworks like Bootstrap to build advanced
user interfaces, while still keeping all the code local. This script can be compiled and still function
fine without the need to extract any files to a temporary directory.
</p>
<p>
As this example is more advanced, it assumes a stronger familiarity with the technology and may gloss over
some parts more than other examples. If you're just getting started it may be helpful to work with some of
the other example scripts first.
</p>
</div>
<!-- End v-pills-home -->
<!-- v-pills-buttons -->
<div class="tab-pane fade" id="v-pills-buttons" role="tabpanel" aria-labelledby="v-pills-buttons-tab">
<h1>Buttons!</h1>
<h2>Colored Buttons:</h2>
<div class="btns_to_trigger_ahk">
<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-secondary">Secondary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-light">Light</button>
<button type="button" class="btn btn-dark">Dark</button>
<button type="button" class="btn btn-link">Link</button>
<h2>Outline Buttons:</h2>
<button type="button" class="btn btn-outline-primary">Primary</button>
<button type="button" class="btn btn-outline-secondary">Secondary</button>
<button type="button" class="btn btn-outline-success">Success</button>
<button type="button" class="btn btn-outline-danger">Danger</button>
<button type="button" class="btn btn-outline-warning">Warning</button>
<button type="button" class="btn btn-outline-info">Info</button>
<button type="button" class="btn btn-outline-light">Light</button>
<button type="button" class="btn btn-outline-dark">Dark</button>
<button type="button" class="btn btn-outline-link">Link</button>
<h2>Block Buttons:</h2>
<button type="button" class="btn btn-block btn-primary">Block level
button</button>
<button type="button" class="btn btn-block btn-outline-primary">Block level
button</button>
</div>
</div>
<!-- End v-pills-buttons -->
<!-- v-pills-forms -->
<div class="tab-pane fade" id="v-pills-forms" role="tabpanel" aria-labelledby="v-pills-forms-tab">
<h1>Forms!</h1>
<form>
<div class="form-row">
<div class="form-group col-md-6">
<label for="inputEmail">Email</label>
<input type="email" class="form-control" id="inputEmail" placeholder="Email" required>
</div>
<div class="form-group col-md-6">
<label for="inputPassword">Password</label>
<input type="password" class="form-control" id="inputPassword" placeholder="Password" required>
</div>
</div>
<div class="form-group">
<label for="inputAddress">Address</label>
<input type="text" class="form-control" id="inputAddress" placeholder="1234 Main St">
</div>
<div class="form-group">
<label for="inputAddress2">Address 2</label>
<input type="text" class="form-control" id="inputAddress2" placeholder="Apartment, studio, or floor">
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="inputCity">City</label>
<input type="text" class="form-control" id="inputCity">
</div>
<div class="form-group col-md-4">
<label for="inputState">State</label>
<select id="inputState" class="form-control">
<option selected>Choose...</option>
<option>...</option>
</select>
</div>
<div class="form-group col-md-2">
<label for="inputZip">Zip</label>
<input type="text" class="form-control" id="inputZip">
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="gridCheck">
<label class="form-check-label" for="gridCheck">
Check me out
</label>
</div>
</div>
<button class="btn btn-primary">Sign in</button>
</form>
</div>
<!-- End v-pills-forms -->
<!-- v-pills-settings -->
<div class="tab-pane fade" id="v-pills-settings" role="tabpanel" aria-labelledby="v-pills-settings-tab">
Settings
</div>
<!-- End v-pills-settings -->
</div>
</div>
<!-- End Page Contents -->
</div>
<!-- End Window Contents -->
</body>
<script>
var btns = document.querySelectorAll('.btns_to_trigger_ahk button')
for(i=0;i<btns.length;i++){
btns[i].addEventListener('click',() => getBtns(this,event), false)
}
async function getBtns(t,e){
obj1 = await window.chrome.webview.hostObjects.btnsToAHK;
obj1.func(e.target.innerText);
}
</script>
<script>
document.querySelector('#v-pills-forms > form').addEventListener("submit", () => getForm(this,event), true)
async function getForm(t,e){
e.preventDefault(); // before the code
var FormData = Object()
var els = document.querySelector('form').elements;
for(i=0;i<els.length;i++){
var name = els[i].name
if (name !== '')
FormData[els[i].name] = els[i].value
else
FormData[els[i].id] = els[i].value
}
obj = await window.chrome.webview.hostObjects.formdataToAHK;
obj.func(JSON.stringify(FormData));
}
</script>
</html>
Thanks!
Re: 2.0-beta.1 - WebView2
Why are you calling bind on the functions but not... binding anything?
-
- Posts: 139
- Joined: 26 Jan 2016, 16:05
Re: 2.0-beta.1 - WebView2
well, because like i said....i really am just fumbling my way through this. Its the only way i could get it to work