Skip to content

[WinForms] Deprecate and remove ability to access Windows Forms objects from native code #22423

@RussKie

Description

@RussKie

Deprecate and remove ability to access Windows Forms objects from native code

Accessing Windows Forms objects from native code was deprecated as .NET runtime no longer supports creation of custom type libraries out of the box, nor it can't depend on the type library for .NET Framework (as would require to maintain the shape of classes as they were in .NET Framework)

Version introduced

.NET 5.0 Preview 7

Old behavior

A number of Windows Forms types were decorated as visible to COM interop, and thus accessible to native code.

New behavior

None of Windows Forms API are visible to COM interop, and thus not accessible to native code.

Reason for change

  • Remove ComVisible(true) from enums, they were used for TLB generation/lookup. Since there is no WinForms TLB provided by .NET Core there is no value in keeping this attribute.
  • Remove ComVisible(true) from AccessibleObject classes. They are not CoCreateable (no parameterless constructor) and exposing an already existing instance to COM does not require that attribute.
  • Remove ComVisible(true) from Control/Component classes. This was used to allow hosting of WinForms controls via OLE/ActiveX, for example in VB6 or MFC. However this requires a TLB for WinForms which is no longer provided, as well as registry-based activation which also would not work out of the box. Generally there was no maintenance of COM based hosting of WinForms controls so its likely to be broken, therefore removing support for COM based hosting of WinForms controls instead of leaving it in an unsupported state.
    • This commit also removes ClassInterface attributes from controls. If hosting via OLE/ActiveX is not supported these attributes are not needed anymore. They are kept in other places where objects are still exposed to COM and the attribute may be relevant.
  • Remove ComVisible(true) from EventArgs. They were most likely used with OLE/ActiveX hosting, which is no longer supported. They are not CoCreateable either so the attribute has no purpose. Exposing existing instances without providing a TLB makes no sense either.
  • Remove ComVisible(true) from delegates. Purpose is unknown but since ActiveX hosting of WinForms Controls is no longer supported its unlikely to have any purpose any more.
  • Remove ComVisible(true) from some non-public code. The only potential consumer would be the new VS designer, but without a GUID specified its unlikely that its still needed.
  • Remove ComVisible(true) from some arbitrary public designer classes. The old VS designer may have been using COM interop to talk to them, but the old designer doesn't support .NET Core so there is most likely no one who needs these ComVisible.
  • IWin32Window defined the same GUID as defined in .NET Framework which has dangerous consequences. If interop with .NET Framework is required this can be ComImported.
  • The WinForms managed IDataObject was made ComVisible. This is not required, there is a separate ComImport interface declaration for IDataObject COM interop. Having the managed IDataObject being ComVisible is actually counterproductive since no TLB is provided and marshaling will always fail. Also the GUID was not specified and differed from .NET Framework so its unlikely that removing an undocumented IID will affect customers negatively.
  • Remove ComVisible(false) - those are placed in seemingly arbitrary places and are redundant when the default is to not expose classes to COM interop (if the default is to expose, then current set of annotations would also be wrong because way too few classes have this annotation)

Recommended action

The following example that relied on the .NET Framework type library (which basically allowed the JavaScript to call back into the form subclass via reflection) works on .NET Framework and .NET Core 3.1, but no longer works on .NET 5.0:

[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class Form1 : Form
{
    private WebBrowser webBrowser1 = new WebBrowser();

    protected override void OnLoad(EventArgs e)
    {
        webBrowser1.AllowWebBrowserDrop = false;
        webBrowser1.IsWebBrowserContextMenuEnabled = false;
        webBrowser1.WebBrowserShortcutsEnabled = false;
        webBrowser1.ObjectForScripting = this;

        webBrowser1.DocumentText =
            "<html><body><button " +
            "onclick=\"window.external.Test('called from script code')\">" +
            "call client code from script code</button>" +
            "</body></html>";
    }

    public void Test(String message)
    {
        MessageBox.Show(message, "client code");
    }
}

There are two possible ways to make the example working.

  1. Introduce a user-declared ObjectForScripting object which supports IDispatch (which is applied by default, unless changed explicitly at the project level)
public class MyScriptObject
{
    private Form1 _form;

    public MyScriptObject(Form1 form)
    {
        _form = form;
    }

    public void Test(string message)
    {
        MessageBox.Show(message, "client code");
    }
}

public partial class Form1 : Form
{
    protected override void OnLoad(EventArgs e)
    {
        // ...

        // will work correctly
        webBrowser1.ObjectForScripting = new MyScriptObject(this);

        // ...
    }
}
  1. Declare an interface with the methods to expose
public interface IForm1
{
    void Test(string message);
}

[ComDefaultInterface(typeof(IForm1))]
public partial class Form1 : Form, IForm1
{
    protected override void OnLoad(EventArgs e)
    {
        // ...

        // will work correctly
        webBrowser1.ObjectForScripting = this;

        // ...
    }
}

Category

  • Windows Forms

Affected APIs

All Windows Forms API


Issue metadata

  • Issue type: breaking-change

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions