WinMIDL
Copilot instructions0 starsChanged 4 months agoMITView on GitHub
E2E proxy/stub tests require an MSVC x64 dev prompt: The VS extension must be built with MSBuild from VS, not dotnet build. WinMIDL is a MIDL3 compiler with an LSP server, two editor extensions, and custom proxy/stub codegen. Pipeline: IDL source → Lexer → Parser (lossless green tree) → Binder → InterfaceSynthesizer → VersionPropagator → AttributeValidator → CodeGen (WinMD / Header / IID / Proxy) Key projects (in src/): - Midl.Syntax — shared token/node types - Midl.Lexer — hand-written lexer,…
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,336 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repositoryOne other file it gives its agents.
- releaseSkill
The file
We split this copilot-instructions.md into the rules it gives an agent
11 rules. About 0 are common, 4 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 52
Every change must be evaluated across 12 aspects: lexer/parser, analysis, diagnostics, autocomplete, signature help, hover/goto-def, WinMD …
- Very specific: line 66
All codes defined in src/Midl.Analysis/Diagnostics/DiagnosticDescriptors.cs
- Very specific: line 83
All attributes must be emitted to WinMD.
- Distinctive: line 95
Use C# partial classes to minimize merge conflicts
- Distinctive: line 96
Never use regex to edit source code — use exact string matching
- Very specific: line 97
Never hardcode IIDs — use generated _i.c files
- Distinctive: line 98
Every agent must run tests before committing
- Very specific: line 110
Never push after running only a subset.
- Very specific: line 114
All changes must follow TDD: write tests first, verify they fail, implement, verify they pass.
- Very specific: line 134
Method params/retvals: use marshal_interface/unmarshal_interface (COM marshaling, preserves object identity)
- Very specific: line 135
Struct fields: use marshal_nullable<T>/unmarshal_nullable<T> (inline [uint8 hasValue][T value], uses winrt::box_value/winrt::unbox_value)
≈ “Common” is an estimate: at least 1 in 5 of the 3,779 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Copilot Instructions — WinMIDL
Build & Test
dotnet build # Build all projects
dotnet test # Run all ~1,900 tests (xUnit)
dotnet test tests/Midl.Analysis.Tests # Single project
dotnet test --filter "FullyQualifiedName~Parse" # Single test by name pattern
scripts/publish-optimized.ps1 # NativeAOT binary + smoke test
scripts/package-vsix.ps1 # VS Code VSIX (auto-infers version from git tag)
scripts/package-vs-vsix.ps1 # VS VSIXE2E proxy/stub tests require an MSVC x64 dev prompt:
tests/e2e-custom-marshal/comprehensive/build-and-test.ps1 # In-proc (89 tests)
tests/e2e-custom-marshal/outofproc/build-and-test.ps1 # Cross-process (108 tests)The VS extension must be built with MSBuild from VS, not dotnet build.
Architecture
WinMIDL is a MIDL3 compiler with an LSP server, two editor extensions, and custom proxy/stub codegen.
Pipeline: IDL source → Lexer → Parser (lossless green tree) → Binder → InterfaceSynthesizer → VersionPropagator → AttributeValidator → CodeGen (WinMD / Header / IID / Proxy)
Key projects (in src/):
Midl.Syntax— shared token/node typesMidl.Lexer— hand-written lexer, built-in C preprocessorMidl.Parser— error-recovering recursive-descent parser (Roslyn green tree pattern)Midl.Analysis— binder, symbol table, type resolver, validators, WinMD readerMidl.CodeGen— WinMD emitter, C header, IID, proxy/stub generators, decompilerMidl.Lsp— JSON-RPC LSP server (no external NuGet deps)Midl.Cli— CLI entry point, NativeAOT-compatible
Extensions (in editors/):
editors/vscode/— VS Code extension (TextMate grammar, LSP client, TypeScript)editors/vs/Midl.VsExtension/— Visual Studio extension (traditional VSSDK, ILanguageClient)
Proxy/stub (in src/Midl.CodeGen/Proxy/):
- Generates direct C++ proxy/stub code (no NDR) for COM cross-apartment/cross-process marshaling
- Payload format: simple packed binary with null-terminated HSTRING
- Interface pointer marshaling: typed IID first, IID_IUnknown fallback for system objects
- Runtime helpers in
include/winmidl/proxy_helpers.h
Conventions
Feature/bug checklist (see CONTRIBUTING.md)
Every change must be evaluated across 12 aspects: lexer/parser, analysis, diagnostics, autocomplete, signature help, hover/goto-def, WinMD emission (on ALL targets: types, methods, properties, events, params, fields), header/IID, proxy/stub codegen, decompiler round-trip, VS Code ↔ VS parity, and testing.
Compilation modes
CompilationMode.Strict— MIDL3 only, classic constructs produce errorsCompilationMode.Compat— allows classic MIDL2 constructs (coclass, typedef, etc.)WITH_COMPATdefine — enables compat-mode code pathsFEATURE_STAGINGdefine — enables feature-staging support (feature_name declarations, [feature] gating)
Diagnostics
MIDL1xxx— semantic errors and warningsMIDL2xxx— strict-mode errors (classic constructs, C-only types)MIDL3xxx— code quality hints (naming, empty types, etc.)- All codes defined in
src/Midl.Analysis/Diagnostics/DiagnosticDescriptors.cs
Interface synthesis
Runtimeclasses get synthesized exclusive interfaces:
- Instance members →
I<Class>(default interface) - Constructors →
I<Class>Factory - Static members →
I<Class>Statics - Protected →
I<Class>Protected - Overridable →
I<Class>Overrides
Parameterized types
IReference<T>, IVector<T>, IMap<K,V>, EventHandler<T> etc. emit as IInspectable* in generated headers and proxy code. PIIDs computed via UUID v5.
WinMD attribute emission
All attributes must be emitted to WinMD. Well-known attributes use dedicated Add*Attribute methods in CustomAttributeEmitter.cs. Everything else uses AddGenericCustomAttribute via EmitRemainingAttributes. Default values (threading(both), marshaling_behavior(agile)) are suppressed in decompiled output.
Proxy/stub marshaling
CoMarshalInterface/CoUnmarshalInterfaceuse the typed IID (needed for delegate callbacks)- Falls back to
IID_IUnknownfor system WinRT objects (PropertyValue, etc.) MSHCTX_LOCALfor both inproc and cross-process- Object type →
IID_IUnknown(notIID_IInspectable— no proxy/stub for IInspectable)
Agent workflow
- Background agents get their own dedicated git worktree + branch
- Use C# partial classes to minimize merge conflicts
- Never use regex to edit source code — use exact string matching
- Never hardcode IIDs — use generated
_i.cfiles - Every agent must run tests before committing
- Audit sub-agent changes: always diff sub-agent commits in
src/andtests/against the design intent before accepting. Sub-agents may change the design (e.g., modify test assertions) to make their code pass rather than fixing actual bugs. Verify the diff explicitly — do not trust "all tests pass" from a sub-agent.
Pre-push verification
ALL of the following must pass locally before pushing:
dotnet test --filter "Category!=E2E" # Unit tests (~2500)
pwsh tests/e2e-custom-marshal/comprehensive/build-and-test.ps1 # In-proc E2E (133 tests)
pwsh tests/e2e-custom-marshal/outofproc/build-and-test.ps1 # Cross-process E2E (123 tests)
dotnet test tests/Midl.E2E.Tests # C# E2E runner (runs build scripts from C#)Never push after running only a subset. The C# E2E runner (Midl.E2E.Tests) exercises different code paths than the pwsh scripts (different INCLUDE setup, different process management).
TDD
All changes must follow TDD: write tests first, verify they fail, implement, verify they pass. For proxy/stub changes, this means unit tests in Midl.CodeGen.Tests first, then E2E tests that exercise actual C++ compilation and cross-apartment round-trip.
VS extension limitations
- VS doesn't render markdown in LSP hover — hover handler strips markdown for VS
- VS doesn't support LSP
onTypeFormatting— use nativeISmartIndentinstead - VS built-in C++ project system hijacks
.idlfiles — use.idlrtas primary extension - VS extension uses traditional VSSDK (AsyncPackage + ILanguageClient), not VisualStudio.Extensibility SDK
proxy_helpers.h compilation paths
include/winmidl/proxy_helpers.h is compiled in multiple contexts. When adding new #include directives or dependencies, ALL of these must be updated:
tests/e2e-custom-marshal/comprehensive/build-and-test.ps1—$env:INCLUDEtests/e2e-custom-marshal/outofproc/build-and-test.ps1—$includesarraytests/Midl.E2E.Tests/E2ETestHelper.cs—MsvcToolchainrecord +Environment["INCLUDE"]tests/e2e-custom-marshal/comprehensive/generated/winmidl/proxy_helpers.h— tracked copy
IReference<T> encoding
IReference<T> (nullable value types) has different encoding depending on context:
- Method params/retvals: use
marshal_interface/unmarshal_interface(COM marshaling, preserves object identity) - Struct fields: use
marshal_nullable<T>/unmarshal_nullable<T>(inline[uint8 hasValue][T value], useswinrt::box_value/winrt::unbox_value)
This distinction exists because method-level IReference<T> is an IInspectable* that may carry custom behavior, while struct-field IReference<T> is conceptually just "T or null" with no identity to preserve.
Testing patterns
CompilationHelper.Compile(source)— compile IDL without SDK refsCompilationHelper.Compile(source, new[] { sdk.WindowsWinMdPath })— with SDKCompileAndEmit(source)— compile + emit WinMD bytesOpenMetadataReader(bytes)— read WinMD metadata- E2E tests use
Check(condition, "TestName")pattern with pass/fail counting
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

