How do resolve the type-conflict (CS0436) when using CsWin32 in dependent projects?

Gavin Williams 801 Reputation points
2026-08-21T05:25:26.0533333+00:00

I have a project that uses CsWin32, it uses a shared project reference that also uses CsWin32. I'm getting green squiggles under PInvoke...
Screenshot 2026-08-21 145935

The type PInvoke conflicts with the imported type. How do I resolve this issue?

Suggestions:

  • Use a fully qualified name - use Windows.Win32.PInvoke, doesn't fix it, because it's the same type, it's not just something that happens to have the same name.
Windows development | Windows API - Win32
0 comments No comments

Answer accepted by question author
Taki Ly (WICLOUD CORPORATION) 4,440 Reputation points Microsoft External Staff Moderator
2026-08-21T09:47:35.9233333+00:00

Hello @Gavin Williams ,

Thank you for the clear description and the screenshot. This is expected behavior rather than a name collision: CsWin32 runs independently in each project, so both your shared project and the dependent project each generate their own Windows.Win32.PInvoke class. Once the shared project exposes that class (for example as public, or via InternalsVisibleTo), the dependent project's compilation sees two definitions of the same type, its own generated one plus the imported one, which is exactly what CS0436 reports. As you noted, a fully qualified name cannot help, because it really is the same type generated twice.

The recommended fix is CsWin32's layered composition feature, where one assembly owns the canonical PInvoke class and the other extends it instead of redeclaring it, so callers still reach everything through a single PInvoke.X(). In the shared (lower) project, mark it as the owner in NativeMethods.json:

{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "className": "PInvoke",
  "public": true
}

And in the dependent project, make it an extender with a unique className:

{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "className": "PInvokeApp",
  "extensionReceiver": "PInvoke"
}

This relies on C# 14 extension members, so every consuming project needs LangVersion 14 or later (automatic when targeting .NET 10 or later, otherwise set <LangVersion>14</LangVersion>), and CsWin32 will detect and skip duplicate APIs across the layers for you.

If C# 14 is not an option in your setup, you can instead generate each API only once by declaring the P/Invokes in the shared project with "public": true and not listing those same APIs again in the dependent project or give each project a distinct className (such as CorePInvoke and AppPInvoke) so the classes no longer collide, at the cost of losing the single unified PInvoke surface. One thing to watch is that if you have handwritten partial definitions for foundation types like HRESULT or PWSTR, promoting the shared project to public can surface a similar CS0436 on those, which the guide resolves by moving the extra members into an extension(T) block.

The full worked example is here.

To tailor the guidance, it would help to know your CsWin32 package version, the target framework and effective LangVersion, and which project sits at the bottom of your dependency graph. If you found my response helpful or informative, I would greatly appreciate it if you could follow this guide for your confirmation.

Thank you.

Was this answer helpful?

1 person found this answer helpful.
0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.