mirror of
https://github.com/containers/podman.git
synced 2026-03-05 23:41:50 -05:00
with libhvee, we are able to do the basics of podman machine management on hyperv. The basic functions like init, rm, stop, and start are all functional. Start and stop will periodically throw a benign error processing the hyperv message being returned from the action. The error is described in the todo's below. notable items: * no podman commands will work (like ps, images, etc) * the machine must be initialized with --image-path and fed a custom image. * disk size is set to 100GB statically. * the vm joins the default hyperv network which is TCP/IP network based. * podman machine ssh does not work * podman machine set does not work * you can grab the ip address from hyperv and fake a machine connection with `podman system connection`. * when booting, use the hyperv console to know the boot is complete. TODOs: * podman machine ssh * podman machine set * podman machine rm needs force bool * disk size in NewMachine is set to 100GB * podman start needs to wait until fully booted * establish a boot complete signal from guest * implement gvproxy like user networking * fix benign failures in stop/start -> Error: error 2147749890 (FormatMessage failed with: The system cannot find message text for message number 0x%1 in the message file for %2.) [NO NEW TESTS NEEDED] Signed-off-by: Brent Baude <bbaude@redhat.com>
635 lines
19 KiB
Go
635 lines
19 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package wmiext
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"github.com/go-ole/go-ole"
|
|
)
|
|
|
|
const (
|
|
WmiPathKey = "__PATH"
|
|
)
|
|
|
|
var (
|
|
WindowsEpoch = time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
type Instance struct {
|
|
object *ole.IUnknown
|
|
vTable *IWbemClassObjectVtbl
|
|
service *Service
|
|
}
|
|
|
|
type IWbemClassObjectVtbl struct {
|
|
QueryInterface uintptr
|
|
AddRef uintptr
|
|
Release uintptr
|
|
GetQualifierSet uintptr
|
|
Get uintptr
|
|
Put uintptr
|
|
Delete uintptr
|
|
GetNames uintptr
|
|
BeginEnumeration uintptr
|
|
Next uintptr
|
|
EndEnumeration uintptr
|
|
GetPropertyQualifierSet uintptr
|
|
Clone uintptr
|
|
GetObjectText uintptr
|
|
SpawnDerivedClass uintptr
|
|
SpawnInstance uintptr
|
|
CompareTo uintptr
|
|
GetPropertyOrigin uintptr
|
|
InheritsFrom uintptr
|
|
GetMethod uintptr
|
|
PutMethod uintptr
|
|
DeleteMethod uintptr
|
|
BeginMethodEnumeration uintptr
|
|
NextMethod uintptr
|
|
EndMethodEnumeration uintptr
|
|
GetMethodQualifierSet uintptr
|
|
GetMethodOrigin uintptr
|
|
}
|
|
|
|
type CIMTYPE_ENUMERATION uint32
|
|
|
|
const (
|
|
CIM_ILLEGAL CIMTYPE_ENUMERATION = 0xFFF
|
|
CIM_EMPTY CIMTYPE_ENUMERATION = 0
|
|
CIM_SINT8 CIMTYPE_ENUMERATION = 16
|
|
CIM_UINT8 CIMTYPE_ENUMERATION = 17
|
|
CIM_SINT16 CIMTYPE_ENUMERATION = 2
|
|
CIM_UINT16 CIMTYPE_ENUMERATION = 18
|
|
CIM_SINT32 CIMTYPE_ENUMERATION = 3
|
|
CIM_UINT32 CIMTYPE_ENUMERATION = 19
|
|
CIM_SINT64 CIMTYPE_ENUMERATION = 20
|
|
CIM_UINT64 CIMTYPE_ENUMERATION = 21
|
|
CIM_REAL32 CIMTYPE_ENUMERATION = 4
|
|
CIM_REAL64 CIMTYPE_ENUMERATION = 5
|
|
CIM_BOOLEAN CIMTYPE_ENUMERATION = 11
|
|
CIM_STRING CIMTYPE_ENUMERATION = 8
|
|
CIM_DATETIME CIMTYPE_ENUMERATION = 101
|
|
CIM_REFERENCE CIMTYPE_ENUMERATION = 102
|
|
CIM_CHAR16 CIMTYPE_ENUMERATION = 103
|
|
CIM_OBJECT CIMTYPE_ENUMERATION = 13
|
|
CIM_FLAG_ARRAY CIMTYPE_ENUMERATION = 0x2000
|
|
)
|
|
|
|
type WBEM_FLAVOR_TYPE uint32
|
|
|
|
const (
|
|
WBEM_FLAVOR_DONT_PROPAGATE WBEM_FLAVOR_TYPE = 0
|
|
WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE WBEM_FLAVOR_TYPE = 0x1
|
|
WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS WBEM_FLAVOR_TYPE = 0x2
|
|
WBEM_FLAVOR_MASK_PROPAGATION WBEM_FLAVOR_TYPE = 0xf
|
|
WBEM_FLAVOR_OVERRIDABLE WBEM_FLAVOR_TYPE = 0
|
|
WBEM_FLAVOR_NOT_OVERRIDABLE WBEM_FLAVOR_TYPE = 0x10
|
|
WBEM_FLAVOR_MASK_PERMISSIONS WBEM_FLAVOR_TYPE = 0x10
|
|
WBEM_FLAVOR_ORIGIN_LOCAL WBEM_FLAVOR_TYPE = 0
|
|
WBEM_FLAVOR_ORIGIN_PROPAGATED WBEM_FLAVOR_TYPE = 0x20
|
|
WBEM_FLAVOR_ORIGIN_SYSTEM WBEM_FLAVOR_TYPE = 0x40
|
|
WBEM_FLAVOR_MASK_ORIGIN WBEM_FLAVOR_TYPE = 0x60
|
|
WBEM_FLAVOR_NOT_AMENDED WBEM_FLAVOR_TYPE = 0
|
|
WBEM_FLAVOR_AMENDED WBEM_FLAVOR_TYPE = 0x80
|
|
WBEM_FLAVOR_MASK_AMENDED WBEM_FLAVOR_TYPE = 0x80
|
|
)
|
|
|
|
func newInstance(object *ole.IUnknown, service *Service) *Instance {
|
|
instance := &Instance{
|
|
object: object,
|
|
vTable: (*IWbemClassObjectVtbl)(unsafe.Pointer(object.RawVTable)),
|
|
service: service,
|
|
}
|
|
|
|
return instance
|
|
}
|
|
|
|
// Close cleans up all memory associated with this instance.
|
|
func (i *Instance) Close() {
|
|
if i != nil && i.object != nil {
|
|
i.object.Release()
|
|
}
|
|
}
|
|
|
|
// GetClassName Gets the WMI class name for this WMI object instance
|
|
func (i *Instance) GetClassName() (className string, err error) {
|
|
return i.GetAsString(`__CLASS`)
|
|
}
|
|
|
|
// Path gets the WMI object path of this instance
|
|
func (i *Instance) Path() (string, error) {
|
|
ref, _, _, err := i.GetAsAny(WmiPathKey)
|
|
return ref.(string), err
|
|
}
|
|
|
|
// IsReferenceProperty returns whether the property is of type CIM_REFERENCE, a string which points to
|
|
// an object path of another instance.
|
|
func (i *Instance) IsReferenceProperty(name string) (bool, error) {
|
|
_, cimType, _, err := i.GetAsAny(name)
|
|
return cimType == CIM_REFERENCE, err
|
|
}
|
|
|
|
// SpawnInstance create a new WMI object instance that is zero-initialized. The returned instance
|
|
// will not respect expected default values, which must be populated by other means.
|
|
func (i *Instance) SpawnInstance() (instance *Instance, err error) {
|
|
var res uintptr
|
|
var newUnknown *ole.IUnknown
|
|
|
|
res, _, _ = syscall.SyscallN(
|
|
i.vTable.SpawnInstance, // IWbemClassObject::SpawnInstance(
|
|
uintptr(unsafe.Pointer(i.object)), // IWbemClassObject ptr
|
|
uintptr(0), // [in] long lFlags,
|
|
uintptr(unsafe.Pointer(&newUnknown))) // [out] IWbemClassObject **ppNewInstance)
|
|
if res != 0 {
|
|
return nil, ole.NewError(res)
|
|
}
|
|
|
|
return newInstance(newUnknown, i.service), nil
|
|
}
|
|
|
|
// CloneInstance create a new cloned copy of this WMI instance.
|
|
func (i *Instance) CloneInstance() (*Instance, error) {
|
|
classObj := i.object
|
|
vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
|
|
var cloned *ole.IUnknown
|
|
|
|
ret, _, _ := syscall.SyscallN(
|
|
vTable.Clone, // IWbemClassObject::Clone(
|
|
uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr
|
|
uintptr(unsafe.Pointer(&cloned))) // [out] IWbemClassObject **ppCopy)
|
|
if ret != 0 {
|
|
return nil, ole.NewError(ret)
|
|
}
|
|
|
|
return newInstance(cloned, i.service), nil
|
|
}
|
|
|
|
// PutAll sets all fields of this instance to the passed src parameter's fields, converting accordingly.
|
|
// The src parameter must be a pointer to a struct, otherwise an error will be returned.
|
|
func (i *Instance) PutAll(src interface{}) error {
|
|
val := reflect.ValueOf(src)
|
|
if val.Kind() == reflect.Pointer {
|
|
val = val.Elem()
|
|
}
|
|
|
|
if val.Kind() != reflect.Struct {
|
|
return errors.New("not a struct or pointer to struct")
|
|
}
|
|
|
|
props, err := i.GetAllProperties()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return i.instancePutAllTraverse(val, props)
|
|
}
|
|
|
|
func (i *Instance) instancePutAllTraverse(val reflect.Value, propMap map[string]interface{}) error {
|
|
for j := 0; j < val.NumField(); j++ {
|
|
fieldVal := val.Field(j)
|
|
fieldType := val.Type().Field(j)
|
|
|
|
if fieldType.Type.Kind() == reflect.Struct && fieldType.Anonymous {
|
|
if err := i.instancePutAllTraverse(fieldVal, propMap); err != nil {
|
|
return err
|
|
}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(fieldType.Name, "S__") {
|
|
continue
|
|
}
|
|
|
|
if !fieldType.IsExported() {
|
|
continue
|
|
}
|
|
|
|
if _, exists := propMap[fieldType.Name]; !exists {
|
|
continue
|
|
}
|
|
|
|
if fieldVal.Kind() == reflect.String && fieldVal.Len() == 0 {
|
|
continue
|
|
}
|
|
|
|
if err := i.Put(fieldType.Name, fieldVal.Interface()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Put sets the specified property to the passed Golang value, converting appropriately.
|
|
func (i *Instance) Put(name string, value interface{}) (err error) {
|
|
var variant ole.VARIANT
|
|
|
|
switch cast := value.(type) {
|
|
case ole.VARIANT:
|
|
variant = cast
|
|
case *ole.VARIANT:
|
|
variant = *cast
|
|
default:
|
|
variant, err = NewAutomationVariant(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var wszName *uint16
|
|
if wszName, err = syscall.UTF16PtrFromString(name); err != nil {
|
|
return
|
|
}
|
|
|
|
classObj := i.object
|
|
vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
|
|
res, _, _ := syscall.SyscallN(
|
|
vTable.Put, // IWbemClassObject::Put(
|
|
uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr
|
|
uintptr(unsafe.Pointer(wszName)), // [in] LPCWSTR wszName,
|
|
uintptr(0), // [in] long lFlags,
|
|
uintptr(unsafe.Pointer(&variant)), // [in] VARIANT *pVal,
|
|
uintptr(0)) // [in] CIMTYPE Type)
|
|
if res != 0 {
|
|
return ole.NewError(res)
|
|
}
|
|
|
|
_ = variant.Clear()
|
|
return
|
|
}
|
|
|
|
// GetCimText returns the CIM XML representation of this instance. Some WMI methods use a string
|
|
// parameter to represent a full complex object, and this method is used to generate
|
|
// the expected format.
|
|
func (i *Instance) GetCimText() string {
|
|
type wmiWbemTxtSrcVtable struct {
|
|
QueryInterface uintptr
|
|
AddRef uintptr
|
|
Release uintptr
|
|
GetTxt uintptr
|
|
}
|
|
const CIM_XML_FORMAT = 1
|
|
|
|
classObj := i.object
|
|
|
|
vTable := (*wmiWbemTxtSrcVtable)(unsafe.Pointer(wmiWbemTxtLocator.RawVTable))
|
|
var retString *uint16
|
|
res, _, _ := syscall.SyscallN(
|
|
vTable.GetTxt, // IWbemObjectTextSrc::GetText()
|
|
uintptr(unsafe.Pointer(wmiWbemLocator)), // IWbemObjectTextSrc ptr
|
|
uintptr(0), // [in] long lFlags
|
|
uintptr(unsafe.Pointer(classObj)), // [in] IWbemClassObject *pObj
|
|
uintptr(CIM_XML_FORMAT), // [in] ULONG uObjTextFormat,
|
|
uintptr(0), // [in] IWbemContext *pCtx,
|
|
uintptr(unsafe.Pointer(&retString))) // [out] BSTR *strText)
|
|
if res != 0 {
|
|
return ""
|
|
}
|
|
itemStr := ole.BstrToString(retString)
|
|
return itemStr
|
|
}
|
|
|
|
// GetAll gets all fields that map to a target struct and populates all struct fields according to
|
|
// the expected type information. The target parameter should be a pointer to a struct, and
|
|
// will return an error otherwise.
|
|
func (i *Instance) GetAll(target interface{}) error {
|
|
elem := reflect.ValueOf(target)
|
|
if elem.Kind() != reflect.Ptr || elem.IsNil() {
|
|
return errors.New("invalid destination type for mapping a WMI instance to an object")
|
|
}
|
|
|
|
// deref pointer
|
|
elem = elem.Elem()
|
|
var err error
|
|
|
|
if err = i.BeginEnumeration(); err != nil {
|
|
return err
|
|
}
|
|
|
|
properties := make(map[string]*ole.VARIANT)
|
|
|
|
for {
|
|
var name string
|
|
var value *ole.VARIANT
|
|
var done bool
|
|
|
|
if done, name, value, _, _, err = i.NextAsVariant(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if done {
|
|
break
|
|
}
|
|
|
|
if value != nil {
|
|
properties[name] = value
|
|
}
|
|
}
|
|
|
|
defer func() {
|
|
for _, v := range properties {
|
|
_ = v.Clear()
|
|
}
|
|
}()
|
|
|
|
_ = i.EndEnumeration()
|
|
|
|
return i.instanceGetAllPopulate(elem, elem.Type(), properties)
|
|
}
|
|
|
|
// GetAsAny gets a property and converts it to a Golang type that matches the internal
|
|
// variant automation type passed back from WMI. For usage with predictable static
|
|
// type mapping, use GetAsString(), GetAsUint(), or GetAll() instead of this method.
|
|
func (i *Instance) GetAsAny(name string) (interface{}, CIMTYPE_ENUMERATION, WBEM_FLAVOR_TYPE, error) {
|
|
variant, cimType, flavor, err := i.GetAsVariant(name)
|
|
if err != nil {
|
|
return nil, cimType, flavor, err
|
|
}
|
|
defer variant.Clear()
|
|
|
|
// Since there is no type information only perform the stock conversion
|
|
result := convertToGenericValue(variant)
|
|
|
|
return result, cimType, flavor, err
|
|
}
|
|
|
|
// GetAsString gets a property value as a string value, converting if necessary
|
|
func (i *Instance) GetAsString(name string) (value string, err error) {
|
|
variant, _, _, err := i.GetAsVariant(name)
|
|
if err != nil || variant == nil {
|
|
return "", err
|
|
}
|
|
defer variant.Clear()
|
|
|
|
// TODO: replace with something better
|
|
return fmt.Sprintf("%v", convertToGenericValue(variant)), nil
|
|
}
|
|
|
|
// GetAsUint gets a property value as a uint value, if conversion is possible. Otherwise,
|
|
// returns an error.
|
|
func (i *Instance) GetAsUint(name string) (uint, error) {
|
|
val, _, _, err := i.GetAsAny(name)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch ret := val.(type) {
|
|
case int:
|
|
return uint(ret), nil
|
|
case int8:
|
|
return uint(ret), nil
|
|
case int16:
|
|
return uint(ret), nil
|
|
case int32:
|
|
return uint(ret), nil
|
|
case int64:
|
|
return uint(ret), nil
|
|
case uint:
|
|
return ret, nil
|
|
case uint8:
|
|
return uint(ret), nil
|
|
case uint16:
|
|
return uint(ret), nil
|
|
case uint32:
|
|
return uint(ret), nil
|
|
case uint64:
|
|
return uint(ret), nil
|
|
case string:
|
|
parse, err := strconv.ParseUint(ret, 10, 64)
|
|
return uint(parse), err
|
|
default:
|
|
return 0, fmt.Errorf("type conversion from %T on param %s not supported", val, name)
|
|
}
|
|
}
|
|
|
|
// GetAsVariant obtains a specified property value, if it exists.
|
|
func (i *Instance) GetAsVariant(name string) (*ole.VARIANT, CIMTYPE_ENUMERATION, WBEM_FLAVOR_TYPE, error) {
|
|
var variant ole.VARIANT
|
|
var err error
|
|
var wszName *uint16
|
|
var cimType CIMTYPE_ENUMERATION
|
|
var flavor WBEM_FLAVOR_TYPE
|
|
|
|
if wszName, err = syscall.UTF16PtrFromString(name); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
|
|
classObj := i.object
|
|
vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
|
|
|
|
res, _, _ := syscall.SyscallN(
|
|
vTable.Get, // IWbemClassObject::Get(
|
|
uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr
|
|
uintptr(unsafe.Pointer(wszName)), // [in] LPCWSTR wszName,
|
|
uintptr(0), // [in] long lFlags,
|
|
uintptr(unsafe.Pointer(&variant)), // [out] VARIANT *pVal,
|
|
uintptr(unsafe.Pointer(&cimType)), // [out, optional] CIMTYPE *pType,
|
|
uintptr(unsafe.Pointer(&flavor))) // [out, optional] long *plFlavor)
|
|
if res != 0 {
|
|
return nil, 0, 0, ole.NewError(res)
|
|
}
|
|
|
|
return &variant, cimType, flavor, nil
|
|
}
|
|
|
|
// Next retrieves the next property as a Golang type when iterating the properties using an enumerator
|
|
// created by BeginEnumeration(). The returned value's type represents the internal automation type
|
|
// used by WMI. It is usually preferred to use GetAsXXX(), GetAll(), or GetAll Properties() over this
|
|
// method.
|
|
func (i *Instance) Next() (done bool, name string, value interface{}, cimType CIMTYPE_ENUMERATION, flavor WBEM_FLAVOR_TYPE, err error) {
|
|
var variant *ole.VARIANT
|
|
done, name, variant, cimType, flavor, err = i.NextAsVariant()
|
|
|
|
if err == nil && !done {
|
|
defer variant.Clear()
|
|
value = convertToGenericValue(variant)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// NextAsVariant retrieves the next property as a VARIANT type when iterating the properties using an enumerator
|
|
// created by BeginEnumeration(). The returned value's type represents the internal automation type
|
|
// used by WMI. It is usually preferred to use GetAsXXX(), GetAll(), or GetAllProperties() over this
|
|
// method. Callers are responsible for clearing the VARIANT, otherwise associated memory will leak.
|
|
func (i *Instance) NextAsVariant() (bool, string, *ole.VARIANT, CIMTYPE_ENUMERATION, WBEM_FLAVOR_TYPE, error) {
|
|
var res uintptr
|
|
var strName *uint16
|
|
var variant ole.VARIANT
|
|
var cimType CIMTYPE_ENUMERATION
|
|
var flavor WBEM_FLAVOR_TYPE
|
|
|
|
res, _, _ = syscall.SyscallN(
|
|
i.vTable.Next, // IWbemClassObject::Next(
|
|
uintptr(unsafe.Pointer(i.object)), // IWbemClassObject ptr
|
|
uintptr(0), // [in] long lFlags,
|
|
uintptr(unsafe.Pointer(&strName)), // [out] BSTR *strName,
|
|
uintptr(unsafe.Pointer(&variant)), // [out] VARIANT *pVal,
|
|
uintptr(unsafe.Pointer(&cimType)), // [out, optional] CIMTYPE *pType,
|
|
uintptr(unsafe.Pointer(&flavor))) // [out, optional] long *plFlavor
|
|
if res < 0 {
|
|
return false, "", nil, cimType, flavor, ole.NewError(res)
|
|
}
|
|
|
|
if res == WBEM_S_NO_MORE_DATA {
|
|
return true, "", nil, cimType, flavor, nil
|
|
}
|
|
|
|
defer ole.SysFreeString((*int16)(unsafe.Pointer(strName)))
|
|
name := ole.BstrToString(strName)
|
|
|
|
return false, name, &variant, cimType, flavor, nil
|
|
}
|
|
|
|
// GetAllProperties gets all properties on this instance. The returned map is keyed by the field name and the value
|
|
// is a Golang type which matches the WMI internal implementation. For static type conversions,
|
|
// it's recommended to use either GetAll(), which uses struct fields for type information, or
|
|
// the GetAsXXX() methods.
|
|
func (i *Instance) GetAllProperties() (map[string]interface{}, error) {
|
|
var err error
|
|
properties := make(map[string]interface{})
|
|
|
|
if err = i.BeginEnumeration(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer i.EndEnumeration()
|
|
|
|
for {
|
|
var name string
|
|
var value interface{}
|
|
var done bool
|
|
|
|
if done, name, value, _, _, err = i.Next(); err != nil || done {
|
|
return properties, err
|
|
}
|
|
|
|
properties[name] = value
|
|
}
|
|
}
|
|
|
|
// GetMethodParameters returns a WMI class object which represents the [in] method parameters for a method invocation.
|
|
// This is an advanced method, used for dynamic introspection or manual method invocation. In most
|
|
// cases it is recommended to use BeginInvoke() instead, which constructs the parameter payload
|
|
// automatically.
|
|
func (i *Instance) GetMethodParameters(method string) (*Instance, error) {
|
|
var err error
|
|
var res uintptr
|
|
var inSignature *ole.IUnknown
|
|
|
|
var wszName *uint16
|
|
if wszName, err = syscall.UTF16PtrFromString(method); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res, _, _ = syscall.SyscallN(
|
|
i.vTable.GetMethod, // IWbemClassObject::GetMethod(
|
|
uintptr(unsafe.Pointer(i.object)), // IWbemClassObject ptr
|
|
uintptr(unsafe.Pointer(wszName)), // [in] LPCWSTR wszName
|
|
uintptr(0), // [in] long lFlags,
|
|
uintptr(unsafe.Pointer(&inSignature)), // [out] IWbemClassObject **ppInSignature,
|
|
uintptr(0)) // [out] IWbemClassObject **ppOutSignature)
|
|
if res != 0 {
|
|
return nil, ole.NewError(res)
|
|
}
|
|
|
|
return newInstance(inSignature, i.service), nil
|
|
}
|
|
|
|
func (i *Instance) instanceGetAllPopulate(elem reflect.Value, elemType reflect.Type, properties map[string]*ole.VARIANT) error {
|
|
var err error
|
|
|
|
for j := 0; j < elemType.NumField(); j++ {
|
|
fieldType := elemType.Field(j)
|
|
fieldVal := elem.Field(j)
|
|
|
|
if !fieldType.IsExported() {
|
|
continue
|
|
}
|
|
|
|
if fieldType.Type.Kind() == reflect.Struct && fieldType.Anonymous {
|
|
if err := i.instanceGetAllPopulate(fieldVal, fieldType.Type, properties); err != nil {
|
|
return err
|
|
}
|
|
continue
|
|
}
|
|
|
|
fieldName := fieldType.Name
|
|
|
|
if strings.HasPrefix(fieldName, "S__") {
|
|
fieldName = fieldName[1:]
|
|
}
|
|
if variant, ok := properties[fieldName]; ok {
|
|
var val interface{}
|
|
if val, err = convertToGoType(variant, fieldVal, fieldType.Type); err != nil {
|
|
return err
|
|
}
|
|
|
|
if val != nil {
|
|
fieldVal.Set(reflect.ValueOf(val))
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// BeginEnumeration begins iterating the property list on this instance. This is an advanced method.
|
|
// In most cases, the GetAsXXX() methods, GetAll(), and GetAllProperties() methods should be
|
|
// preferred.
|
|
func (i *Instance) BeginEnumeration() error {
|
|
classObj := i.object
|
|
vTable := (*IWbemClassObjectVtbl)(unsafe.Pointer(classObj.RawVTable))
|
|
|
|
result, _, _ := syscall.SyscallN(
|
|
vTable.BeginEnumeration, // IWbemClassObject::BeginEnumeration(
|
|
uintptr(unsafe.Pointer(classObj)), // IWbemClassObject ptr,
|
|
uintptr(0)) // [in] long lEnumFlags) // 0 = defaults
|
|
if result != 0 {
|
|
return ole.NewError(result)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// EndEnumeration completes iterating a property list on this instance. This is an advanced method.
|
|
// In most cases, the GetAsXXX() methods, GetAll(), and GetAllProperties() methods
|
|
// should be preferred.
|
|
func (i *Instance) EndEnumeration() error {
|
|
res, _, _ := syscall.SyscallN(
|
|
i.vTable.EndEnumeration, // IWbemClassObject::EndEnumeration(
|
|
uintptr(unsafe.Pointer(i.object))) // IWbemClassObject ptr)
|
|
if res != 0 {
|
|
return ole.NewError(res)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// BeginInvoke invokes a method on this Instance. Returns a MethodExecutor builder object
|
|
// that is used to construct the input parameters (via calls to In()), perform the
|
|
// invocation (using calls to Execute()), retrieve output parameters (via calls to
|
|
// Out()), and finally the method return value (using a call to End())
|
|
func (i *Instance) BeginInvoke(method string) *MethodExecutor {
|
|
objPath, err := i.Path()
|
|
if err != nil {
|
|
return &MethodExecutor{err: err}
|
|
}
|
|
|
|
var class, inParam *Instance
|
|
if class, err = i.service.GetClassInstance(i); err == nil {
|
|
inParam, err = class.GetMethodParameters(method)
|
|
class.Close()
|
|
}
|
|
|
|
return &MethodExecutor{method: method, path: objPath, service: i.service, inParam: inParam, err: err}
|
|
}
|