Classic COM API Support Plan

September 15, 2026 ยท View on GitHub

This document is the user-facing capability map and roadmap for the Classic COM interface portion of Windows.Win32.winmd.

It answers three practical questions:

  1. Which COM APIs work today?
  2. Which APIs work only for a limited native contract or through an unsafe declaration?
  3. Which APIs are not currently possible, and what work would unlock them?

For ABI details and implementation architecture, see Classic COM support. For raw unsafe design, see Classic COM raw unsafe. For usage examples, see the Classic COM JavaScript guide. Automatic high-level unsafe companion generation is specified in Generated high-level unsafe COM companions.

Current baseline

The current census was produced from Microsoft.Windows.SDK.Win32Metadata 71.0.14-preview:

Windows.Win32.winmd SHA-256:
B64EE4818A7ED9F9D135038D58C51BD08369184D4D5ED428F20E9DE55DF8121D
ResultInterfacesPercentage
Externally addressable Classic COM interfaces7,929100%
Complete safe generation5,72172.15%
Rejected because at least one contract is incomplete2,20827.85%

The denominator contains addressable COM interface identities, not flat Win32 DLL exports. A complete interface means that its full inherited vtable can be generated without guessing ABI, layout, count relationships, ownership, or cleanup.

The 5,721 figure is semantic codegen coverage, not a claim that every interface has a dedicated live Windows test or can be activated on every machine.

PR4 promotes 24 previously raw-metadata-complete interfaces by naming otherwise validated normal overloads explicitly. Every member of a formerly rejected same-shape/arity or projected-buffer group receives <camelName>AtSlot<absoluteVtableSlot>; the ambiguous unsuffixed method is not emitted. Existing distinguishable overload dispatch, native ABI/conversion/ lifetime plans, and already-supported generated output remain unchanged. Alias collisions and synthesized/dynamic-IID/non-normal groups still fail closed. This needs no further manifest version change and does not turn the PR3 bounded-copy facades into complete native interface projections. See overload usage and limits.

Reproduce the census with:

npx dynwinrt-codegen com-census `
  --winmd C:\path\to\Windows.Win32.winmd `
  --json

How we describe support

LabelWhat users can expect
Verified liveGenerated code has been exercised against a real Windows COM implementation.
Safe generatedThe complete interface passes metadata, ABI, layout, ownership, and cleanup validation. It may still require hardware, software, or an application-specific acquisition path.
Semantic unsafeThe caller manually declares a trusted IID and signature while selecting a dynwinrt-managed ownership plan such as COM, BSTR, or CoTaskMem.
Raw unsafeThe caller supplies native memory, pointers, pointer slots, layout, and cleanup. dynwinrt guarantees only ABI execution.
Not supportedThe required calling convention, threading, marshaling, server, or runtime primitive is unavailable.

Safe generation is determined per complete interface and metadata version. A safe wrapper is not generated from only the methods an application happens to call, and safe generation never falls back to an unsafe layer.

APIs users can rely on today

These APIs represent the strongest support level because they combine complete generation with real runtime coverage.

AreaAPI examplesWhat is covered
COM fundamentalsIUnknown, IClassFactoryInheritance, QueryInterface, dynamic-IID output, owned +1 references, class factory acquisition, and server locking.
Memory and streamsIMalloc, ISequentialStream, IStreamDirect scalar/pointer/void returns, allocator identity, byte buffers, actual lengths, seek, STATSTG, interface outputs, and failure cleanup.
Binding and errorsIBindCtx, ICreateErrorInfo, IErrorInfoValidated POD layout, acquisition helpers, wide strings, BSTR output, thread-local error state, and deterministic release.
Shell linksIShellLinkW, IPersistFileCoclass activation, wide strings, enums, nested POD output, persistence interfaces, and QueryInterface views.
Shell UITaskbarList, ITaskbarList3, FileOperation, FileOpenDialogCoclass construction, inherited slots, HWND input, unsigned flags, u64, and option/state round trips.
Property SystemIPropertyStorePROPERTYKEY, owned PROPVARIANT values, Set/Get/Commit, and cleanup.
Automation coreIDispatchGetIDsOfNames, natural-order DISPPARAMS, optional Invoke outputs, EXCEPINFO, VARIANT results, and HRESULT failure information.
ImagingIWICImagingFactoryExplicit CLSID activation and typed interface outputs.
WinRT interopIDataTransferManagerInterop, ISystemMediaTransportControlsInteropHWND plus REFIID bridges and owned WinRT interface output.
JavaScript COM sinksIFileDialogEvents, IDropTargetGenerated JavaScript implementations, real Advise/Unadvise, static and libffi callbacks, POD/InOut arguments, multiple interfaces, and canonical IUnknown identity.

