fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

Windows Forms in FSI works in Visual Studio but not calling dotnet fsi

Open somelinguist opened this issue 3 years ago • 2 comments

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:

  1. Run a script such as the following using Execute in Interactive in 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()

  1. Run the same script via dotnet fsi forms.fsx on the command line or using F#: Run script in 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

somelinguist avatar Jul 08 '22 15:07 somelinguist

This is expected, I believe, we need to support it though.

vzarytovskii avatar Jul 08 '22 16:07 vzarytovskii

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.

somelinguist avatar Jul 08 '22 17:07 somelinguist