Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UseWindowsForms causes token Windows to be clobbered in global scope. #39299

Open
nitz opened this issue Mar 7, 2024 · 5 comments
Open

UseWindowsForms causes token Windows to be clobbered in global scope. #39299

nitz opened this issue Mar 7, 2024 · 5 comments
Assignees
Labels
Area-NetSDK needs team triage Requires a full team discussion

Comments

@nitz
Copy link

nitz commented Mar 7, 2024

Describe the bug

In a project that is making use of <UseWindowsForms>true</UseWindowsForms>, an attempt to access an unqualified symbol named Windows will cause csc to produce a CS0234. If the symbol is named anything other than windows, this does not occur. Unlike other library provided namespaces (e.g.: System,) there is no Windows namespace in the global scope. It appears to believe that Windows is a namespace, regardless of the current scope's usings. I have confirmed that this behavior is unaffected by the state of ImplicitUsings. Edited to add: of note, <UseWPF>true</UseWPF> does not produce this behavior.

To Reproduce

Repro 1

Create a project with the following files. The .cs files can be combined into a single file with appropriate namespace bracing. The result is the same either way.

repro.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0-windows7.0</TargetFramework>
    <LangVersion>10.0</LangVersion>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>
</Project>

Program.cs:

using Foo;
Windows.Bar();
NotWindows.Baz();

Foo.cs:

namespace Foo;

public static class Windows
{
	public static void Bar() => System.Console.WriteLine("Bar!");
}

internal static class NotWindows
{
	public static void Baz() => System.Console.WriteLine("Baz!");
}

Repro 2

Attempt to build project, and observe emitted CS0234:

W:\issue>dotnet build repro.csproj
MSBuild version 17.8.5+b5265ef37 for .NET
  Determining projects to restore...
  Restored W:\issue\repro.csproj (in 226 ms).
W:\issue\Program.cs(2,1): error CS0234: The type or namespace name 'Bar' does not exist in
 the namespace 'Windows' (are you missing an assembly reference?) [W:\issue\repro.csproj]

Build FAILED.

W:\issue\Program.cs(2,1): error CS0234: The type or namespace name 'Bar' does not exist in
 the namespace 'Windows' (are you missing an assembly reference?) [W:\issue\repro.csproj]
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:04.51

Repro 3

Modify repro.csproj as follows:

-    <UseWindowsForms>true</UseWindowsForms>
+    <UseWindowsForms>false</UseWindowsForms>

Repro 4

Build again, observing successful compilation:

W:\issue>dotnet build repro.csproj
MSBuild version 17.8.5+b5265ef37 for .NET
  Determining projects to restore...
  Restored W:\issue\repro.csproj (in 225 ms).
  Test -> W:\issue\bin\Debug\net8.0-windows7.0\repro.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.06

Exceptions (if any)

N/A.

Further technical details

  • Include the output of dotnet --info
  • The IDE (VS / VS Code/ VS4Mac) you're running on, and its version
    dotnet --info:
W:\issue>dotnet --info
.NET SDK:
 Version:           8.0.102
 Commit:            64f1bc458e
 Workload version:  8.0.100-manifests.8a11730e

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.102\

.NET workloads installed:
 Workload version: 8.0.100-manifests.8a11730e
There are no installed workloads to display.

Host:
  Version:      8.0.2
  Architecture: x64
  Commit:       1381d5ebd2

.NET SDKs installed:
  3.1.426 [C:\Program Files\dotnet\sdk]
  5.0.104 [C:\Program Files\dotnet\sdk]
  5.0.202 [C:\Program Files\dotnet\sdk]
  5.0.214 [C:\Program Files\dotnet\sdk]
  5.0.303 [C:\Program Files\dotnet\sdk]
  5.0.403 [C:\Program Files\dotnet\sdk]
  5.0.408 [C:\Program Files\dotnet\sdk]
  6.0.101 [C:\Program Files\dotnet\sdk]
  6.0.127 [C:\Program Files\dotnet\sdk]
  6.0.202 [C:\Program Files\dotnet\sdk]
  6.0.203 [C:\Program Files\dotnet\sdk]
  6.0.321 [C:\Program Files\dotnet\sdk]
  6.0.419 [C:\Program Files\dotnet\sdk]
  7.0.102 [C:\Program Files\dotnet\sdk]
  7.0.116 [C:\Program Files\dotnet\sdk]
  8.0.102 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.16 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.27 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.27 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.21 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.13 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.27 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.16 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  arm64 [C:\Program Files\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\arm64\InstallLocation]
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