The live Classic COM suite currently contains 17 runners and is available with:

$env:DYNWINRT_WIN32_WINMD = "C:\path\to\Windows.Win32.winmd"
.\tests\e2e\e2e_test.ps1 -Lang com

Native contracts supported by the safe generator

An API not named above may still be safe when all of its methods use these modeled contracts.

Native contractCurrent support
Scalars and enumsSigned and unsigned integers, floating point, BOOL, HRESULT, pointer-sized values, enums, and flags.
GUIDs and interfacesGUID values, REFIID/REFGUID, typed interface input/output, QueryInterface, dynamic-IID void**, and owned +1 output.
Native POD structsValidated x86, x64, and ARM64 layouts with primitive, enum, GUID, pointer-sized, nested POD, and fixed primitive-array fields.
Native unionsTagged, validated pointer-input unions with safe POD fields. By-value, output, nested-owning, and undiscriminated unions are not supported.
StringsBSTR, HSTRING, supported PWSTR/PSTR inputs and outputs, embedded NUL BSTR values, and matching allocator cleanup.
Counted buffersTyped input buffers, caller-owned output buffers, capacity/actual-length patterns, exact bounded sizing, and known CoTaskMem outputs.
Automation valuesDefined subsets of VARIANT, SAFEARRAY, PROPVARIANT, DISPPARAMS, and EXCEPINFO.
Return conventionsOrdinary and semantic HRESULT, direct scalar, direct void, and exact registered direct-pointer contracts such as IMalloc.
COM object semanticsCoclass activation, inherited interfaces, projectAs QI views of managed values or wrappers, automatic release, and idempotent explicit release.

The safe /com entrypoint exports projectAs(value, InterfaceClass). It borrows a managed native value or generated wrapper and returns an independent QueryInterface owner of a registered generated safe COM interface. Raw pointers and unsafe target classes are rejected.

IMMDevice is now safe-complete: activate(InterfaceClass) infers the returned wrapper, fixes CLSCTX_INPROC_SERVER = 1, and passes native NULL activation parameters. The supported targets are IAudioClient, IAudioEndpointVolume, IAudioMeterInformation, IAudioSessionManager, and IAudioSessionManager2. Other/custom targets, async activation, and loopback or other parameterized activation remain outside this subset. getId() returns a string with exact CoTaskMem cleanup. This uses generated semantic plans and shared runtime primitives, not per-interface native adapters; the WinRT root is unchanged. See the audio endpoint example.

JavaScript interface implementation

dynwinrt can dynamically implement an interface in JavaScript when:

  • the interface is rooted in IUnknown;
  • its complete inherited vtable is contiguous and validated;
  • every callback argument, output, and return value has a completed inbound ABI plan;
  • output ownership can be prepared under RAII and committed atomically; and
  • callbacks execute synchronously on the thread that created the implementation.

Generated implementations support multiple interface views, canonical IUnknown identity, shared reference counting, common-signature static thunks, dynamic libffi closures, common native values, and failure containment. They do not provide general cross-apartment callback dispatch, IInspectable implementation, aggregation, or custom marshaling.

APIs not supported by the safe layer today

