O código nativo não pode acessar objetos do Windows Forms
A partir do .NET 5, você não pode mais acessar objetos do Windows Forms a partir do código nativo.
Descrição das alterações
Em versões anteriores do .NET, alguns tipos do Windows Forms eram decorados como visíveis para a interoperabilidade COM e, portanto, eram acessíveis ao código nativo. A partir do .NET 5, nenhuma API do Windows Forms é visível para a interoperabilidade COM ou acessível ao código nativo. O runtime do .NET não dá mais suporte à criação de bibliotecas de tipos personalizados prontas para uso. Além disso, o runtime do .NET não pode depender da biblioteca de tipos para o .NET Framework (isso exigiria manter a forma das classes como estavam no .NET Framework).
Motivo da alteração
- Remoção de
ComVisible(true)
das enumerações usadas para a geração e pesquisa de biblioteca de tipos (arquivo TLB): como não há nenhum TLB do WinForms fornecido pelo .NET Core, não há valor em manter esse atributo. - Remoção de
ComVisible(true)
de classesAccessibleObject
: as classes não podem ser cocriadas (não têm construtor sem parâmetros), e expor uma instância já existente ao COM não requer esse atributo. - Remoção de
ComVisible(true)
das classesControl
eComponent
: isso foi usado para permitir a hospedagem de controles do WinForms por meio do OLE/ActiveX, por exemplo, no VB6 ou MFC. No entanto, isso requer um TLB para o WinForms, que não é mais fornecido, bem como ativação baseada em registro, que também não funcionaria prontamente. Em geral, não houve manutenção da hospedagem baseada em COM de controles do WinForms; portanto, o suporte foi removido em vez de deixá-lo em um estado sem suporte. - Remoção de atributos
ClassInterface
de controles: se a hospedagem via OLE/ActiveX não tiver suporte, esses atributos não serão mais necessários. Eles são mantidos em outros locais onde os objetos ainda estão expostos ao COM e o atributo pode ser relevante. - Remoção de
ComVisible(true)
deEventArgs
: eles provavelmente foram usados com a hospedagem OLE/ActiveX, que não tem mais suporte. Eles também não podem ser cocriados; portanto, o atributo não tem nenhuma finalidade. Além disso, expor instâncias existentes sem fornecer um TLB não faz sentido. - Remoção de delegados
ComVisible(true)
: a finalidade é desconhecida, mas como a hospedagem ActiveX de controles do WinForms não tem mais suporte, é improvável que tenha qualquer utilidade. - Remoção de
ComVisible(true)
de algum código não público: o único consumidor em potencial seria o novo designer do Visual Studio, mas sem um GUID especificado é improvável que ele ainda seja necessário. - Remoção de
ComVisible(true)
de algumas classes arbitrárias de designer público: o antigo designer do Visual Studio pode ter usado a interoperabilidade COM para conversar com essas classes. No entanto, o designer antigo não dá suporte ao .NET Core, portanto, poucas pessoas precisariam deles comoComVisible
. IWin32Window
definiu o mesmo GUID que foi definido em .NET Framework, o que traz consequências perigosas. Se você precisar de interoperabilidade com o .NET Framework, useComImport
.- O WinForms gerenciado
IDataObject
foi tornadoComVisible
. Isso não é necessário; há uma declaração de interface separadaComImport
para a interoperabilidade COMIDataObject
. É contraproducente ter oIDataObject
gerenciado comoComVisible
, já que nenhum TLB é fornecido e realizar marshaling sempre falhará. Além disso, o GUID não foi especificado e difere de .NET Framework; portanto, é improvável que a remoção de uma IID não documentada afete negativamente os clientes. - Remoção de
ComVisible(false)
: eles são colocados em locais aparentemente arbitrários e são redundantes quando o padrão é não expor classes à interoperabilidade COM.
Versão introduzida
.NET 5.0
Ação recomendada
O exemplo a seguir funciona no .NET Framework e no .NET Core 3.1. Este exemplo se baseia na biblioteca de tipos .NET Framework, que permite que o JavaScript retorne à subclasse do formulário por meio da reflexão.
[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");
}
}
Há duas maneiras possíveis de fazer o exemplo funcionar no .NET 5 e versões posteriores:
Introduzir um objeto declarado pelo usuário
ObjectForScripting
com suporte aIDispatch
(que é aplicado por padrão, a menos que seja alterado explicitamente no nível do projeto).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); ... } }
Declarar uma interface com os métodos a serem expostos.
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; ... } }
APIs afetadas
Todas as APIs do Windows Forms.
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de