mirror of
https://github.com/taigrr/wails.git
synced 2026-04-04 22:22:41 -07:00
Compare commits
10 Commits
v2.0.0-bet
...
v2.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cb480f0f0 | ||
|
|
6825a631f5 | ||
|
|
39f91a030f | ||
|
|
202e4d5be8 | ||
|
|
045e58778a | ||
|
|
e375d60c67 | ||
|
|
fcb5499d3a | ||
|
|
dd5a54a8e0 | ||
|
|
9f24a46b8a | ||
|
|
d7eaab97dd |
@@ -1,3 +1,3 @@
|
||||
package internal
|
||||
|
||||
var Version = "v2.0.0-beta.24"
|
||||
var Version = "v2.0.0-beta.27"
|
||||
|
||||
@@ -80,5 +80,3 @@ require (
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
replace github.com/leaanthony/go-webview2 => C:\Users\leaan\Documents\wails-v2-beta\go-webview2
|
||||
|
||||
@@ -118,6 +118,8 @@ github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQ
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v1.0.2 h1:IjTbpAXUig33G3LUqf+8EClZutg2Z/C1cbxqhHKPxbU=
|
||||
github.com/leaanthony/go-webview2 v1.0.2/go.mod h1:iX54IaVk1FnDqMuHJ47VYLPQOcVqQiOe9SJACt9CAbU=
|
||||
github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw=
|
||||
|
||||
BIN
v2/internal/webview2runtime/MicrosoftEdgeWebview2Setup.exe
Normal file
BIN
v2/internal/webview2runtime/MicrosoftEdgeWebview2Setup.exe
Normal file
Binary file not shown.
232
v2/internal/webview2runtime/sudo_mattn.go
Normal file
232
v2/internal/webview2runtime/sudo_mattn.go
Normal file
@@ -0,0 +1,232 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
// Original File (c) 2017 Yasuhiro Matsumoto: https://github.com/mattn/sudo/blob/master/win32.go
|
||||
// License: https://github.com/mattn/sudo/blob/master/LICENSE
|
||||
|
||||
package webview2runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modshell32 = syscall.NewLazyDLL("shell32.dll")
|
||||
procShellExecuteEx = modshell32.NewProc("ShellExecuteExW")
|
||||
)
|
||||
|
||||
const (
|
||||
_SEE_MASK_DEFAULT = 0x00000000
|
||||
_SEE_MASK_CLASSNAME = 0x00000001
|
||||
_SEE_MASK_CLASSKEY = 0x00000003
|
||||
_SEE_MASK_IDLIST = 0x00000004
|
||||
_SEE_MASK_INVOKEIDLIST = 0x0000000C
|
||||
_SEE_MASK_ICON = 0x00000010
|
||||
_SEE_MASK_HOTKEY = 0x00000020
|
||||
_SEE_MASK_NOCLOSEPROCESS = 0x00000040
|
||||
_SEE_MASK_CONNECTNETDRV = 0x00000080
|
||||
_SEE_MASK_NOASYNC = 0x00000100
|
||||
_SEE_MASK_FLAG_DDEWAIT = 0x00000100
|
||||
_SEE_MASK_DOENVSUBST = 0x00000200
|
||||
_SEE_MASK_FLAG_NO_UI = 0x00000400
|
||||
_SEE_MASK_UNICODE = 0x00004000
|
||||
_SEE_MASK_NO_CONSOLE = 0x00008000
|
||||
_SEE_MASK_ASYNCOK = 0x00100000
|
||||
_SEE_MASK_NOQUERYCLASSSTORE = 0x01000000
|
||||
_SEE_MASK_HMONITOR = 0x00200000
|
||||
_SEE_MASK_NOZONECHECKS = 0x00800000
|
||||
_SEE_MASK_WAITFORINPUTIDLE = 0x02000000
|
||||
_SEE_MASK_FLAG_LOG_USAGE = 0x04000000
|
||||
_SEE_MASK_FLAG_HINST_IS_SITE = 0x08000000
|
||||
)
|
||||
|
||||
const (
|
||||
_ERROR_BAD_FORMAT = 11
|
||||
)
|
||||
|
||||
const (
|
||||
_SE_ERR_FNF = 2
|
||||
_SE_ERR_PNF = 3
|
||||
_SE_ERR_ACCESSDENIED = 5
|
||||
_SE_ERR_OOM = 8
|
||||
_SE_ERR_DLLNOTFOUND = 32
|
||||
_SE_ERR_SHARE = 26
|
||||
_SE_ERR_ASSOCINCOMPLETE = 27
|
||||
_SE_ERR_DDETIMEOUT = 28
|
||||
_SE_ERR_DDEFAIL = 29
|
||||
_SE_ERR_DDEBUSY = 30
|
||||
_SE_ERR_NOASSOC = 31
|
||||
)
|
||||
|
||||
type (
|
||||
dword uint32
|
||||
hinstance syscall.Handle
|
||||
hkey syscall.Handle
|
||||
hwnd syscall.Handle
|
||||
ulong uint32
|
||||
lpctstr uintptr
|
||||
lpvoid uintptr
|
||||
)
|
||||
|
||||
// SHELLEXECUTEINFO struct
|
||||
type _SHELLEXECUTEINFO struct {
|
||||
cbSize dword
|
||||
fMask ulong
|
||||
hwnd hwnd
|
||||
lpVerb lpctstr
|
||||
lpFile lpctstr
|
||||
lpParameters lpctstr
|
||||
lpDirectory lpctstr
|
||||
nShow int
|
||||
hInstApp hinstance
|
||||
lpIDList lpvoid
|
||||
lpClass lpctstr
|
||||
hkeyClass hkey
|
||||
dwHotKey dword
|
||||
hIconOrMonitor syscall.Handle
|
||||
hProcess syscall.Handle
|
||||
}
|
||||
|
||||
// ShellExecuteAndWait is version of ShellExecuteEx which want process
|
||||
func ShellExecuteAndWait(hwnd hwnd, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
|
||||
var lpctstrVerb, lpctstrParameters, lpctstrDirectory, lpctstrFile lpctstr
|
||||
var err error
|
||||
if len(lpOperation) != 0 {
|
||||
lpctstrVerb, err = toUTF16(lpOperation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(lpParameters) != 0 {
|
||||
lpctstrParameters, err = toUTF16(lpParameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(lpDirectory) != 0 {
|
||||
lpctstrDirectory, err = toUTF16(lpDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(lpDirectory) != 0 {
|
||||
lpctstrFile, err = toUTF16(lpFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i := &_SHELLEXECUTEINFO{
|
||||
fMask: _SEE_MASK_NOCLOSEPROCESS,
|
||||
hwnd: hwnd,
|
||||
lpVerb: lpctstrVerb,
|
||||
lpFile: lpctstrFile,
|
||||
lpParameters: lpctstrParameters,
|
||||
lpDirectory: lpctstrDirectory,
|
||||
nShow: nShowCmd,
|
||||
}
|
||||
i.cbSize = dword(unsafe.Sizeof(*i))
|
||||
return ShellExecuteEx(i)
|
||||
}
|
||||
|
||||
func toUTF16(lpOperation string) (lpctstr, error) {
|
||||
result, err := syscall.UTF16PtrFromString(lpOperation)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return lpctstr(unsafe.Pointer(result)), nil
|
||||
}
|
||||
|
||||
// ShellExecuteNoWait is version of ShellExecuteEx which don't want process
|
||||
func ShellExecuteNowait(hwnd hwnd, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
|
||||
var lpctstrVerb, lpctstrParameters, lpctstrDirectory, lpctstrFile lpctstr
|
||||
var err error
|
||||
if len(lpOperation) != 0 {
|
||||
lpctstrVerb, err = toUTF16(lpOperation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(lpParameters) != 0 {
|
||||
lpctstrParameters, err = toUTF16(lpParameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(lpDirectory) != 0 {
|
||||
lpctstrDirectory, err = toUTF16(lpDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(lpDirectory) != 0 {
|
||||
lpctstrFile, err = toUTF16(lpFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i := &_SHELLEXECUTEINFO{
|
||||
fMask: _SEE_MASK_DEFAULT,
|
||||
hwnd: hwnd,
|
||||
lpVerb: lpctstrVerb,
|
||||
lpFile: lpctstrFile,
|
||||
lpParameters: lpctstrParameters,
|
||||
lpDirectory: lpctstrDirectory,
|
||||
nShow: nShowCmd,
|
||||
}
|
||||
i.cbSize = dword(unsafe.Sizeof(*i))
|
||||
return ShellExecuteEx(i)
|
||||
}
|
||||
|
||||
// ShellExecuteEx is Windows API
|
||||
func ShellExecuteEx(pExecInfo *_SHELLEXECUTEINFO) error {
|
||||
ret, _, _ := procShellExecuteEx.Call(uintptr(unsafe.Pointer(pExecInfo)))
|
||||
if ret == 1 && pExecInfo.fMask&_SEE_MASK_NOCLOSEPROCESS != 0 {
|
||||
s, e := syscall.WaitForSingleObject(pExecInfo.hProcess, syscall.INFINITE)
|
||||
switch s {
|
||||
case syscall.WAIT_OBJECT_0:
|
||||
break
|
||||
case syscall.WAIT_FAILED:
|
||||
return os.NewSyscallError("WaitForSingleObject", e)
|
||||
default:
|
||||
return errors.New("Unexpected result from WaitForSingleObject")
|
||||
}
|
||||
}
|
||||
errorMsg := ""
|
||||
if pExecInfo.hInstApp != 0 && pExecInfo.hInstApp <= 32 {
|
||||
switch int(pExecInfo.hInstApp) {
|
||||
case _SE_ERR_FNF:
|
||||
errorMsg = "The specified file was not found"
|
||||
case _SE_ERR_PNF:
|
||||
errorMsg = "The specified path was not found"
|
||||
case _ERROR_BAD_FORMAT:
|
||||
errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)"
|
||||
case _SE_ERR_ACCESSDENIED:
|
||||
errorMsg = "The operating system denied access to the specified file"
|
||||
case _SE_ERR_ASSOCINCOMPLETE:
|
||||
errorMsg = "The file name association is incomplete or invalid"
|
||||
case _SE_ERR_DDEBUSY:
|
||||
errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed"
|
||||
case _SE_ERR_DDEFAIL:
|
||||
errorMsg = "The DDE transaction failed"
|
||||
case _SE_ERR_DDETIMEOUT:
|
||||
errorMsg = "The DDE transaction could not be completed because the request timed out"
|
||||
case _SE_ERR_DLLNOTFOUND:
|
||||
errorMsg = "The specified DLL was not found"
|
||||
case _SE_ERR_NOASSOC:
|
||||
errorMsg = "There is no application associated with the given file name extension"
|
||||
case _SE_ERR_OOM:
|
||||
errorMsg = "There was not enough memory to complete the operation"
|
||||
case _SE_ERR_SHARE:
|
||||
errorMsg = "A sharing violation occurred"
|
||||
default:
|
||||
errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", pExecInfo.hInstApp)
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return errors.New(errorMsg)
|
||||
}
|
||||
168
v2/internal/webview2runtime/webview2runtime.go
Normal file
168
v2/internal/webview2runtime/webview2runtime.go
Normal file
@@ -0,0 +1,168 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package webview2runtime
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:embed MicrosoftEdgeWebview2Setup.exe
|
||||
var setupexe []byte
|
||||
|
||||
// Info contains all the information about an installation of the webview2 runtime.
|
||||
type Info struct {
|
||||
Location string
|
||||
Name string
|
||||
Version string
|
||||
SilentUninstall string
|
||||
}
|
||||
|
||||
// IsOlderThan returns true if the installed version is older than the given required version.
|
||||
// Returns error if something goes wrong.
|
||||
func (i *Info) IsOlderThan(requiredVersion string) (bool, error) {
|
||||
var mod = syscall.NewLazyDLL("WebView2Loader.dll")
|
||||
var CompareBrowserVersions = mod.NewProc("CompareBrowserVersions")
|
||||
v1, err := syscall.UTF16PtrFromString(i.Version)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
v2, err := syscall.UTF16PtrFromString(requiredVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var result int = 9
|
||||
_, _, err = CompareBrowserVersions.Call(uintptr(unsafe.Pointer(v1)), uintptr(unsafe.Pointer(v2)), uintptr(unsafe.Pointer(&result)))
|
||||
if result < -1 || result > 1 {
|
||||
return false, err
|
||||
}
|
||||
return result == -1, nil
|
||||
}
|
||||
|
||||
func downloadBootstrapper() (string, error) {
|
||||
bootstrapperURL := `https://go.microsoft.com/fwlink/p/?LinkId=2124703`
|
||||
installer := filepath.Join(os.TempDir(), `MicrosoftEdgeWebview2Setup.exe`)
|
||||
|
||||
// Download installer
|
||||
out, err := os.Create(installer)
|
||||
defer out.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := http.Get(bootstrapperURL)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
err = out.Close()
|
||||
return "", err
|
||||
}
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return installer, nil
|
||||
}
|
||||
|
||||
// InstallUsingEmbeddedBootstrapper will download the bootstrapper from Microsoft and run it to install
|
||||
// the latest version of the runtime.
|
||||
// Returns true if the installer ran successfully.
|
||||
// Returns an error if something goes wrong
|
||||
func InstallUsingEmbeddedBootstrapper() (bool, error) {
|
||||
|
||||
installer := filepath.Join(os.TempDir(), `MicrosoftEdgeWebview2Setup.exe`)
|
||||
err := os.WriteFile(installer, setupexe, 0755)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, err := runInstaller(installer)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result, os.Remove(installer)
|
||||
|
||||
}
|
||||
|
||||
// InstallUsingBootstrapper will extract the embedded bootstrapper from Microsoft and run it to install
|
||||
// the latest version of the runtime.
|
||||
// Returns true if the installer ran successfully.
|
||||
// Returns an error if something goes wrong
|
||||
func InstallUsingBootstrapper() (bool, error) {
|
||||
|
||||
installer, err := downloadBootstrapper()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
result, err := runInstaller(installer)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return result, os.Remove(installer)
|
||||
|
||||
}
|
||||
|
||||
func runInstaller(installer string) (bool, error) {
|
||||
err := ShellExecuteAndWait(0, "runas", installer, "", os.Getenv("TMP"), syscall.SW_NORMAL)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Confirm will prompt the user with a message and OK / CANCEL buttons.
|
||||
// Returns true if OK is selected by the user.
|
||||
// Returns an error if something went wrong.
|
||||
func Confirm(caption string, title string) (bool, error) {
|
||||
var flags uint = 0x00000001 // MB_OKCANCEL
|
||||
result, err := MessageBox(caption, title, flags)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result == 1, nil
|
||||
}
|
||||
|
||||
// Error will an error message to the user.
|
||||
// Returns an error if something went wrong.
|
||||
func Error(caption string, title string) error {
|
||||
var flags uint = 0x00000010 // MB_ICONERROR
|
||||
_, err := MessageBox(caption, title, flags)
|
||||
return err
|
||||
}
|
||||
|
||||
// MessageBox prompts the user with the given caption and title.
|
||||
// Flags may be provided to customise the dialog.
|
||||
// Returns an error if something went wrong.
|
||||
func MessageBox(caption string, title string, flags uint) (int, error) {
|
||||
captionUTF16, err := syscall.UTF16PtrFromString(caption)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
titleUTF16, err := syscall.UTF16PtrFromString(title)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
ret, _, _ := syscall.NewLazyDLL("user32.dll").NewProc("MessageBoxW").Call(
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(captionUTF16)),
|
||||
uintptr(unsafe.Pointer(titleUTF16)),
|
||||
uintptr(flags))
|
||||
|
||||
return int(ret), nil
|
||||
}
|
||||
|
||||
// OpenInstallerDownloadWebpage will open the browser on the WebView2 download page
|
||||
func OpenInstallerDownloadWebpage() error {
|
||||
cmd := exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://developer.microsoft.com/en-us/microsoft-edge/webview2/")
|
||||
return cmd.Run()
|
||||
}
|
||||
@@ -32,6 +32,7 @@ Example: `wails init -n "Your Project Name" -t https://github.com/misitebao/wail
|
||||
## React
|
||||
|
||||
- [wails-react-template](https://github.com/AlienRecall/wails-react-template) - A template using reactjs
|
||||
- [wails-react-template](https://github.com/flin7/wails-react-template) - A minimal template for React that supports live development
|
||||
|
||||
## Svelte
|
||||
|
||||
|
||||
Reference in New Issue
Block a user