API or familyCurrent blockerRaw direction
Non-HGLOBAL/device-specific clipboard and drag-and-dropDVTARGETDEVICE and the remaining STGMEDIUM alternatives have distinct layout and release rules.Opaque aligned storage and explicit type-specific cleanup until each semantic alternative exists.
DXGI/D3D GetPrivateDataThe same payload may be bytes or an AddRef'd interface pointer.Caller-selected byte storage or pointer slot with explicit adoption.
Generic typed interface InOutReplacing an interface pointer requires explicit old/new reference transfer.UnsafeInterfaceReplacement with one independent +1 owner per slot.
Advanced AutomationBYREF VARIANTs, additional alternatives, replacement arrays, and nested ownership are incomplete.Raw storage can expose ABI reach; safe support still requires dedicated value and cleanup models.
Custom allocators and resource handlesThe runtime lacks the exact cleanup operation.Raw pointer plus explicit cleanup primitive where one exists.
Cross-apartment callbacksJavaScript is tied to its V8 owner thread while COM callbacks can be synchronous on foreign threads.Not solved by raw ABI; requires marshaling and dispatch architecture.
COM aggregation, custom marshaling, and registered serversThese change object identity, activation, and process semantics rather than only method ABI.Separate architecture work.
Flat Win32 DLL exportsThey are not COM vtable methods.Use the separate contract-driven Win32 layer for supported exports.

How users check a specific API

Run a dry run against the exact metadata version used by the application:

npx dynwinrt-codegen generate `
  --winmd C:\path\to\Windows.Win32.winmd `
  --class-name Windows.Win32.System.Com.IStream `
  --output .\generated `
  --dry-run

Interpret the result as:

Success = the complete interface is safe generated for this metadata version.
Failure = inspect the diagnostic, then decide whether the missing fact belongs
          in semantic unsafe, raw unsafe, or unsupported architecture work.

Unsafe layers

@microsoft/dynwinrt/com/unsafe remains the preferred manual layer when the caller knows the contract and dynwinrt already has a matching semantic type:

  • COM-owned interface output;
  • BSTR output;
  • CoTaskMem output;
  • borrowed handle or pointer;
  • scalar/POD InOut; or
  • authoritative counted buffers.

@microsoft/dynwinrt/com/unsafe/raw is the lower layer for aligned native memory, pointer slots, opaque records, and caller-managed replacement. It does not infer ownership or call cleanup automatically. Phase 1A is complete: nonzero zero-initialized aligned allocations, checked native-endian primitive and pointer-width access, owner-retaining in-allocation pointers, unowned external pointers, borrowed conversion into the existing COM invocation path, and reentrant-release-safe invocation leases.

The first Phase 1B block adds explicitly unsafe bounded external views plus architecture-specific raw struct and closed C-POD union descriptors. Validated recursive structs support scalar, GUID, pointer, nested struct, and fixed-array fields; existing signatures cover by-value input, pointer input, output, InOut, and direct struct return. External views never free caller memory. The next block adds retained borrowed managed pointers, dedicated raw +1 COM owners, atomic managed adoption, explicit detach/transfer, caller-managed interface InOut reconciliation, and fixed standard cleanup for COM task/local/ global/BSTR/SAFEARRAY/VARIANT/PROPVARIANT/STGMEDIUM/handle/icon/GDI resources. RawCom invocation leases retain a temporary +1 across every dispatch path; detached pointers remain RAII-owned until adoption, and slot transfer writes before disarming ownership. Closed, fully described recursive unions support by-value input, Out, InOut, and direct return on x64 and i686. ARM64 classification compiles but remains runtime-gated pending an executable oracle. Win64 3/5/6/7-byte by-value aggregates are rejected at the top-level CIF boundary for the bundled libffi 3.5.2 irregular-size argument passing/copy defect; valid naturally laid out outer aggregates may contain an odd-sized union.

RawOutbound by-value structs additionally require recursive natural C field offsets, alignment, and final size. Unexplained gaps or inflated tail padding are rejected; intentional reserved bytes require explicit fixed u8 fields. Semantic explicit layouts and raw pointer-only storage are unchanged.

The independent test-only C oracle is compiled by MSVC and executes live on x64 and i686, covering register/stack positions, register and sret returns, HFA1/HFA2/HFA4, mixed non-HFA, nested struct/union forms, sentinels, guarded destination canaries, indirect U16 local-copy mutation, and input immutability. Core tests additionally guard direct-return storage on both sides and validate the guards immediately after dispatch; production storage is unchanged. CI runs the exact test with test-hooks on x64 and live i686. The same C/Rust oracle cross-compiles in CI for ARM64 with --no-run, but the core runtime gate remains until native execution is available. Production builds omit test-hooks and do not compile or link the C oracle. windows-rs BITS and WHV union types provide additional layout evidence. Phase 1 is therefore complete only for the documented x64/i686 in-process current-apartment outbound subset, not cross-platform complete.

