mirror of
https://github.com/wavetermdev/wails.git
synced 2026-08-05 13:53:43 -07:00
[chore] Use webview2 package (#2687)
* [v2 windows] Use external webview2 package * Update CHANGELOG
This commit is contained in:
@@ -35,6 +35,7 @@ require (
|
||||
github.com/tidwall/sjson v1.1.7
|
||||
github.com/tkrajina/go-reflector v0.5.6
|
||||
github.com/wailsapp/mimetype v1.4.1
|
||||
github.com/wailsapp/go-webview2 v1.0.1
|
||||
github.com/wzshiming/ctc v1.2.3
|
||||
golang.org/x/mod v0.8.0
|
||||
golang.org/x/net v0.10.0
|
||||
@@ -59,6 +60,7 @@ require (
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/lithammer/fuzzysearch v1.1.5 // indirect
|
||||
|
||||
@@ -250,6 +250,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II=
|
||||
github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/bep/debounce"
|
||||
"github.com/wailsapp/go-webview2/pkg/edge"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/go-webview2/pkg/edge"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32"
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 John Chadwick
|
||||
Some portions Copyright (c) 2017 Serge Zaitsev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,27 +0,0 @@
|
||||
# go-webview2
|
||||
|
||||
This is a proof of concept for embedding Webview2 into Go without CGo. It is based
|
||||
on [webview/webview](https://github.com/webview/webview) and provides a compatible API.
|
||||
|
||||
## Notice
|
||||
|
||||
Because this version doesn't currently have an EdgeHTML fallback, it will not work unless you have a Webview2 runtime
|
||||
installed. In addition, it requires the Webview2Loader DLL in order to function. Adding an EdgeHTML fallback should be
|
||||
technically possible but will likely require much worse hacks since the API is not strictly COM to my knowledge.
|
||||
|
||||
## Demo
|
||||
|
||||
For now, you'll need to install the Webview2 runtime, as it does not ship with Windows.
|
||||
|
||||
[WebView2 runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)
|
||||
|
||||
After that, you should be able to run go-webview2 directly:
|
||||
|
||||
```
|
||||
go run go-webview2/cmd/demo
|
||||
```
|
||||
|
||||
This will use go-winloader to load an embedded copy of WebView2Loader.dll.
|
||||
|
||||
If this does not work, please try running from a directory that has an appropriate copy of `WebView2Loader.dll` for your
|
||||
GOARCH. If _that_ worked, *please* file a bug so we can figure out what's wrong with go-winloader :)
|
||||
@@ -1,157 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
ole32 = windows.NewLazySystemDLL("ole32")
|
||||
Ole32CoInitializeEx = ole32.NewProc("CoInitializeEx")
|
||||
|
||||
kernel32 = windows.NewLazySystemDLL("kernel32")
|
||||
Kernel32GetCurrentThreadID = kernel32.NewProc("GetCurrentThreadId")
|
||||
|
||||
shlwapi = windows.NewLazySystemDLL("shlwapi")
|
||||
shlwapiSHCreateMemStream = shlwapi.NewProc("SHCreateMemStream")
|
||||
|
||||
user32 = windows.NewLazySystemDLL("user32")
|
||||
User32LoadImageW = user32.NewProc("LoadImageW")
|
||||
User32GetSystemMetrics = user32.NewProc("GetSystemMetrics")
|
||||
User32RegisterClassExW = user32.NewProc("RegisterClassExW")
|
||||
User32CreateWindowExW = user32.NewProc("CreateWindowExW")
|
||||
User32DestroyWindow = user32.NewProc("DestroyWindow")
|
||||
User32ShowWindow = user32.NewProc("ShowWindow")
|
||||
User32UpdateWindow = user32.NewProc("UpdateWindow")
|
||||
User32SetFocus = user32.NewProc("SetFocus")
|
||||
User32GetMessageW = user32.NewProc("GetMessageW")
|
||||
User32TranslateMessage = user32.NewProc("TranslateMessage")
|
||||
User32DispatchMessageW = user32.NewProc("DispatchMessageW")
|
||||
User32DefWindowProcW = user32.NewProc("DefWindowProcW")
|
||||
User32GetClientRect = user32.NewProc("GetClientRect")
|
||||
User32PostQuitMessage = user32.NewProc("PostQuitMessage")
|
||||
User32SetWindowTextW = user32.NewProc("SetWindowTextW")
|
||||
User32PostThreadMessageW = user32.NewProc("PostThreadMessageW")
|
||||
User32GetWindowLongPtrW = user32.NewProc("GetWindowLongPtrW")
|
||||
User32SetWindowLongPtrW = user32.NewProc("SetWindowLongPtrW")
|
||||
User32AdjustWindowRect = user32.NewProc("AdjustWindowRect")
|
||||
User32SetWindowPos = user32.NewProc("SetWindowPos")
|
||||
)
|
||||
|
||||
const (
|
||||
SystemMetricsCxIcon = 11
|
||||
SystemMetricsCyIcon = 12
|
||||
)
|
||||
|
||||
const (
|
||||
SWShow = 5
|
||||
)
|
||||
|
||||
const (
|
||||
SWPNoZOrder = 0x0004
|
||||
SWPNoActivate = 0x0010
|
||||
SWPNoMove = 0x0002
|
||||
SWPFrameChanged = 0x0020
|
||||
)
|
||||
|
||||
const (
|
||||
WMDestroy = 0x0002
|
||||
WMMove = 0x0003
|
||||
WMSize = 0x0005
|
||||
WMClose = 0x0010
|
||||
WMQuit = 0x0012
|
||||
WMGetMinMaxInfo = 0x0024
|
||||
WMNCLButtonDown = 0x00A1
|
||||
WMMoving = 0x0216
|
||||
WMApp = 0x8000
|
||||
)
|
||||
|
||||
const (
|
||||
GWLStyle = -16
|
||||
)
|
||||
|
||||
const (
|
||||
WSOverlapped = 0x00000000
|
||||
WSMaximizeBox = 0x00020000
|
||||
WSThickFrame = 0x00040000
|
||||
WSCaption = 0x00C00000
|
||||
WSSysMenu = 0x00080000
|
||||
WSMinimizeBox = 0x00020000
|
||||
WSOverlappedWindow = (WSOverlapped | WSCaption | WSSysMenu | WSThickFrame | WSMinimizeBox | WSMaximizeBox)
|
||||
)
|
||||
|
||||
type WndClassExW struct {
|
||||
CbSize uint32
|
||||
Style uint32
|
||||
LpfnWndProc uintptr
|
||||
CnClsExtra int32
|
||||
CbWndExtra int32
|
||||
HInstance windows.Handle
|
||||
HIcon windows.Handle
|
||||
HCursor windows.Handle
|
||||
HbrBackground windows.Handle
|
||||
LpszMenuName *uint16
|
||||
LpszClassName *uint16
|
||||
HIconSm windows.Handle
|
||||
}
|
||||
|
||||
type Rect struct {
|
||||
Left int32
|
||||
Top int32
|
||||
Right int32
|
||||
Bottom int32
|
||||
}
|
||||
|
||||
type MinMaxInfo struct {
|
||||
PtReserved Point
|
||||
PtMaxSize Point
|
||||
PtMaxPosition Point
|
||||
PtMinTrackSize Point
|
||||
PtMaxTrackSize Point
|
||||
}
|
||||
|
||||
type Point struct {
|
||||
X, Y int32
|
||||
}
|
||||
|
||||
type Msg struct {
|
||||
Hwnd syscall.Handle
|
||||
Message uint32
|
||||
WParam uintptr
|
||||
LParam uintptr
|
||||
Time uint32
|
||||
Pt Point
|
||||
LPrivate uint32
|
||||
}
|
||||
|
||||
func Utf16PtrToString(p *uint16) string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
// Find NUL terminator.
|
||||
end := unsafe.Pointer(p)
|
||||
n := 0
|
||||
for *(*uint16)(end) != 0 {
|
||||
end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p))
|
||||
n++
|
||||
}
|
||||
s := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:n:n]
|
||||
return string(utf16.Decode(s))
|
||||
}
|
||||
|
||||
func SHCreateMemStream(data []byte) (uintptr, error) {
|
||||
ret, _, err := shlwapiSHCreateMemStream.Call(
|
||||
uintptr(unsafe.Pointer(&data[0])),
|
||||
uintptr(len(data)),
|
||||
)
|
||||
if ret == 0 {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package combridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
comIfcePointersL sync.RWMutex
|
||||
comIfcePointers = map[uintptr]*comObject{} // Map from ComInterfacePointer to the Go ComObject
|
||||
)
|
||||
|
||||
// Resolve the GoInterface of the specified ComInterfacePointer
|
||||
func Resolve[T IUnknown](ifceP uintptr) T {
|
||||
comIfcePointersL.RLock()
|
||||
comObj := comIfcePointers[ifceP]
|
||||
comIfcePointersL.RUnlock()
|
||||
|
||||
var n T
|
||||
if comObj != nil {
|
||||
t := comObj.resolve(ifceP)
|
||||
if t != nil {
|
||||
n = t.(T)
|
||||
}
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// New returns a new ComObject which implements the specified Com Interface, com calls will be redirected
|
||||
// to the specified go interface.
|
||||
func New[T IUnknown](obj T) *ComObject[T] {
|
||||
cObj := new(
|
||||
ifceDef[T]{obj},
|
||||
)
|
||||
return newComObject[T](cObj)
|
||||
}
|
||||
|
||||
// New2 returns a new ComObject which implements the two specified Com Interfaces, com calls will be redirected
|
||||
// to those interfaces accordingly.
|
||||
// This is needed if a ComObject should implement two interfaces that are not descendants of each other,
|
||||
// then you get multiple inheritance.
|
||||
func New2[T IUnknown, T2 IUnknown](obj T, obj2 T2) *ComObject[T] {
|
||||
cObj := new(
|
||||
ifceDef[T]{obj},
|
||||
ifceDef[T2]{obj2},
|
||||
)
|
||||
return newComObject[T](cObj)
|
||||
}
|
||||
|
||||
// new returns a new ComObject which implements multiple specified Com Interfaces, com calls will be redirected
|
||||
// to the specified go interfaces accordingly.
|
||||
// This is needed if a ComObject should implement multiple interfaces that are not descendants of each other,
|
||||
// then you get multiple inheritance.
|
||||
func new(impls ...ifceImpl) *comObject {
|
||||
impls = append([]ifceImpl{ifceDef[IUnknown]{}}, impls...)
|
||||
|
||||
cObj := &comObject{
|
||||
refCount: 1,
|
||||
ifces: map[string]int{},
|
||||
ifcesImpl: make([]comInterfaceDesc, len(impls)),
|
||||
}
|
||||
|
||||
for i, ifceDef := range impls {
|
||||
vtable, err := ifceDef.ifce()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
needsImplement := false
|
||||
for table := vtable; table != nil; table = table.Parent {
|
||||
guid := table.ComGUID
|
||||
if i, found := cObj.ifces[guid]; found {
|
||||
// This Interface is already implemented
|
||||
if guid == iUnknownGUID {
|
||||
// IUnknown is a special interface and never has an user specific implementation
|
||||
} else if cObj.ifcesImpl[i].impl != ifceDef.impl() {
|
||||
panic(fmt.Sprintf("Interface '%s' is already implemented by another object", table.Name))
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
needsImplement = true
|
||||
cObj.ifces[guid] = i
|
||||
}
|
||||
|
||||
if !needsImplement {
|
||||
continue
|
||||
}
|
||||
|
||||
ifceP, ifcePSlice := allocUintptrObject(1)
|
||||
ifcePSlice[0] = vtable.ComVTable
|
||||
cObj.ifcesImpl[i] = comInterfaceDesc{ifceP, ifceDef.impl()}
|
||||
}
|
||||
|
||||
comIfcePointersL.Lock()
|
||||
for _, ifceImpl := range cObj.ifcesImpl {
|
||||
comIfcePointers[ifceImpl.ref] = cObj
|
||||
}
|
||||
comIfcePointersL.Unlock()
|
||||
|
||||
return cObj
|
||||
}
|
||||
|
||||
func newComObject[T IUnknown](comObj *comObject) *ComObject[T] {
|
||||
c := &ComObject[T]{obj: comObj}
|
||||
// Make sure to async release since release needs locks and might block the finalizer goroutine for a longer period
|
||||
runtime.SetFinalizer(c, func(obj *ComObject[T]) { obj.close(true) })
|
||||
return c
|
||||
}
|
||||
|
||||
// ComObject describes an exported go instance to be used as a ComObject which implements
|
||||
// the specified Interface.
|
||||
type ComObject[T IUnknown] struct {
|
||||
obj *comObject
|
||||
closed int32
|
||||
}
|
||||
|
||||
// Ref returns the native uintptr that points to the ComObject that is an interface pointer to T.
|
||||
// This can be used in native calls. If the object has been closed this function will panic.
|
||||
func (o *ComObject[T]) Ref() uintptr {
|
||||
if atomic.LoadInt32(&o.closed) != 0 {
|
||||
panic("ComObject has been released")
|
||||
}
|
||||
return o.obj.queryInterface(guidOf[T](), false)
|
||||
}
|
||||
|
||||
// Close releases the native com object from the go side. It will only be destroyed if the ref counter
|
||||
// reaches zero.
|
||||
// After closing `Ref()` will panic.
|
||||
func (o *ComObject[T]) Close() error {
|
||||
o.close(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
// close releases the native com object from the go side. It will only be destroyed if the ref counter
|
||||
// reaches zero.
|
||||
// After closing `Ref()` will panic.
|
||||
func (o *ComObject[T]) close(asyncRelease bool) {
|
||||
if atomic.CompareAndSwapInt32(&o.closed, 0, 1) {
|
||||
runtime.SetFinalizer(o, nil)
|
||||
if asyncRelease {
|
||||
go o.obj.release()
|
||||
} else {
|
||||
o.obj.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type comInterfaceDesc struct {
|
||||
ref uintptr // The native Com InterfacePointer
|
||||
impl any // The golang target object
|
||||
}
|
||||
|
||||
type comObject struct {
|
||||
l sync.Mutex
|
||||
|
||||
refCount int32
|
||||
ifces map[string]int // Map of ComInterfaceGUID to Interface Slots
|
||||
ifcesImpl []comInterfaceDesc // Slots with InterfaceDescriptors
|
||||
}
|
||||
|
||||
func (c *comObject) queryInterface(ifceGUID string, withAddRef bool) uintptr {
|
||||
c.l.Lock()
|
||||
defer c.l.Unlock()
|
||||
if c.refCount <= 0 {
|
||||
panic("call on released com object")
|
||||
}
|
||||
|
||||
i, found := c.ifces[ifceGUID]
|
||||
if !found {
|
||||
return 0
|
||||
}
|
||||
|
||||
if withAddRef {
|
||||
c.refCount++
|
||||
}
|
||||
return c.ifcesImpl[i].ref
|
||||
}
|
||||
|
||||
func (c *comObject) resolve(ifceP uintptr) any {
|
||||
c.l.Lock()
|
||||
defer c.l.Unlock()
|
||||
if c.refCount <= 0 {
|
||||
panic("call on destroyed com object")
|
||||
}
|
||||
|
||||
for _, ifce := range c.ifcesImpl {
|
||||
if ifce.ref != ifceP {
|
||||
continue
|
||||
}
|
||||
|
||||
return ifce.impl
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *comObject) addRef() int32 {
|
||||
c.l.Lock()
|
||||
defer c.l.Unlock()
|
||||
if c.refCount <= 0 {
|
||||
panic("call on destroyed com object")
|
||||
}
|
||||
|
||||
c.refCount++
|
||||
return c.refCount
|
||||
}
|
||||
|
||||
func (c *comObject) release() int32 {
|
||||
c.l.Lock()
|
||||
defer c.l.Unlock()
|
||||
if c.refCount <= 0 {
|
||||
panic("call on destroyed com object")
|
||||
}
|
||||
|
||||
if c.refCount--; c.refCount == 0 {
|
||||
comIfcePointersL.Lock()
|
||||
for _, ref := range c.ifcesImpl {
|
||||
delete(comIfcePointers, ref.ref)
|
||||
}
|
||||
comIfcePointersL.Unlock()
|
||||
|
||||
for _, impl := range c.ifcesImpl {
|
||||
ref := impl.ref
|
||||
if ref == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
globalFree(ref)
|
||||
}
|
||||
}
|
||||
|
||||
return c.refCount
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package combridge
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const iUnknownGUID = "{00000000-0000-0000-C000-000000000046}"
|
||||
|
||||
func init() {
|
||||
registerVTableInternal[IUnknown, IUnknown](
|
||||
iUnknownGUID,
|
||||
true,
|
||||
iUnknownQueryInterface,
|
||||
iUnknownAddRef,
|
||||
iUnknownRelease,
|
||||
)
|
||||
}
|
||||
|
||||
type IUnknown interface{}
|
||||
|
||||
func iUnknownQueryInterface(this uintptr, refiid *windows.GUID, ppvObject *uintptr) uintptr {
|
||||
if refiid == nil || ppvObject == nil {
|
||||
return uintptr(windows.E_INVALIDARG)
|
||||
}
|
||||
|
||||
comIfcePointersL.RLock()
|
||||
obj := comIfcePointers[this]
|
||||
comIfcePointersL.RUnlock()
|
||||
|
||||
ref := obj.queryInterface(refiid.String(), true)
|
||||
if ref != 0 {
|
||||
*ppvObject = ref
|
||||
return windows.NO_ERROR
|
||||
}
|
||||
|
||||
*ppvObject = 0
|
||||
return uintptr(windows.E_NOINTERFACE)
|
||||
}
|
||||
|
||||
func iUnknownAddRef(this uintptr) uintptr {
|
||||
comIfcePointersL.RLock()
|
||||
obj := comIfcePointers[this]
|
||||
comIfcePointersL.RUnlock()
|
||||
|
||||
return uintptr(obj.addRef())
|
||||
}
|
||||
|
||||
func iUnknownRelease(this uintptr) uintptr {
|
||||
comIfcePointersL.RLock()
|
||||
obj := comIfcePointers[this]
|
||||
comIfcePointersL.RUnlock()
|
||||
|
||||
return uintptr(obj.release())
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package combridge
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// IUnknownFromPointer cast a generic pointer into a IUnknownImpl pointer
|
||||
func IUnknownFromPointer(ref unsafe.Pointer) *IUnknownImpl {
|
||||
return (*IUnknownImpl)(ref)
|
||||
}
|
||||
|
||||
// IUnknownFromPointer cast native pointer into a IUnknownImpl pointer
|
||||
func IUnknownFromUintptr(ref uintptr) *IUnknownImpl {
|
||||
return IUnknownFromPointer(unsafe.Pointer(ref))
|
||||
}
|
||||
|
||||
type IUnknownVtbl struct {
|
||||
queryInterface uintptr
|
||||
addRef uintptr
|
||||
release uintptr
|
||||
}
|
||||
|
||||
func (i *IUnknownVtbl) QueryInterface(this unsafe.Pointer, refiid *windows.GUID, ppvObject **IUnknownImpl) error {
|
||||
r, _, _ := syscall.SyscallN(
|
||||
i.queryInterface,
|
||||
uintptr(this),
|
||||
uintptr(unsafe.Pointer(refiid)),
|
||||
uintptr(unsafe.Pointer(ppvObject)),
|
||||
)
|
||||
|
||||
if r != uintptr(windows.S_OK) {
|
||||
return syscall.Errno(r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IUnknownVtbl) AddRef(this unsafe.Pointer) uint32 {
|
||||
r, _, _ := syscall.SyscallN(
|
||||
i.addRef,
|
||||
uintptr(this),
|
||||
)
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
func (i *IUnknownVtbl) Release(this unsafe.Pointer) uint32 {
|
||||
r, _, _ := syscall.SyscallN(
|
||||
i.release,
|
||||
uintptr(this),
|
||||
)
|
||||
|
||||
return uint32(r)
|
||||
}
|
||||
|
||||
type IUnknownImpl struct {
|
||||
vtbl *IUnknownVtbl
|
||||
}
|
||||
|
||||
func (i *IUnknownImpl) QueryInterface(refiid *windows.GUID, ppvObject **IUnknownImpl) error {
|
||||
return i.vtbl.QueryInterface(unsafe.Pointer(i), refiid, ppvObject)
|
||||
}
|
||||
|
||||
func (i *IUnknownImpl) AddRef() uint32 {
|
||||
return i.vtbl.AddRef(unsafe.Pointer(i))
|
||||
}
|
||||
|
||||
func (i *IUnknownImpl) Release() uint32 {
|
||||
return i.vtbl.Release(unsafe.Pointer(i))
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package combridge
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
|
||||
procGlobalFree = modkernel32.NewProc("GlobalFree")
|
||||
|
||||
uintptrSize = unsafe.Sizeof(uintptr(0))
|
||||
)
|
||||
|
||||
func allocUintptrObject(size int) (uintptr, []uintptr) {
|
||||
v := globalAlloc(uintptr(size) * uintptrSize)
|
||||
slice := unsafe.Slice((*uintptr)(unsafe.Pointer(v)), size)
|
||||
return v, slice
|
||||
}
|
||||
|
||||
func globalAlloc(dwBytes uintptr) uintptr {
|
||||
ret, _, _ := procGlobalAlloc.Call(uintptr(0), dwBytes)
|
||||
if ret == 0 {
|
||||
panic("globalAlloc failed")
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func globalFree(data uintptr) {
|
||||
ret, _, _ := procGlobalFree.Call(data)
|
||||
if ret != 0 {
|
||||
panic("globalFree failed")
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package combridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
vTablesL sync.Mutex
|
||||
vTables = make(map[string]*vTable)
|
||||
)
|
||||
|
||||
// RegisterVTable registers the vtable trampoline methods for the specified ComInterface
|
||||
// TBase is the base interface of T, and must be another ComInterface which roots in IUnknown or IUnknown itself.
|
||||
// The first paramter of the fn is always the uintptr of the ComObject and the GoObject can be resolved with Resolve().
|
||||
// After having resolved the GoObject the call must be redirected to the GoObject.
|
||||
// Typically a trampoline FN looks like this.
|
||||
//
|
||||
// func _ICoreWebView2NavigationCompletedEventHandlerInvoke(this uintptr, sender *ICoreWebView2, args *ICoreWebView2NavigationCompletedEventArgs) uintptr {
|
||||
// return combridge.Resolve[_ICoreWebView2NavigationCompletedEventHandler](this).NavigationCompleted(sender, args)
|
||||
// }
|
||||
//
|
||||
// The order of registration must be in the correct order as specified in the IDL of the interface.
|
||||
func RegisterVTable[TParent, T IUnknown](guid string, fns ...interface{}) {
|
||||
registerVTableInternal[TParent, T](guid, false, fns...)
|
||||
}
|
||||
|
||||
type vTable struct {
|
||||
Parent *vTable
|
||||
|
||||
Name string
|
||||
ComGUID string
|
||||
ComVTable uintptr
|
||||
ComProcs []uintptr
|
||||
}
|
||||
|
||||
func registerVTableInternal[TParent, T IUnknown](guid string, isInternal bool, fns ...interface{}) {
|
||||
vTablesL.Lock()
|
||||
defer vTablesL.Unlock()
|
||||
|
||||
t, tName := typeInterfaceToString[T]()
|
||||
tParent, tParentName := typeInterfaceToString[TParent]()
|
||||
if !t.Implements(tParent) {
|
||||
panic(fmt.Errorf("RegisterVTable '%s': '%s' must implement '%s'", tName, tName, tParentName))
|
||||
}
|
||||
|
||||
if !isInternal {
|
||||
if t == reflect.TypeOf((*IUnknown)(nil)).Elem() {
|
||||
panic(fmt.Errorf("RegisterVTable '%s' IUnknown can't be registered", tName))
|
||||
}
|
||||
|
||||
if t == tParent {
|
||||
panic(fmt.Errorf("RegisterVTable '%s': T and TParent can't be the same type", tName))
|
||||
}
|
||||
}
|
||||
|
||||
var parent *vTable
|
||||
var parentProcs []uintptr
|
||||
var parentProcsCount int
|
||||
if t != tParent {
|
||||
parent = vTables[tParentName]
|
||||
if parent == nil {
|
||||
panic(fmt.Errorf("RegisterVTable '%s': Parent VTable '%s' not registered", tName, tParentName))
|
||||
}
|
||||
|
||||
parentProcs = parent.ComProcs
|
||||
parentProcsCount = len(parentProcs)
|
||||
}
|
||||
|
||||
comGuid, err := windows.GUIDFromString(guid)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("RegisterVTable '%s': invalid guid: %s", tName, err))
|
||||
}
|
||||
|
||||
vTable := &vTable{
|
||||
Parent: parent,
|
||||
Name: tName,
|
||||
ComGUID: comGuid.String(),
|
||||
}
|
||||
vTable.ComVTable, vTable.ComProcs = allocUintptrObject(parentProcsCount + len(fns))
|
||||
|
||||
for i, proc := range parentProcs {
|
||||
vTable.ComProcs[i] = proc
|
||||
}
|
||||
|
||||
for i, fn := range fns {
|
||||
vTable.ComProcs[parentProcsCount+i] = windows.NewCallback(fn)
|
||||
}
|
||||
|
||||
vTables[tName] = vTable
|
||||
}
|
||||
|
||||
func typeInterfaceToString[T any]() (reflect.Type, string) {
|
||||
t := reflect.TypeOf((*T)(nil))
|
||||
if t.Kind() != reflect.Pointer {
|
||||
panic("must be a (*yourInterfaceType)(nil)")
|
||||
}
|
||||
t = t.Elem()
|
||||
return t, t.PkgPath() + "/" + t.Name()
|
||||
}
|
||||
|
||||
func typeInterfaceToStringOnly[T any]() string {
|
||||
_, nane := typeInterfaceToString[T]()
|
||||
return nane
|
||||
}
|
||||
|
||||
func guidOf[T any]() string {
|
||||
vtable := vTableOf[T]()
|
||||
if vtable == nil {
|
||||
return ""
|
||||
}
|
||||
return vtable.ComGUID
|
||||
}
|
||||
|
||||
func vTableOf[T any]() *vTable {
|
||||
name := typeInterfaceToStringOnly[T]()
|
||||
vTablesL.Lock()
|
||||
defer vTablesL.Unlock()
|
||||
|
||||
return vTables[name]
|
||||
}
|
||||
|
||||
type ifceImpl interface {
|
||||
impl() any
|
||||
ifce() (*vTable, error)
|
||||
}
|
||||
|
||||
type ifceDef[T any] struct {
|
||||
objImpl any
|
||||
}
|
||||
|
||||
func (i ifceDef[T]) impl() any {
|
||||
return i.objImpl
|
||||
}
|
||||
|
||||
func (i ifceDef[T]) ifce() (*vTable, error) {
|
||||
vtable := vTableOf[T]()
|
||||
if vtable == nil {
|
||||
return nil, fmt.Errorf("Unable to find vTable for %s", typeInterfaceToStringOnly[T]())
|
||||
}
|
||||
return vtable, nil
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_COLOR struct {
|
||||
A uint8
|
||||
R uint8
|
||||
G uint8
|
||||
B uint8
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND uint32
|
||||
|
||||
const (
|
||||
COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY = iota
|
||||
COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_ALLOW
|
||||
COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY_CORS
|
||||
)
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_KEY_EVENT_KIND uint32
|
||||
|
||||
const (
|
||||
COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN = 0
|
||||
COREWEBVIEW2_KEY_EVENT_KIND_KEY_UP = 1
|
||||
COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN = 2
|
||||
COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_UP = 3
|
||||
)
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_MOVE_FOCUS_REASON uint32
|
||||
|
||||
const (
|
||||
COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC = 0
|
||||
COREWEBVIEW2_MOVE_FOCUS_REASON_NEXT = 1
|
||||
COREWEBVIEW2_MOVE_FOCUS_REASON_PREVIOUS = 2
|
||||
)
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_PHYSICAL_KEY_STATUS struct {
|
||||
RepeatCount uint32
|
||||
ScanCode uint32
|
||||
IsExtendedKey bool
|
||||
IsMenuKeyDown bool
|
||||
WasKeyDown bool
|
||||
IsKeyReleased bool
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_PROCESS_FAILED_KIND uint32
|
||||
|
||||
const (
|
||||
// Indicates that the browser process ended unexpectedly. The WebView
|
||||
// automatically moves to the Closed state. The app has to recreate a new
|
||||
// WebView to recover from this failure.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED = 0
|
||||
|
||||
// Indicates that the main frame's render process ended unexpectedly. A new
|
||||
// render process is created automatically and navigated to an error page.
|
||||
// You can use the `Reload` method to try to reload the page that failed.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED = 1
|
||||
|
||||
// Indicates that the main frame's render process is unresponsive.
|
||||
//
|
||||
// Note that this does not seem to work right now.
|
||||
// Does not fire for simple long running script case, the only related test
|
||||
// SitePerProcessBrowserTest::NoCommitTimeoutForInvisibleWebContents is
|
||||
// disabled.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE = 2
|
||||
|
||||
// Indicates that a frame-only render process ended unexpectedly. The process
|
||||
// exit does not affect the top-level document, only a subset of the
|
||||
// subframes within it. The content in these frames is replaced with an error
|
||||
// page in the frame.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED = 3
|
||||
|
||||
// Indicates that a utility process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED = 4
|
||||
|
||||
// Indicates that a sandbox helper process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED = 5
|
||||
|
||||
// Indicates that the GPU process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED = 6
|
||||
|
||||
// Indicates that a PPAPI plugin process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED = 7
|
||||
|
||||
// Indicates that a PPAPI plugin broker process ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED = 8
|
||||
|
||||
// Indicates that a process of unspecified kind ended unexpectedly.
|
||||
COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED = 9
|
||||
)
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type COREWEBVIEW2_WEB_RESOURCE_CONTEXT uint32
|
||||
|
||||
const (
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL = 0
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_DOCUMENT = 1
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_STYLESHEET = 2
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE = 3
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_MEDIA = 4
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_FONT = 5
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_SCRIPT = 6
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_XML_HTTP_REQUEST = 7
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_FETCH = 8
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_TEXT_TRACK = 9
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_EVENT_SOURCE = 10
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_WEBSOCKET = 11
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_MANIFEST = 12
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_SIGNED_EXCHANGE = 13
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_PING = 14
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_CSP_VIOLATION_REPORT = 15
|
||||
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_OTHER = 16
|
||||
)
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type _ICoreWebView2AcceleratorKeyPressedEventArgsVtbl struct {
|
||||
_IUnknownVtbl
|
||||
GetKeyEventKind ComProc
|
||||
GetVirtualKey ComProc
|
||||
GetKeyEventLParam ComProc
|
||||
GetPhysicalKeyStatus ComProc
|
||||
GetHandled ComProc
|
||||
PutHandled ComProc
|
||||
}
|
||||
|
||||
type ICoreWebView2AcceleratorKeyPressedEventArgs struct {
|
||||
vtbl *_ICoreWebView2AcceleratorKeyPressedEventArgsVtbl
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2AcceleratorKeyPressedEventArgs) AddRef() uintptr {
|
||||
return i.AddRef()
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2AcceleratorKeyPressedEventArgs) GetKeyEventKind() (COREWEBVIEW2_KEY_EVENT_KIND, error) {
|
||||
var err error
|
||||
var keyEventKind COREWEBVIEW2_KEY_EVENT_KIND
|
||||
_, _, err = i.vtbl.GetKeyEventKind.Call(
|
||||
uintptr(unsafe.Pointer(i)),
|
||||
uintptr(unsafe.Pointer(&keyEventKind)),
|
||||
)
|
||||
if err != windows.ERROR_SUCCESS {
|
||||
return 0, err
|
||||
}
|
||||
return keyEventKind, nil
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2AcceleratorKeyPressedEventArgs) GetVirtualKey() (uint, error) {
|
||||
var err error
|
||||
var virtualKey uint
|
||||
_, _, err = i.vtbl.GetVirtualKey.Call(
|
||||
uintptr(unsafe.Pointer(i)),
|
||||
uintptr(unsafe.Pointer(&virtualKey)),
|
||||
)
|
||||
if err != windows.ERROR_SUCCESS {
|
||||
return 0, err
|
||||
}
|
||||
return virtualKey, nil
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2AcceleratorKeyPressedEventArgs) GetPhysicalKeyStatus() (COREWEBVIEW2_PHYSICAL_KEY_STATUS, error) {
|
||||
var err error
|
||||
var physicalKeyStatus COREWEBVIEW2_PHYSICAL_KEY_STATUS
|
||||
_, _, err = i.vtbl.GetPhysicalKeyStatus.Call(
|
||||
uintptr(unsafe.Pointer(i)),
|
||||
uintptr(unsafe.Pointer(&physicalKeyStatus)),
|
||||
)
|
||||
if err != windows.ERROR_SUCCESS {
|
||||
return COREWEBVIEW2_PHYSICAL_KEY_STATUS{}, err
|
||||
}
|
||||
return physicalKeyStatus, nil
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2AcceleratorKeyPressedEventArgs) PutHandled(handled bool) error {
|
||||
var err error
|
||||
|
||||
_, _, err = i.vtbl.PutHandled.Call(
|
||||
uintptr(unsafe.Pointer(i)),
|
||||
uintptr(boolToInt(handled)),
|
||||
)
|
||||
if err != windows.ERROR_SUCCESS {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package edge
|
||||
|
||||
type _ICoreWebView2AcceleratorKeyPressedEventHandlerVtbl struct {
|
||||
_IUnknownVtbl
|
||||
Invoke ComProc
|
||||
}
|
||||
|
||||
type ICoreWebView2AcceleratorKeyPressedEventHandler struct {
|
||||
vtbl *_ICoreWebView2AcceleratorKeyPressedEventHandlerVtbl
|
||||
impl _ICoreWebView2AcceleratorKeyPressedEventHandlerImpl
|
||||
}
|
||||
|
||||
func (i *ICoreWebView2AcceleratorKeyPressedEventHandler) AddRef() uintptr {
|
||||
return i.AddRef()
|
||||
}
|
||||
func _ICoreWebView2AcceleratorKeyPressedEventHandlerIUnknownQueryInterface(this *ICoreWebView2AcceleratorKeyPressedEventHandler, refiid, object uintptr) uintptr {
|
||||
return this.impl.QueryInterface(refiid, object)
|
||||
}
|
||||
|
||||
func _ICoreWebView2AcceleratorKeyPressedEventHandlerIUnknownAddRef(this *ICoreWebView2AcceleratorKeyPressedEventHandler) uintptr {
|
||||
return this.impl.AddRef()
|
||||
}
|
||||
|
||||
func _ICoreWebView2AcceleratorKeyPressedEventHandlerIUnknownRelease(this *ICoreWebView2AcceleratorKeyPressedEventHandler) uintptr {
|
||||
return this.impl.Release()
|
||||
}
|
||||
|
||||
func _ICoreWebView2AcceleratorKeyPressedEventHandlerInvoke(this *ICoreWebView2AcceleratorKeyPressedEventHandler, sender *ICoreWebView2Controller, args *ICoreWebView2AcceleratorKeyPressedEventArgs) uintptr {
|
||||
return this.impl.AcceleratorKeyPressed(sender, args)
|
||||
}
|
||||
|
||||
type _ICoreWebView2AcceleratorKeyPressedEventHandlerImpl interface {
|
||||
_IUnknownImpl
|
||||
AcceleratorKeyPressed(sender *ICoreWebView2Controller, args *ICoreWebView2AcceleratorKeyPressedEventArgs) uintptr
|
||||
}
|
||||
|
||||
var _ICoreWebView2AcceleratorKeyPressedEventHandlerFn = _ICoreWebView2AcceleratorKeyPressedEventHandlerVtbl{
|
||||
_IUnknownVtbl{
|
||||
NewComProc(_ICoreWebView2AcceleratorKeyPressedEventHandlerIUnknownQueryInterface),
|
||||
NewComProc(_ICoreWebView2AcceleratorKeyPressedEventHandlerIUnknownAddRef),
|
||||
NewComProc(_ICoreWebView2AcceleratorKeyPressedEventHandlerIUnknownRelease),
|
||||
},
|
||||
NewComProc(_ICoreWebView2AcceleratorKeyPressedEventHandlerInvoke),
|
||||
}
|
||||
|
||||
func newICoreWebView2AcceleratorKeyPressedEventHandler(impl _ICoreWebView2AcceleratorKeyPressedEventHandlerImpl) *ICoreWebView2AcceleratorKeyPressedEventHandler {
|
||||
return &ICoreWebView2AcceleratorKeyPressedEventHandler{
|
||||
vtbl: &_ICoreWebView2AcceleratorKeyPressedEventHandlerFn,
|
||||
impl: impl,
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user