|
4 | 4 | package cim
|
5 | 5 |
|
6 | 6 | import (
|
| 7 | + "errors" |
7 | 8 | "fmt"
|
| 9 | + "runtime" |
8 | 10 |
|
9 | 11 | "github.com/go-ole/go-ole"
|
10 | 12 | "github.com/go-ole/go-ole/oleutil"
|
11 | 13 | "github.com/microsoft/wmi/pkg/base/query"
|
12 | 14 | wmierrors "github.com/microsoft/wmi/pkg/errors"
|
13 | 15 | cim "github.com/microsoft/wmi/pkg/wmiinstance"
|
| 16 | + "golang.org/x/sys/windows" |
14 | 17 | "k8s.io/klog/v2"
|
15 | 18 | )
|
16 | 19 |
|
@@ -248,3 +251,39 @@ func IgnoreNotFound(err error) error {
|
248 | 251 | }
|
249 | 252 | return err
|
250 | 253 | }
|
| 254 | + |
| 255 | +// WithCOMThread runs the given function `fn` on a locked OS thread |
| 256 | +// with COM initialized using COINIT_MULTITHREADED. |
| 257 | +// |
| 258 | +// This is necessary for using COM/OLE APIs directly (e.g., via go-ole), |
| 259 | +// because COM requires that initialization and usage occur on the same thread. |
| 260 | +// |
| 261 | +// It performs the following steps: |
| 262 | +// - Locks the current goroutine to its OS thread |
| 263 | +// - Calls ole.CoInitializeEx with COINIT_MULTITHREADED |
| 264 | +// - Executes the user-provided function |
| 265 | +// - Uninitializes COM |
| 266 | +// - Unlocks the thread |
| 267 | +// |
| 268 | +// If COM initialization fails, or if the user's function returns an error, |
| 269 | +// that error is returned by WithCOMThread. |
| 270 | +func WithCOMThread(fn func() error) error { |
| 271 | + runtime.LockOSThread() |
| 272 | + defer runtime.UnlockOSThread() |
| 273 | + |
| 274 | + if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil { |
| 275 | + var oleError *ole.OleError |
| 276 | + if errors.As(err, &oleError) && oleError != nil && oleError.Code() == uintptr(windows.S_FALSE) { |
| 277 | + klog.V(10).Infof("COM library has been already initialized for the calling thread, proceeding to the function with no error") |
| 278 | + err = nil |
| 279 | + } |
| 280 | + if err != nil { |
| 281 | + return err |
| 282 | + } |
| 283 | + } else { |
| 284 | + klog.V(10).Infof("COM library is initialized for the calling thread") |
| 285 | + } |
| 286 | + defer ole.CoUninitialize() |
| 287 | + |
| 288 | + return fn() |
| 289 | +} |
0 commit comments