5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 20:51:38 +08:00

[webviewloader] Use go implementation to retrieve the version of a fixed runtime (#1790)

* [webview2loader] Start porting of OpenWebView2Loader to go

* [webviewloader] Use go implementation to retrieve the version of a fixed runtime

This fixes a problem with the go-winloader and using GetAvailableCoreWebView2BrowserVersionString

Fixes #1569

Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
This commit is contained in:
stffabi 2022-08-27 01:29:09 +02:00 committed by GitHub
parent bbfb64a965
commit 3632ef9dc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 249 additions and 3 deletions

View File

@ -0,0 +1,16 @@
ISC License (ISC)
Copyright (c) 2020 John Chadwick
Copyright (c) 2022 Wails Project Developers
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,15 @@
# GoWebView2Loader
GoWebView2Loader is a port of [OpenWebView2Loader](https://github.com/jchv/OpenWebView2Loader) to Go.
It is intended to be feature-complete in the near future with the original WebView2Loader distributed with
the WebView2 NuGet package.
## Status
- [ ] CompareBrowserVersions
- [ ] CreateCoreWebView2Environment
- [ ] CreateCoreWebView2EnvironmentWithOptions
- [ ] GetAvailableCoreWebView2BrowserVersionString
- [ ] Feature Complete
- [x] Fixed Runtime support

View File

@ -0,0 +1,128 @@
package webview2loader
import (
"fmt"
"syscall"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
)
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
procGlobalFree = modkernel32.NewProc("GlobalFree")
modversion = windows.NewLazySystemDLL("version.dll")
procGetFileVersionInfoSize = modversion.NewProc("GetFileVersionInfoSizeW")
procGetFileVersionInfo = modversion.NewProc("GetFileVersionInfoW")
procVerQueryValue = modversion.NewProc("VerQueryValueW")
)
func getFileVersionInfo(path string) ([]byte, error) {
lptstrFilename, err := syscall.UTF16PtrFromString(path)
if err != nil {
return nil, err
}
size, _, err := procGetFileVersionInfoSize.Call(
uintptr(unsafe.Pointer(lptstrFilename)),
0,
)
err = maskErrorSuccess(err)
if size == 0 && err == nil {
err = fmt.Errorf("GetFileVersionInfoSize failed")
}
if err != nil {
return nil, err
}
data := make([]byte, size)
ret, _, err := procGetFileVersionInfo.Call(
uintptr(unsafe.Pointer(lptstrFilename)),
0,
uintptr(size),
uintptr(unsafe.Pointer(&data[0])),
)
err = maskErrorSuccess(err)
if ret == 0 && err == nil {
err = fmt.Errorf("GetFileVersionInfo failed")
}
if err != nil {
return nil, err
}
return data, nil
}
func verQueryValueString(block []byte, subBlock string) (string, error) {
// Allocate memory from native side to make sure the block doesn't get moved
// because we get a pointer into that memory block from the native verQueryValue
// call back.
pBlock := globalAlloc(0, uint32(len(block)))
defer globalFree(unsafe.Pointer(pBlock))
// Copy the memory region into native side memory
copy(unsafe.Slice((*byte)(pBlock), len(block)), block)
lpSubBlock, err := syscall.UTF16PtrFromString(subBlock)
if err != nil {
return "", err
}
var lplpBuffer unsafe.Pointer
var puLen uint
ret, _, err := procVerQueryValue.Call(
uintptr(pBlock),
uintptr(unsafe.Pointer(lpSubBlock)),
uintptr(unsafe.Pointer(&lplpBuffer)),
uintptr(unsafe.Pointer(&puLen)),
)
err = maskErrorSuccess(err)
if ret == 0 && err == nil {
err = fmt.Errorf("VerQueryValue failed")
}
if err != nil {
return "", err
}
if puLen <= 1 {
return "", nil
}
puLen -= 1 // Remove Null-Terminator
wchar := unsafe.Slice((*uint16)(lplpBuffer), puLen)
return string(utf16.Decode(wchar)), nil
}
func globalAlloc(uFlags uint, dwBytes uint32) unsafe.Pointer {
ret, _, _ := procGlobalAlloc.Call(
uintptr(uFlags),
uintptr(dwBytes))
if ret == 0 {
panic("globalAlloc failed")
}
return unsafe.Pointer(ret)
}
func globalFree(data unsafe.Pointer) {
ret, _, _ := procGlobalFree.Call(uintptr(data))
if ret != 0 {
panic("globalFree failed")
}
}
func maskErrorSuccess(err error) error {
if err == windows.ERROR_SUCCESS {
return nil
}
return err
}

View File

@ -0,0 +1,69 @@
package webview2loader
import (
"fmt"
"os"
"path/filepath"
"runtime"
)
// GetAvailableCoreWebView2BrowserVersionString get the browser version info including channel name.
func GetAvailableCoreWebView2BrowserVersionString(browserExecutableFolder string) (string, error) {
if browserExecutableFolder != "" {
clientPath, err := findEmbeddedClientDll(browserExecutableFolder)
if err != nil {
return "", err
}
return findEmbeddedBrowserVersion(clientPath)
}
return "", fmt.Errorf("not implemented yet for empty browserExecutableFolder ")
}
func findEmbeddedBrowserVersion(filename string) (string, error) {
block, err := getFileVersionInfo(filename)
if err != nil {
return "", err
}
info, err := verQueryValueString(block, "\\StringFileInfo\\040904B0\\ProductVersion")
if err != nil {
return "", err
}
return info, nil
}
func findEmbeddedClientDll(embeddedEdgeSubFolder string) (outClientPath string, err error) {
if !filepath.IsAbs(embeddedEdgeSubFolder) {
exe, err := os.Executable()
if err != nil {
return "", err
}
embeddedEdgeSubFolder = filepath.Join(filepath.Dir(exe), embeddedEdgeSubFolder)
}
return findClientDllInFolder(embeddedEdgeSubFolder)
}
func findClientDllInFolder(folder string) (string, error) {
arch := ""
switch runtime.GOARCH {
case "arm64":
arch = "arm64"
case "amd64":
arch = "x64"
case "386":
arch = "x86"
default:
return "", fmt.Errorf("Unsupported architecture")
}
dllPath := filepath.Join(folder, "EBWebView", arch, "EmbeddedBrowserWebView.dll")
if _, err := os.Stat(dllPath); err != nil {
return "", err
}
return dllPath, nil
}

View File

@ -1,11 +1,15 @@
package webviewloader
import (
"errors"
"fmt"
"os"
"sync"
"unsafe"
"github.com/jchv/go-winloader"
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/go-webview2/webview2loader"
"golang.org/x/sys/windows"
)
@ -28,9 +32,10 @@ const (
)
// CompareBrowserVersions will compare the 2 given versions and return:
// Less than zero: v1 < v2
// zero: v1 == v2
// Greater than zero: v1 > v2
//
// 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 {
@ -62,6 +67,19 @@ func CompareBrowserVersions(v1 string, v2 string) (int, error) {
// If path is empty, it will try to find installed webview2 is the system.
// If there is no version installed, a blank string is returned.
func GetWebviewVersion(path string) (string, error) {
if path != "" {
// The default implementation fails if CGO and a fixed browser path is used. It's caused by the go-winloader
// which loads the native DLL from memory.
// Use the new GoWebView2Loader in this case, in the future we will make GoWebView2Loader
// feature-complete and remove the use of the native DLL and go-winloader.
version, err := webview2loader.GetAvailableCoreWebView2BrowserVersionString(path)
if errors.Is(err, os.ErrNotExist) {
// Webview2 is not found
return "", nil
}
return version, nil
}
err := loadFromMemory()
if err != nil {
return "", err