5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-04 07:43:11 +08:00
wails/v2/internal/frontend/desktop/windows/go-webview2/webviewloader/module.go
stffabi 884773a218
[v2, windows] Fix WebView2 minimum runtime version check (#1456)
* [v2, windows] CompareBrowserVersions needs a int32 pointer

Otherwise 4294967295 will be returned instead of -1 and the
minimum version check can't detect an older version.
So an older version than the minimum might be used and will
result in AccessViolationExceptions.

* [v2, windows] Use the correct minimum runtime version for SDK 1.0.992.28

The Webview2Loader.dll are already at version 1.0.992.28 for all platforms.
2022-06-16 18:43:19 +10:00

115 lines
3.2 KiB
Go

package webviewloader
import (
"fmt"
"sync"
"unsafe"
"github.com/jchv/go-winloader"
"golang.org/x/sys/windows"
)
var (
memOnce sync.Once
memModule winloader.Module
memCreate winloader.Proc
memCompareBrowserVersions winloader.Proc
memGetAvailableCoreWebView2BrowserVersionString winloader.Proc
memErr error
)
const (
// https://referencesource.microsoft.com/#system.web/Util/hresults.cs,20
E_FILENOTFOUND = 0x80070002
)
// CompareBrowserVersions will compare the 2 given versions and return:
// Less than zero: v1 < v2
// zero: v1 == v2
// Greater than zero: v1 > v2
func CompareBrowserVersions(v1 string, v2 string) (int, error) {
_v1, err := windows.UTF16PtrFromString(v1)
if err != nil {
return 0, err
}
_v2, err := windows.UTF16PtrFromString(v2)
if err != nil {
return 0, err
}
err = loadFromMemory()
if err != nil {
return 0, err
}
var result int32
_, _, err = memCompareBrowserVersions.Call(
uint64(uintptr(unsafe.Pointer(_v1))),
uint64(uintptr(unsafe.Pointer(_v2))),
uint64(uintptr(unsafe.Pointer(&result))))
if err != windows.ERROR_SUCCESS {
return 0, err
}
return int(result), nil
}
// GetInstalledVersion returns the installed version of the webview2 runtime.
// If there is no version installed, a blank string is returned.
func GetInstalledVersion() (string, error) {
err := loadFromMemory()
if err != nil {
return "", err
}
var result *uint16
res, _, err := memGetAvailableCoreWebView2BrowserVersionString.Call(
uint64(uintptr(unsafe.Pointer(nil))),
uint64(uintptr(unsafe.Pointer(&result))))
if res != 0 {
if res == E_FILENOTFOUND {
// Webview2 is not installed
return "", nil
}
return "", fmt.Errorf("Unable to call GetAvailableCoreWebView2BrowserVersionString (%x): %w", res, err)
}
version := windows.UTF16PtrToString(result)
windows.CoTaskMemFree(unsafe.Pointer(result))
return version, nil
}
// CreateCoreWebView2EnvironmentWithOptions tries to load WebviewLoader2 and
// call the CreateCoreWebView2EnvironmentWithOptions routine.
func CreateCoreWebView2EnvironmentWithOptions(browserExecutableFolder, userDataFolder *uint16, environmentOptions uintptr, environmentCompletedHandle uintptr) (uintptr, error) {
err := loadFromMemory()
if err != nil {
return 0, err
}
res, _, _ := memCreate.Call(
uint64(uintptr(unsafe.Pointer(browserExecutableFolder))),
uint64(uintptr(unsafe.Pointer(userDataFolder))),
uint64(environmentOptions),
uint64(environmentCompletedHandle),
)
return uintptr(res), nil
}
func loadFromMemory() error {
var err error
// DLL is not available natively. Try loading embedded copy.
memOnce.Do(func() {
memModule, memErr = winloader.LoadFromMemory(WebView2Loader)
if memErr != nil {
err = fmt.Errorf("Unable to load WebView2Loader.dll from memory: %w", memErr)
return
}
memCreate = memModule.Proc("CreateCoreWebView2EnvironmentWithOptions")
memCompareBrowserVersions = memModule.Proc("CompareBrowserVersions")
memGetAvailableCoreWebView2BrowserVersionString = memModule.Proc("GetAvailableCoreWebView2BrowserVersionString")
})
return err
}