The final Phase 1 matrix executes representative raw GetPrivateData, IsFormatSupported, GetData, and interface-InOut contracts with real fake vtables. It also covers pointer depth through T***, required/nullable pointers, every struct direction and return, caller/callee buffers, cleanup failure paths, the managed/raw bridge, and all standard cleanup wrappers. IsFormatSupported includes its real share-mode argument and documented shared/exclusive output rules. GetData uses real TYMED_HGLOBAL cleanup both with and without pUnkForRelease. Interface InOut has distinct consume-old/replace, preserve-old/replace, and unchanged-slot tests. This demonstrates raw reach only; the named interfaces remain unsafe and absent from complete safe generation. Phase 1 is complete for the documented x64/i686 in-process current-apartment outbound subset, with explicit aggregate and ARM64 gates.

Generated unsafe companions: Stage 1

The ordinary generate command now reuses the exact capability-census method classifier after complete safe projection fails. When at least one method is raw_metadata_complete on x64, i686, and ARM64, it emits a nonconstructible <Interface>Unsafe companion under generated/com/unsafe/ with natural method names, exact hidden IID/slot/signature wiring, and explicit DynComRawMemory | DynComRawPointer storage arguments. There is no new CLI flag.

Only metadata-complete methods are executable in Stage 1. raw_manual_contract and raw_runtime_blocked methods are omitted from the class but retained with target status, reasons, declaring IID, absolute slot, and signature fingerprint in deterministic support.json. Safe-complete interfaces retain their byte-identical safe output and receive no duplicate unsafe class. Safe barrels and the npm root, /com, and /com/unsafe surfaces never export generated unsafe symbols.

Pointer-width inputs and direct results remain exact bigint values: NativeIsize uses I32 on i686 and I64 on 64-bit targets; NativeUsize uses U32 on i686 and U64 on 64-bit targets. Empty/zero interface IIDs, unsupported roots, and non-addressable identities block every method before companion selection. MFASYNCRESULT therefore produces no callable class.

When an interface has no executable method, generation transactionally commits a schema-12 report containing every blocked/manual method and exact reasons, emits no class .js/.d.ts, and then exits nonzero. The metadata record is a sorted, deduplicated set of every loaded emission/reference/sibling winmd, with per-file hashes, a set hash, and an optional exact defining file; it contains no local paths. Concurrent incremental COM generation is serialized by a crash-safe OS file lock shared by WinRT-only, COM-only, mixed, report-only, and Python writers. The complete output root is staged and replaced as one transaction, covering cleanup, manifest/support, barrels, package files, and the com subtree. Pre-publication failure restores the previous root byte-for-byte. Successful publication is the commit point; later backup cleanup failure keeps the complete new root, warns, retains residue, and retries cleanup on the next locked run. Owner-marked stage/backup residue from process termination between publication renames is recovered under that same lock; ambiguous or unowned residue fails closed.

Unmanaged file symlinks, directory symlinks, and junctions inside an existing output are detected without following reparse targets. Their directory entries move from backup to stage immediately before publication and move back on pre-publication rollback. No-follow residue cleanup removes only the links, never an external target. Case aliases, managed/staged/manifest ownership conflicts, transaction-residue names, and unsupported reparse tags fail closed.

Safe and unsafe modules use the canonical lowercase/kebab namespace layout, for example com/windows/win32/ui/shell/ITaskbarList3.js and com/unsafe/windows/win32/ai/machine-learning/win-ml/IWinMLEvaluationContextUnsafe.js. The short class name remains IWinMLEvaluationContextUnsafe. A short barrel export is emitted only when globally unique; ambiguous names are available only through deep modules, and incremental order does not affect the resulting barrel.

Generated and retained paths share an ASCII case-folded Windows identity. Traversal, rooted/drive paths, trailing dots/spaces, reserved device names, and case-only namespace/type collisions fail closed. Existing cross-root shared ownership additionally requires the staged file to exist and exactly match the planned bytes before overwrite.

