Files
go-winrt/windows/foundation/deferralcompletedhandler.go

205 lines
5.1 KiB
Go

// Code generated by winrt-go-gen. DO NOT EDIT.
//go:build windows
//nolint:all
package foundation
import (
"sync"
"time"
"unsafe"
"git.savin.nyc/alex/go-winrt/internal/delegate"
"git.savin.nyc/alex/go-winrt/internal/kernel32"
"github.com/go-ole/go-ole"
)
const GUIDDeferralCompletedHandler string = "ed32a372-f3c8-4faa-9cfb-470148da3888"
const SignatureDeferralCompletedHandler string = "delegate({ed32a372-f3c8-4faa-9cfb-470148da3888})"
type DeferralCompletedHandler struct {
ole.IUnknown
sync.Mutex
refs uintptr
IID ole.GUID
}
type DeferralCompletedHandlerVtbl struct {
ole.IUnknownVtbl
Invoke uintptr
}
type DeferralCompletedHandlerCallback func(instance *DeferralCompletedHandler)
var callbacksDeferralCompletedHandler = &deferralCompletedHandlerCallbacks{
mu: &sync.Mutex{},
callbacks: make(map[unsafe.Pointer]DeferralCompletedHandlerCallback),
}
var releaseChannelsDeferralCompletedHandler = &deferralCompletedHandlerReleaseChannels{
mu: &sync.Mutex{},
chans: make(map[unsafe.Pointer]chan struct{}),
}
func NewDeferralCompletedHandler(iid *ole.GUID, callback DeferralCompletedHandlerCallback) *DeferralCompletedHandler {
// create type instance
size := unsafe.Sizeof(*(*DeferralCompletedHandler)(nil))
instPtr := kernel32.Malloc(size)
inst := (*DeferralCompletedHandler)(instPtr)
// get the callbacks for the VTable
callbacks := delegate.RegisterCallbacks(instPtr, inst)
// the VTable should also be allocated in the heap
sizeVTable := unsafe.Sizeof(*(*DeferralCompletedHandlerVtbl)(nil))
vTablePtr := kernel32.Malloc(sizeVTable)
inst.RawVTable = (*interface{})(vTablePtr)
vTable := (*DeferralCompletedHandlerVtbl)(vTablePtr)
vTable.IUnknownVtbl = ole.IUnknownVtbl{
QueryInterface: callbacks.QueryInterface,
AddRef: callbacks.AddRef,
Release: callbacks.Release,
}
vTable.Invoke = callbacks.Invoke
// Initialize all properties: the malloc may contain garbage
inst.IID = *iid // copy contents
inst.Mutex = sync.Mutex{}
inst.refs = 0
callbacksDeferralCompletedHandler.add(unsafe.Pointer(inst), callback)
// See the docs in the releaseChannelsDeferralCompletedHandler struct
releaseChannelsDeferralCompletedHandler.acquire(unsafe.Pointer(inst))
inst.addRef()
return inst
}
func (r *DeferralCompletedHandler) GetIID() *ole.GUID {
return &r.IID
}
// addRef increments the reference counter by one
func (r *DeferralCompletedHandler) addRef() uintptr {
r.Lock()
defer r.Unlock()
r.refs++
return r.refs
}
// removeRef decrements the reference counter by one. If it was already zero, it will just return zero.
func (r *DeferralCompletedHandler) removeRef() uintptr {
r.Lock()
defer r.Unlock()
if r.refs > 0 {
r.refs--
}
return r.refs
}
func (instance *DeferralCompletedHandler) Invoke(instancePtr, rawArgs0, rawArgs1, rawArgs2, rawArgs3, rawArgs4, rawArgs5, rawArgs6, rawArgs7, rawArgs8 unsafe.Pointer) uintptr {
// See the quote above.
if callback, ok := callbacksDeferralCompletedHandler.get(instancePtr); ok {
callback(instance)
}
return ole.S_OK
}
func (instance *DeferralCompletedHandler) AddRef() uintptr {
return instance.addRef()
}
func (instance *DeferralCompletedHandler) Release() uintptr {
rem := instance.removeRef()
if rem == 0 {
// We're done.
instancePtr := unsafe.Pointer(instance)
callbacksDeferralCompletedHandler.delete(instancePtr)
// stop release channels used to avoid
// https://github.com/golang/go/issues/55015
releaseChannelsDeferralCompletedHandler.release(instancePtr)
kernel32.Free(unsafe.Pointer(instance.RawVTable))
kernel32.Free(instancePtr)
}
return rem
}
type deferralCompletedHandlerCallbacks struct {
mu *sync.Mutex
callbacks map[unsafe.Pointer]DeferralCompletedHandlerCallback
}
func (m *deferralCompletedHandlerCallbacks) add(p unsafe.Pointer, v DeferralCompletedHandlerCallback) {
m.mu.Lock()
defer m.mu.Unlock()
m.callbacks[p] = v
}
func (m *deferralCompletedHandlerCallbacks) get(p unsafe.Pointer) (DeferralCompletedHandlerCallback, bool) {
m.mu.Lock()
defer m.mu.Unlock()
v, ok := m.callbacks[p]
return v, ok
}
func (m *deferralCompletedHandlerCallbacks) delete(p unsafe.Pointer) {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.callbacks, p)
}
// typedEventHandlerReleaseChannels keeps a map with channels
// used to keep a goroutine alive during the lifecycle of this object.
// This is required to avoid causing a deadlock error.
// See this: https://github.com/golang/go/issues/55015
type deferralCompletedHandlerReleaseChannels struct {
mu *sync.Mutex
chans map[unsafe.Pointer]chan struct{}
}
func (m *deferralCompletedHandlerReleaseChannels) acquire(p unsafe.Pointer) {
m.mu.Lock()
defer m.mu.Unlock()
c := make(chan struct{})
m.chans[p] = c
go func() {
// we need a timer to trick the go runtime into
// thinking there's still something going on here
// but we are only really interested in <-c
t := time.NewTimer(time.Minute)
for {
select {
case <-t.C:
t.Reset(time.Minute)
case <-c:
t.Stop()
return
}
}
}()
}
func (m *deferralCompletedHandlerReleaseChannels) release(p unsafe.Pointer) {
m.mu.Lock()
defer m.mu.Unlock()
if c, ok := m.chans[p]; ok {
close(c)
delete(m.chans, p)
}
}