|  | 
| 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