CI also generates real official safe IWbemServices, IDataObject, and IAudioClient wrappers plus an IWinMLEvaluationContextUnsafe companion. The WMI test object uses the official IWbemServices_Vtbl through slot 25 and ABI-correct IWbemClassObject and IWbemCallResult tear-offs with one canonical IUnknown and shared reference counting. The test hooks also validate conditional output selection, data/audio storage cleanup, raw pointer-slot mutation, CJS, ESM, and declarations without requiring live WMI or audio hardware.

Generated companions are outbound only. They do not infer output ownership, provide callbacks or implement(), solve acquisition or apartment transfer, or make raw storage safe.

Stage 2 is now implemented for portable raw_manual_contract methods. Shared generated runtime.js/.d.ts provides closed pointee, pointer-output, handle, interface-replacement, counted-buffer, owned-pointer, and raw-fallback strategies. Generated methods validate strategy types before dispatch, clean dirty HRESULT failure outputs according to the selected strategy, and report exact per-parameter requirements in support schema 12.

Strategy capabilities are unforgeable frozen objects backed by private WeakMaps. Private generated helpers perform prepare, writable-span overlap validation, transactional finish/rollback, dirty-output cleanup, and extracted owner release. Raw-responsibility failure pointers remain one-shot retrievable and are attached to the error. Owned native cleanup results have a FinalizationRegistry fallback; finalizer cleanup failure leaks conservatively because finalizers cannot throw.

Preparation records are frozen and opaque; real records live in a second private WeakMap, internal helper exports are immutable, and production output contains no test hooks. Native WinGuid validation happens before COM output or replacement slot mutation. The core marks actual native dispatch only after fallible target/argument validation, allowing consumes-old activation to roll back and remain retryable on pre-dispatch failure. Replacement selection requires the exact parameter-local missing_interface_replacement_contract reason and InOut IFoo** depth; exact method evidence can suppress it only by recording old/new ownership. Replacement owners cannot alias across prepared slots in any mode. Writable UnsafePointee requirements carry direction, nullability, and per-target layout when known; they require bounded memory and join output, replacement, counted-buffer, and ordinary writable count slots in one overlap graph. Counted-buffer selection similarly requires that parameter's own missing_count_relation.

IWbemServices::OpenNamespace is now covered by exact direction and ownership evidence. Microsoft Learn and the Windows SDK WbemCli.h/WbemIdl.idl declaration identify both pointer-to-interface parameters as [out], not InOut. A stored full-method fingerprint covers all five parameters, return and HRESULT semantics, and absence of competing exact contracts. Generated options hide pCtx, require exactly one empty output slot, enforce exact lFlags 0 versus 16 (WBEM_FLAG_RETURN_IMMEDIATELY), adopt the requested non-null +1, and release dirty failure output. Generic interface InOut parameters remain manual replacement contracts.

1,427 of 1,431 x64 manual-contract interfaces now have at least one portable executable generated high-level method. 1,426 have an executable manual method, one retains only metadata-complete methods, and four have no portable executable method because every candidate is blocked on another generated target. Across the portable generated surface there are 6,046 executable manual methods, 0 remaining portable manual-classified methods omitted, and 1,161 runtime-blocked methods still omitted.

Safe contract evidence census

Stage 1 of the Classic COM contract evidence registry classifies all 5,721 safe-complete interfaces exactly once:

Evidence classInterfaces
standard_derived5,355
exact_registry_dependent366

The registry declares 532 selector-specific entries; all 532 match pinned metadata, 431 distinct entries are consumed by complete safe plans, which contain 694 entry/interface plus 425 family/interface dependencies. They also consume 6,012 metadata-attribute and 26,247 universal COM-rule dependency sets. Entry/interface dependencies by kind are SAFEARRAY 263, enumerator-next 74, borrowed-handle 54, ownership 183, parameter-direction 45, bounded-two-call 16, counted-buffer 16, conditional-output 10, flag-selected-buffer 3, null-input 4, semantic-HRESULT 3, compound-dispatch 1, borrowed-storage 15, and contextual-effect 7. Complete per-entry status, per-family rollups, and per-interface entry IDs are retained in the summary and interface CSV. These are dependency counts, not net contribution; no ablation claim is made.

The 24 PR4 promotions comprise 23 standard-derived interfaces and one exact-registry-dependent interface, IGenericDescriptor2. Its inherited GetBody reuses an existing slot-6 ownership entry; no registry entries or distinct safe-consumed entries are added.

