Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
239
vendor/github.com/wailsapp/go-webview2/pkg/combridge/bridge.go
generated
vendored
Normal file
239
vendor/github.com/wailsapp/go-webview2/pkg/combridge/bridge.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
//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
|
||||
}
|
||||
Reference in New Issue
Block a user