Windows Forms in FSI works in Visual Studio but not calling dotnet fsi
Calling Windows Forms code in F# Interactive works when running FSI in Visual Studio, but not when calling dotnet fsi via the command line or Ionide/VS Code. (See the error below under Actual Behavior)
Repro steps
Provide the steps required to reproduce the problem:
- Run a script such as the following using
Execute in Interactivein Visual Studio :
#I @"C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.6"
#r "System.Windows.Forms"
#r "nuget: System.Drawing.Common, 6.0.0.0"
open System
open System.Drawing
open System.Windows.Forms
// Create form, button and add button to form
let form = new Form(Text = "Hello world!")
let btn = new Button(Text = "Click here")
form.Controls.Add(btn)
// Register event handler for button click event
btn.Click.Add(fun _ ->
// Generate random color and set it as background
let rnd = new Random()
let r, g, b = rnd.Next(256), rnd.Next(256), rnd.Next(256)
form.BackColor <- Color.FromArgb(r, g, b) )
// Show the form (in F# Interactive)
form.Show()
- Run the same script via
dotnet fsi forms.fsxon the command line or usingF#: Run scriptin Ionide/VS Code.
Expected behavior
Running the script in FSI would have the same outcome whether calling from Visual Studio or other environments.
Actual behavior
When running in Visual Studio, the form is shown correctly.
When running fsi elsewhere, the following error is given:
System.IO.FileLoadException: Could not load file or assembly 'System.Drawing.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Could not find or load a specific file. (0x80131621)
File name: 'System.Drawing.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
---> System.IO.FileLoadException: Could not load file or assembly 'System.Drawing.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at System.Reflection.Assembly.LoadFromResolveHandler(Object sender, ResolveEventArgs args)
at System.Runtime.Loader.AssemblyLoadContext.InvokeResolveEvent(ResolveEventHandler eventHandler, RuntimeAssembly assembly, String name)
at System.Runtime.Loader.AssemblyLoadContext.OnAssemblyResolve(RuntimeAssembly assembly, String assemblyFullName)
at <StartupCode$FSI_0002>.$FSI_0002.main@()
If I switch to using #I @"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" instead of #I @"C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.6", the error about System.Drawing.Common goes away, but I get the following error instead when running dotnet fsi or Ionide, but not in Visual Studio:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at System.Windows.Forms.NativeWindow.AdjustWndProcFlagsFromConfig(Int32 wndProcFlags)
at System.Windows.Forms.NativeWindow.get_WndProcFlags()
at System.Windows.Forms.NativeWindow.get_WndProcShouldBeDebuggable()
at System.Windows.Forms.NativeWindow.AssignHandle(IntPtr handle, Boolean assignUniqueID)
at System.Windows.Forms.NativeWindow.AssignHandle(IntPtr handle)
at System.Windows.Forms.NativeWindow.WindowClass.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Known workarounds
Provide a description of any known workarounds.
Related information
Provide any related information (optional):
-
Operating system: Windows 10 Pro 21H2 19044.1806
-
.NET Runtime kind (.NET Core, .NET Framework, Mono): .NETCore Microsoft.WindowsDesktop.App\6.0.6
-
Editing Tools (e.g. Visual Studio Version, Visual Studio)
- Visual Studio 2022 17.2.5
- VS Code 1.69
- Ionide 6.0.6
This is expected, I believe, we need to support it though.
Thanks for the info.
It sort of seems like it was implied to be supported with the --gui[+|-] option.
--gui[+|-] Enables or disables the Windows Forms event loop. The default is enabled.
I saw some reports of issues with Windows Forms with FSI in newer versions of dotnet, but I wanted to check since it still worked in when running FSI in Visual Studio and the option above was still listed in the current FSI documentation.