IDE: None, but I did test that this reproduces with VS v17.8.7.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-NetSDK untriaged Request triage from a team member labels Mar 7, 2024
@KalleOlaviNiemitalo
Copy link
Contributor

This reproduces the same error without defining UseWindowsForms:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0-windows7.0</TargetFramework>
    <LangVersion>10.0</LangVersion>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.2\ref\net8.0\System.Windows.Forms.Primitives.dll" />
  </ItemGroup>
</Project>

So the error is caused by System.Windows.Forms.Primitives.dll, which indeed defines many namespaces whose names start with Windows.Win32. However, these namespaces do not contain any public types. It isn't clear to me whether they should affect C# name lookup.

If you don't use top-level statements, and instead define a Main method within namespace Foo,

namespace Foo
{
    class Program
    {
        static void Main()
        {
            Windows.Bar();
            NotWindows.Baz();
        }
    }
}

then it will build just fine.

@KalleOlaviNiemitalo
Copy link
Contributor

The Microsoft.Windows.CsWin32 package could perhaps add a feature to allow renaming namespaces; then the System.Windows.Forms.Primitives project could rename the Windows namespace to System.Windows.Forms.WindowsInterop or something. But I don't think such a change could be backported to .NET 8.0.

Alternatively, it might be possible to eradicate the Windows.Win32.* namespaces from the reference assemblies and keep them only in the runtime assemblies.

@nitz
Copy link
Author

nitz commented Mar 7, 2024

Good catch with System.Windows.Forms.Primitives.dll. It seems issue isn't present in .NET Framework (<TargetFramework>net481</TargetFramework>), nor was it present in .NET 7.0 (<TargetFramework>net7.0-windows7.0</TargetFramework>), but only started appearing in .NET 8.0 (<TargetFramework>net8.0-windows7.0</TargetFramework>) — Taking a peek at the .net6.0 and net7.0 ref libs, they don't seem to include anything in the Windows namespace.

I don't think the use of top level statements has anything to do with it. I believe your example there dodges it because putting Program.Main in the same namespace as Windows and NotWindows seems to allow it to correctly resolve the static classes.

This Program.cs reproduces the issue without top level statements:

using Foo;

namespace App
{
	class Program
	{
		static void Main()
		{
			Windows.Bar(); // CS0234 if 
			NotWindows.Baz();
		}
	}
}

All that said, I now wonder after you've pointed out that the namespace is coming from System.Windows.Forms.Primitives.dll, if this is less of a https://github.com/dotnet/sdk issue, and more of a https://github.com/dotnet/runtime or https://github.com/dotnet/roslyn issue. I'm not familiar enough with how https://github.com/dotnet/csharplang specifies how resolution should work to know if this is something that should be covered or if it's just an edge case.

Edit to add:

Alternatively, it might be possible to eradicate the Windows.Win32.* namespaces from the reference assemblies and keep them only in the runtime assemblies.

This feels like the ideal path to me. I'm not sure why a reference assembly would be filled with namespaces and classes that you can't even reference! 😂

@KalleOlaviNiemitalo
Copy link
Contributor

I don't think the use of top level statements has anything to do with it.

This was the first thing I tried:

namespace Foo;

Windows.Bar();
NotWindows.Baz();

but it causes error CS0116: A namespace cannot directly contain members such as fields, methods or statements. So, I don't think you can put the code into namespace Foo while using top-level statements.

@KalleOlaviNiemitalo
Copy link
Contributor

I'm not sure why a reference assembly would be filled with namespaces and classes that you can't even reference!

If Windows Forms has a public struct type that has a private field whose type is defined in System.Windows.Forms.Primitives, and you make some postprocessor delete this field from the reference assembly, then this change can cause the struct type to satisfy the unmanaged constraint at build time but not at run time. Which could then cause some weird error. So, I suppose it would be safer if the postprocessor renamed these namespaces to something unspeakable like <Windows>.Win32 in the reference assemblies.

@MiYanni MiYanni added needs team triage Requires a full team discussion and removed untriaged Request triage from a team member type-investigation labels Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-NetSDK needs team triage Requires a full team discussion
Projects
None yet
Development

No branches or pull requests

3 participants