Borrowed buffers now have synchronous owned-copy transactions for WASAPI render/capture, STA WIC BGRA8 locks, and linear IMFMediaBuffer. Audio requires observed successful initialization and GetService provenance; external initialization alone grants no copy capability. Render/capture and linear MF remain copy-only facades and do not increase the safe-complete census. WIC preserves its existing native methods and adds a read-copy operation. Exclusive event-driven render, native-backed JS views, writable external WIC locks, and general signed-pitch/plane IMF2DBuffer/IMF2DBuffer2 access remain unsupported. See the bounded copy contract.

Generic scalar BSTR output/replacement and 24 STANDARD_NEXT enumerator entries remain typed COM standard rules. Twenty-five safe interfaces consume the generic enumerator rule because one contract is inherited. ISequentialStream Read/Write and IDispatch Invoke are distinct exact entries with full selectors, fingerprints, and citations. IAudioClient::IsFormatSupported adds an exact shared/exclusive conditional output contract, while GetMixFormat and IAudioClient3::GetCurrentSharedModeEnginePeriod add exact CoTaskMem-owned variable-format outputs. The two device-control Record methods have separate exact nullable-input contracts: null selects the device default format without allocating a placeholder WAVEFORMATEX. Other audio-format inputs remain required. IMMDevice::Activate adds an exact IID/slot-3/full-fingerprint activation contract, and IMMDevice::GetId adds a JSON-backed slot-5 CoTaskMem ownership entry. Both are consumed by the complete safe endpoint plan. The com.ownership.v1 family now has 169 registered entries, 118 safe-used entries, and 124 family/interface dependencies.

The storage-medium contracts also pin IOleCache::SetData (including inherited IOleCache2 calls) to caller-retained ownership and describe the distinct IDataObject::GetCanonicalFormatEtc success/result semantics. STGMEDIUM InOut additionally requires the exact caller-allocation-preserving IDataObject::GetDataHere contract. IWiaDataTransfer::idtGetData is excluded from safe support until its distinct file-transfer and filename ownership semantics are modeled.

The strict embedded registry lives in tools/dynwinrt-codegen/contracts/classic-com/. JSON is the sole source for seven selector-derived IWbemServices conditional-output contracts and 149 documented output-ownership contracts. Each entry includes its selector, pre-contract fingerprint, evidence, and validated metadata hash.

An interface available only through an unsafe layer is not described as safe supported. A wrong IID, slot, signature, pointer depth, layout, count relation, allocator, or ownership declaration can corrupt memory or crash the process.

Reproducible raw capability census

For Microsoft.Windows.SDK.Win32Metadata 71.0.14-preview (Windows.Win32.winmd SHA-256 B64EE4818A7ED9F9D135038D58C51BD08369184D4D5ED428F20E9DE55DF8121D), the safe census is 5,721 of 7,929 interfaces. The separate outbound raw census classifies the 2,208 safe-incomplete interfaces as:

TargetMetadata-completeManual contractRuntime-blocked
x643881,431389
i6863871,408413
ARM643881,431389

Including safe-complete interfaces, x64 and ARM64 have 6,109 metadata-complete, 1,431 manual, and 389 blocked interfaces. i686 has 6,108 metadata-complete, 1,408 manual, and 413 blocked interfaces.

These all-interface raw totals are unchanged by PR4: all 24 promotions come from the safe-incomplete raw-metadata-complete bucket. Manual/runtime-blocked classifications and the measured Stage 2 executable-method totals are unchanged.

Pointer-shaped types are analyzed recursively. A missing pointee layout for an external input pointer is manual-contract; the same missing layout for a writable/readable T* caller-storage contract is runtime-blocked. Thus ID2D1Factory matrix pointers are manual with external pointee storage, while ITypeComp BINDPTR* output storage is blocked until its nested anonymous layout is complete.

Cleanup availability is no longer represented by ambiguous booleans. Per target, 2,237 interfaces require no cleanup, 4,534 use a Phase 1 standard cleanup, none use a known external cleanup, and 1,158 have unknown cleanup. Every missing output ownership/allocator contract has cleanup_unknown. External pointer/callback requirements affect 1,089 x64/ARM64 interfaces and 1,090 i686 interfaces; 6,804 require external acquisition and all 7,929 retain the current-apartment rule.

