// SPDX-License-Identifier: Apache-2.0 // // Copyright The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build windows package mi import ( "errors" "fmt" "syscall" "unsafe" "golang.org/x/sys/windows" ) type Instance struct { ft *InstanceFT classDecl *ClassDecl serverName *uint16 nameSpace *uint16 _ [4]uintptr } type InstanceFT struct { Clone uintptr Destruct uintptr Delete uintptr IsA uintptr GetClassName uintptr SetNameSpace uintptr GetNameSpace uintptr GetElementCount uintptr AddElement uintptr SetElement uintptr SetElementAt uintptr GetElement uintptr GetElementAt uintptr ClearElement uintptr ClearElementAt uintptr GetServerName uintptr SetServerName uintptr GetClass uintptr } type ClassDecl struct { Flags uint32 Code uint32 Name *uint16 Mqualifiers uintptr NumQualifiers uint32 Mproperties uintptr NumProperties uint32 Size uint32 SuperClass *uint16 SuperClassDecl uintptr Methods uintptr NumMethods uint32 Schema uintptr ProviderFT uintptr OwningClass uintptr } // clone returns a copy of the instance that stays valid until it is deleted. // // https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_instance_clone func (instance *Instance) clone() (*Instance, error) { if instance == nil || instance.ft == nil { return nil, ErrNotInitialized } var clone *Instance r0, _, _ := syscall.SyscallN(instance.ft.Clone, uintptr(unsafe.Pointer(instance)), uintptr(unsafe.Pointer(&clone))) if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { return nil, result } return clone, nil } func (instance *Instance) Delete() error { if instance == nil || instance.ft == nil { return ErrNotInitialized } r0, _, _ := syscall.SyscallN(instance.ft.Delete, uintptr(unsafe.Pointer(instance))) if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { return result } return nil } // ElementName is the UTF-16 name of an instance element. type ElementName *uint16 func NewElementName(elementName string) (ElementName, error) { return windows.UTF16PtrFromString(elementName) } // GetElement gets the element with the given name. To read the same element // from many instances, convert the name once with [NewElementName] and use // [Instance.GetElementByName]. func (instance *Instance) GetElement(elementName string) (Element, error) { if instance == nil || instance.ft == nil { return Element{}, ErrNotInitialized } elementNameUTF16, err := NewElementName(elementName) if err != nil { return Element{}, fmt.Errorf("failed to convert element name %s to UTF-16: %w", elementName, err) } return instance.GetElementByName(elementNameUTF16) } // GetElementByName gets the element with the given name. Strings and arrays // in the returned element point into the instance and are only valid while // the instance is. // // https://learn.microsoft.com/en-us/windows/win32/api/mi/nf-mi-mi_instance_getelement func (instance *Instance) GetElementByName(elementName ElementName) (Element, error) { if instance == nil || instance.ft == nil { return Element{}, ErrNotInitialized } if elementName == nil { return Element{}, ErrInvalidElementName } // MI_Value is a union sized to its largest member. On 64-bit MI_Datetime is // 36 bytes and the union rounds up to 40 bytes for 8-byte alignment, so a // full MI_Value must be provided; the previous single-word buffer let the // provider write past it and corrupt the stack for array or datetime // elements. Word 0 holds the scalar/pointer/array-data; word 1 holds the // array element count for array types. var ( valueBuf [5]uint64 valueType ValueType flags uint32 ) r0, _, _ := syscall.SyscallN( instance.ft.GetElement, uintptr(unsafe.Pointer(instance)), uintptr(unsafe.Pointer(elementName)), uintptr(unsafe.Pointer(&valueBuf)), uintptr(unsafe.Pointer(&valueType)), uintptr(unsafe.Pointer(&flags)), 0, ) if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { return Element{}, result } return Element{ value: uintptr(valueBuf[0]), arrayLen: uint32(valueBuf[1]), valueType: valueType, flags: flags, raw: valueBuf, }, nil } func (instance *Instance) GetElementCount() (uint32, error) { if instance == nil || instance.ft == nil { return 0, ErrNotInitialized } var count uint32 r0, _, _ := syscall.SyscallN( instance.ft.GetElementCount, uintptr(unsafe.Pointer(instance)), uintptr(unsafe.Pointer(&count)), ) if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { return 0, result } return count, nil } func (instance *Instance) GetClassName() (string, error) { if instance == nil || instance.ft == nil { return "", ErrNotInitialized } var classNameUTF16 *uint16 r0, _, _ := syscall.SyscallN( instance.ft.GetClassName, uintptr(unsafe.Pointer(instance)), uintptr(unsafe.Pointer(&classNameUTF16)), ) if result := ResultError(r0); !errors.Is(result, MI_RESULT_OK) { return "", result } if classNameUTF16 == nil { return "", errors.New("class name is nil") } return windows.UTF16PtrToString(classNameUTF16), nil }