cswin32-com

Implements struct-based COM interop in MSBuild using CsWin32 patterns without built-in marshalling.

1.2k|337|Updated Oct 13, 2022
One-click install
npx skills add https://github.com/dotnet/dotnet --skill cswin32-com
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: cswin32-com
Source: https://github.com/dotnet/dotnet/tree/main/src/msbuild/.github/skills/cswin32-com
Command: npx skills add https://github.com/dotnet/dotnet --skill cswin32-com

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

Migrating MSBuild's COM interop away from [ComImport] and built-in marshalling to AOT-compatible, struct-based CsWin32 patterns requires precise knowledge of vtable layouts, lifetime management, and error-handling parity that is easy to get wrong.

Core Features & Use Cases

  • Manual COM struct definitions: Guides defining interfaces not in Win32 metadata (WMI IWbemLocator, Fusion IAssemblyCache, Setup Configuration) with correct delegate* unmanaged[Stdcall] vtable slots and dual-target IComIID shapes for net472 and .NET.
  • Lifetime management patterns: Enforces ComScope<T> for transient pointers, using BSTR for COM strings, and AgileComPointer<T> for pointers stored in class fields, preventing leaks and apartment-agility hazards.
  • Error-handling parity and test mocking: Preserves throw-vs-return contracts when migrating from [ComImport], and bridges managed mocks to struct-based COM via CCW pointers from Marshal.GetComInterfaceForObject.
  • Use Case: When adding WMI-based queries to MSBuild tasks, use this Skill to define the IWbemLocator/IWbemServices structs, activate them via ComClassFactory.TryCreate, and scope every pointer correctly.

Quick Start

Ask the assistant to define a manual CsWin32 COM struct for the WMI IWbemLocator interface with proper ComScope lifetime handling and AOT-compatible activation.

Frequently Asked Questions about cswin32-com

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I define a COM interface not in Win32 metadata with CsWin32?▼

Define a manual struct implementing IComIID in its own folder, with a private void** _lpVtbl field and delegate* unmanaged[Stdcall] casts for each vtable slot. Exclude it from source builds via Compile Remove, and spell out both the static-abstract and instance IComIID shapes for dual-targeting.

How do I manage COM pointer lifetimes in struct-based interop?▼

Use ComScope<T> with a using declaration for every transient COM pointer from CoCreateInstance, QueryInterface, or enumerators; it Releases on dispose and implicitly converts to T** for out-params. For pointers stored in class fields, use AgileComPointer<T>, which registers in the Global Interface Table.

Can struct-based COM interop be mocked in unit tests?▼

Yes, by bridging through the built-in COM marshaller: the mock implements the managed interface and the test passes a CCW pointer from Marshal.GetComInterfaceForObject to the struct-based API. The mock must write all out-params and throw COMException rather than assert, since exception identity is lost across the boundary.

Does CsWin32 COM interop work on both .NET Framework and modern .NET?▼

Yes, but IComIID has two shapes: static-abstract on .NET 7+ and instance-based on net472/netstandard2.0. Manual structs must implement both arms with #if NET, while CsWin32-generated structs pick the correct shape automatically since version 0.3.287.

Why does migrating from [ComImport] to struct-based COM change error handling?▼

Struct-based COM returns raw HRESULTs instead of throwing automatically, so each call site must explicitly call ThrowOnFailure or branch on the HRESULT. When the top-level caller swallows COMException, helpers should return default or false instead of throwing exceptions that are immediately discarded.