podman-build/vendor/github.com/containers/libhvee/pkg/wmiext/invoke.go
2025-10-11 12:30:35 +09:00

133 lines
2.9 KiB
Go

//go:build windows
// +build windows
package wmiext
import (
"fmt"
"reflect"
"github.com/go-ole/go-ole"
"github.com/sirupsen/logrus"
)
type MethodExecutor struct {
err error
path string
method string
service *Service
inParam *Instance
outParam *Instance
}
// In sets an input parameter for the method of this invocation, converting appropriately
func (e *MethodExecutor) In(name string, value interface{}) *MethodExecutor {
if e.err == nil && e.inParam != nil {
switch t := value.(type) {
case *Instance:
var ref bool
if ref, e.err = e.inParam.IsReferenceProperty(name); e.err != nil {
return e
}
if !ref {
// Embedded Object
break
}
if value, e.err = t.Path(); e.err != nil {
return e
}
}
e.err = e.inParam.Put(name, value)
}
return e
}
// Out sets the specified output parameter, and assigns the value parameter to the result.
// The value parameter must be a reference to the field that should be set.
func (e *MethodExecutor) Out(name string, value interface{}) *MethodExecutor {
if e.err == nil && e.outParam != nil {
var variant *ole.VARIANT
var cimType CIMTYPE_ENUMERATION
var result interface{}
dest := reflect.ValueOf(value)
if dest.Kind() != reflect.Ptr {
e.err = fmt.Errorf("Out() on %q called with %T, out parameters must be a reference", name, value)
return e
}
dest = dest.Elem()
variant, cimType, _, e.err = e.outParam.GetAsVariant(name)
if e.err != nil || variant == nil {
return e
}
defer func() {
if err := variant.Clear(); err != nil {
logrus.Error(err)
}
}()
if _, ok := value.(**Instance); ok && cimType == CIM_REFERENCE {
path := variant.ToString()
result, e.err = e.service.GetObject(path)
if e.err != nil {
return e
}
} else {
target := reflect.ValueOf(value).Elem()
result, e.err = convertToGoType(variant, target, target.Type())
if e.err != nil {
return e
}
}
newValue := reflect.ValueOf(result)
if result == nil {
// Nil must be typed to the destination
newValue = reflect.Zero(dest.Type())
}
dest.Set(newValue)
}
return e
}
// Execute executes the method after in parameters have been specified using In()
func (e *MethodExecutor) Execute() *MethodExecutor {
defer e.cleanupInputs()
if e.err == nil {
e.outParam, e.err = e.service.ExecMethod(e.path, e.method, e.inParam)
}
return e
}
func (e *MethodExecutor) cleanupInputs() {
if e.inParam != nil {
e.inParam.Close()
e.inParam = nil
}
}
// End completes the method invocation and returns an error indicating the return
// code of the underlying method
func (e *MethodExecutor) End() error {
e.cleanupInputs()
if e.outParam != nil {
e.outParam.Close()
e.outParam = nil
}
return e.err
}
// Obtains the last error that occurred while building the invocation. Once
// an error has occurred, all future operations are treated as a no-op.
func (e *MethodExecutor) Error() error {
return e.err
}