For all 5,721 safe-complete interfaces, cleanup is derived from the validated projected result conversions rather than the raw analyzer. Pure values, borrowed handles, caller buffers, and plain arrays are none_required. Managed COM/dynamic-IID adoption, BSTR, HSTRING, CoTaskMem, VARIANT, SAFEARRAY, PROPVARIANT, EXCEPINFO, STATSTG, owning/enumerator arrays, and allocator wrappers are standard_supported. No safe-complete interface has cleanup_unknown or known_external.

The ECMA TypeDef table contains 37,310 definitions excluding <Module>. windows_metadata::Index::all() exposes 35,146 addressable definitions; the older 35,055 number belongs to older metadata and is not reused. The category table is only a 21-category semantic summary, not an exhaustive concrete type list. Direct signature and recursively expanded occurrence counts are stored separately. Specialized categories can arise after semantic projection: STATSTG appears as NativeStruct in raw metadata, while the exact IStream::Stat contract becomes semantic StatStg; therefore the raw inventory's StatStg occurrence count is zero.

The COM-reachable inventory contains 6,924 definitions present in the pinned file, 170 unresolved anonymous nested records, six external metadata references, and one system/synthetic identity. External references are Windows.Foundation.IPropertyValue, Windows.Graphics.Effects.IGraphicsEffectSource, Windows.UI.Composition.CompositionGraphicsDevice, CompositionTexture, Desktop.DesktopWindowTarget, and ICompositionSurface. Only identities reconciled against an actual pinned TypeDef row are called named_metadata_definition.

Unresolved anonymous unions remain category Unknown; the appendix displays their unique containing-path identity_key rather than an ambiguous empty namespace/name. NativeUnion = 1 represents the one recognized raw/projected union occurrence. VARIANT and PROPVARIANT use dedicated semantic categories, while outer STGMEDIUM-like records may appear as NativeStruct or contain an unresolved anonymous field.

Retained evidence:

The support index contains namespace, name, IID, complete-safe state, safe evidence class, and the first stable blocker/manual reason code. The complete interface capability matrix, COM-reachable identity inventory, all-TypeDef inventory, canonical type-shape report, and named-type appendix are generated on every CI run and uploaded as the classic-com-capability-report artifact. They remain reproducible locally but are not retained in Git. Arrays, detailed reasons, layout facts, and target states use deterministic JSON cells inside RFC 4180 CSV. Large JSON duplicates are emitted only with --large-json.

Regenerate with:

cargo run -p dynwinrt-codegen -- com-capability-census `
  --winmd <Windows.Win32.winmd> `
  --output-dir docs/status/generated

The census is outbound-only. It does not count callbacks, servers, aggregation, cross-apartment marshaling, acquisition, or cleanup convenience as ABI support. The legacy com-census --json output remains unchanged.

Roadmap

Now

  • Preserve safe generation and the 70% complete-interface target.
  • Maintain completed Phase 1A allocation/provenance/lease invariants.
  • Validate the first Phase 1B bounded-view and recursive-struct block without adding a safe-codegen fallback.
  • Keep safe and raw capability census artifacts reproducible and separately versioned.

Next

  • Add higher-level owning STGMEDIUM, audio-format, handle, and interface-replacement values over the completed raw primitives.
  • Expand authoritative array and allocator contracts.

Later

  • Expand Automation and native-layout semantic support.
  • Design apartment marshaling and agility independently from raw ABI.
  • Keep DLL exports in the separate Win32 contract layer; COM server support remains independent architecture work.

Copyable user-facing statement

dynwinrt supports the Classic COM interface portion of Windows.Win32 metadata. With Win32Metadata 71.0.14-preview, 5,721 of 7,929 addressable COM interfaces pass complete safe generation. Safe symbols never fall back to an unsafe implementation; ordinary generation may instead emit an explicitly named *Unsafe outbound companion containing only metadata-complete methods. Experts may use the semantic unsafe layer for known ownership plans or the isolated raw unsafe layer for caller-managed native memory and pointers. Raw declarations guarantee only ABI execution and can corrupt memory or terminate the process when used incorrectly.