Skip to content

Commit db83ecf

Browse files
committed
Ensure COM threading apartment for API calls
1 parent a63a4ec commit db83ecf

File tree

6 files changed

+665
-522
lines changed

6 files changed

+665
-522
lines changed

pkg/cim/wmi.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
package cim
55

66
import (
7+
"errors"
78
"fmt"
9+
"runtime"
810

911
"github.com/go-ole/go-ole"
1012
"github.com/go-ole/go-ole/oleutil"
1113
"github.com/microsoft/wmi/pkg/base/query"
1214
wmierrors "github.com/microsoft/wmi/pkg/errors"
1315
cim "github.com/microsoft/wmi/pkg/wmiinstance"
16+
"golang.org/x/sys/windows"
1417
"k8s.io/klog/v2"
1518
)
1619

@@ -248,3 +251,39 @@ func IgnoreNotFound(err error) error {
248251
}
249252
return err
250253
}
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

Comments
 (0)