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)
ausAccessibleObject
-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)
ausControl
- undComponent
-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)
ausEventArgs
: 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 alsComVisible
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 SieComImport
.- Das von WinForms verwaltete
IDataObject
wurde zuComVisible
gemacht. Dies ist nicht erforderlich, es gibt eine separateComImport
-Schnittstellendeklaration fürIDataObject
-COM-Interop. Es ist kontraproduktiv, wenn das verwalteteIDataObject
ComVisible
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
Empfohlene Maßnahme
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, dasIDispatch
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.