Nativer Code kann nicht auf Windows Forms-Objekte zugreifen.

Ab .NET 5 können Sie nicht mehr von nativem Code aus auf Windows Forms-Objekte zugreifen.

Änderungsbeschreibung

In früheren Versionen von .net wurden einige Windows Forms Typen für COM-Interop als sichtbar versehen und sind daher für nativen Code zugänglich. Ab .NET 5 sind keine Windows Forms-APIs mehr für COM-Interop sichtbar, noch kann von nativem Code aus auf sie zugegriffen werden. Die .NET-Runtime unterstützt nicht mehr standardmäßig das Erstellen von benutzerdefinierten Typbibliotheken. Darüber hinaus kann die .NET-Runtime nicht von der Typbibliothek für .NET Framework abhängig sein (was das Beibehalten der Form von Klassen erfordern würde, wie sie in .NET Framework vorlagen).

Grund für die Änderung

  • Entfernen von ComVisible(true) aus Enumerationen, die für die Generierung und Suche der Typbibliothek (TLB-Datei) verwendet wurden: Da keine WinForms-TLB von .NET Core bereitgestellt wird, gibt es keinen Grund, dieses Attribut beizubehalten.
  • Entfernen von ComVisible(true) aus AccessibleObject-Klassen: Die Klassen sind nicht CoCreateable (sie haben keinen parameterlosen Konstruktor), und um eine bereits vorhandene Instanz für COM verfügbar zu machen, ist kein Attribut erforderlich.
  • Entfernen von ComVisible(true) aus Control- und Component-Klassen: Dies wurde verwendet, um das Hosting von WinForms-Steuerelementen über OLE/ActiveX zuzulassen, z. B. in VB6 oder MFC. Jedoch erfordert dies eine TLB für WinForms, die nicht mehr bereitgestellt wird, sowie die registrierungsbasierte Aktivierung, die auch nicht standardmäßig funktionieren würde. Im Allgemeinen gab es keine Wartung des COM-basierten Hostings von WinForms-Steuerelementen, daher wurde die Unterstützung entfernt, anstatt sie in einem nicht gewarteten Zustand beizubehalten.
  • Entfernen von ClassInterface-Attributen aus Steuerelementen: Wenn das Hosting über OLE/ActiveX nicht unterstützt wird, sind diese Attribute nicht mehr erforderlich. Sie werden an anderen Stellen beibehalten, wo Objekte weiterhin für COM verfügbar gemacht werden und das Attribut möglicherweise relevant ist.
  • Entfernen von ComVisible(true) aus EventArgs: Sie wurden wahrscheinlich mit dem OLE/ActiveX-Hosting verwendet, das nicht mehr unterstützt wird. Sie sind ebenfalls nicht CoCreateable, sodass das Attribut keinen Zweck hat. Außerdem ist es nicht sinnvoll, vorhandene Instanzen ohne Bereitstellung einer TLB verfügbar zu machen.
  • Entfernen von ComVisible(true)-Delegaten: Der Zweck ist unbekannt, aber da ActiveX-Hosting von WinForms-Steuerelementen nicht mehr unterstützt wird, ist es unwahrscheinlich, dass es sinnvoll ist.
  • Entfernen von ComVisible(true) aus manchem nichtöffentlichem Code: Der einzige potenzielle Consumer wäre der neue Visual Studio-Designer, aber ohne Angabe einer GUID ist es unwahrscheinlich, dass er immer noch benötigt wird.
  • Entfernen von ComVisible(true) aus einigen beliebigen öffentlichen Designerklassen: Der alte Visual Studio-Designer hat möglicherweise COM-Interop verwendet, um mit diesen Klassen zu kommunizieren. Jedoch unterstützt der alte Designer .NET Core nicht, sodass nur wenige Personen diese als ComVisible benötigen würden.
  • IWin32Window definierte dieselbe GUID, die in .NET Framework definiert wurde. Dies hat gefährliche Konsequenzen. Wenn Sie Interop mit .NET Framework benötigen, verwenden Sie ComImport.
  • Das von WinForms verwaltete IDataObject wurde zu ComVisible gemacht. Dies ist nicht erforderlich, es gibt eine separate ComImport-Schnittstellendeklaration für IDataObject-COM-Interop. Es ist kontraproduktiv, wenn das verwaltete IDataObjectComVisible ist, da keine TLB bereitgestellt wird und beim Marshalling immer Fehler auftreten. Außerdem wurde die GUID nicht angegeben und unterschied sich von .NET Framework, sodass es unwahrscheinlich ist, dass das Entfernen einer nicht dokumentierten IID für Kunden negative Auswirkungen hat.
  • Entfernen von ComVisible(false): Diese werden an scheinbar beliebigen Stellen platziert und sind redundant, wenn standardmäßig keine Klassen für COM-Interop verfügbar gemacht werden.

Eingeführt in Version

.NET 5.0

Das folgende Beispiel funktioniert mit .NET Framework und .NET Core 3.1. Dieses Beispiel basiert auf der .NET Framework-Typbibliothek, die JavaScript ermöglicht, über Reflexion einen Rückruf in die Formularunterklasse durchzusetzen.

[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");
    }
}

Es gibt zwei Möglichkeiten, das Beispiel für .NET 5 und höhere Versionen anzupassen:

  • Führen Sie ein benutzerdeklariertes ObjectForScripting-Objekt ein, das IDispatch unterstützt (was standardmäßig angewendet wird, es sei denn, dies wird explizit auf der Projektebene geändert).

    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)
        {
            ...
    
            // Works correctly.
            webBrowser1.ObjectForScripting = new MyScriptObject(this);
    
            ...
        }
    }
    
  • Deklarieren Sie eine Schnittstelle mit den Methoden, die verfügbar gemacht werden sollen.

    public interface IForm1
    {
        void Test(string message);
    }
    
    [ComDefaultInterface(typeof(IForm1))]
    public partial class Form1 : Form, IForm1
    {
        protected override void OnLoad(EventArgs e)
        {
            ...
    
            // Works correctly.
            webBrowser1.ObjectForScripting = this;
    
            ...
        }
    }
    

Betroffene APIs

Alle Windows Forms-APIs.