Files
2024-11-01 17:43:06 +00:00

113 lines
2.4 KiB
Go

// Copyright (c) 2022 Tailscale Inc & AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build windows
package com
import (
"syscall"
"unsafe"
"github.com/dblohm7/wingoes"
)
// IUnknown is the base COM interface.
type IUnknown interface {
QueryInterface(iid *IID) (IUnknown, error)
AddRef() int32
Release() int32
}
// This is a sentinel that indicates that a struct implements the COM ABI.
// Only IUnknownABI should implement this.
type hasVTable interface {
vtable() *uintptr
}
// IUnknownABI describes the ABI of the IUnknown interface (ie, a vtable).
type IUnknownABI struct {
Vtbl *uintptr
}
func (abi IUnknownABI) vtable() *uintptr {
return abi.Vtbl
}
// ABI is a type constraint allowing the COM ABI, or any struct that embeds it.
type ABI interface {
hasVTable
}
// PUnknown is a type constraint for types that both implement IUnknown and
// are also pointers to a COM ABI.
type PUnknown[A ABI] interface {
IUnknown
*A
}
// ABIReceiver is the type that receives COM interface pointers from COM
// method outparams.
type ABIReceiver **IUnknownABI
// NewABIReceiver instantiates a new ABIReceiver.
func NewABIReceiver() ABIReceiver {
return ABIReceiver(new(*IUnknownABI))
}
// ReleaseABI releases a COM object. Finalizers must always invoke this function
// when destroying COM interfaces.
func ReleaseABI(p **IUnknownABI) {
(*p).Release()
}
// QueryInterface implements the QueryInterface call for a COM interface pointer.
// iid is the desired interface ID.
func (abi *IUnknownABI) QueryInterface(iid *IID) (IUnknown, error) {
var punk *IUnknownABI
r, _, _ := syscall.Syscall(
*(abi.Vtbl),
3,
uintptr(unsafe.Pointer(abi)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&punk)),
)
if e := wingoes.ErrorFromHRESULT(wingoes.HRESULT(r)); e.Failed() {
return nil, e
}
return punk, nil
}
// AddRef implements the AddRef call for a COM interface pointer.
func (abi *IUnknownABI) AddRef() int32 {
method := unsafe.Slice(abi.Vtbl, 3)[1]
r, _, _ := syscall.Syscall(
method,
1,
uintptr(unsafe.Pointer(abi)),
0,
0,
)
return int32(r)
}
// Release implements the Release call for a COM interface pointer.
func (abi *IUnknownABI) Release() int32 {
method := unsafe.Slice(abi.Vtbl, 3)[2]
r, _, _ := syscall.Syscall(
method,
1,
uintptr(unsafe.Pointer(abi)),
0,
0,
)
return int32(r)
}