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.