Partilhar via


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.

Alterar descrição

Em versões anteriores do .NET, alguns tipos de Windows Forms eram decorados como visíveis para interoperabilidade COM e, portanto, eram acessíveis ao código nativo. A partir do .NET 5, nenhuma API do Windows Forms é visível para interoperabilidade COM ou acessível para código nativo. O tempo de execução do .NET não suporta mais a criação de bibliotecas de tipos personalizados prontas para uso. Além disso, o tempo de execução do .NET não pode depender da biblioteca de tipos do .NET Framework (o que exigiria manter a forma das classes como estavam no .NET Framework).

Motivo da mudança

  • Remoção de ComVisible(true) das enumerações que foram usadas para geração e pesquisa de biblioteca de tipos (arquivo TLB): Dado que não existe um WinForms TLB fornecido pelo .NET Core, não faz sentido manter este atributo.
  • Remoção de ComVisible(true) das classes AccessibleObject: As classes não são CoCreateable (não têm um construtor sem parâmetros) e expor uma instância já existente para COM não requer esse atributo.
  • Remoção de ComVisible(true) das classes Control e Component: Este elemento foi usado para permitir a hospedagem de controlos WinForms via OLE/ActiveX, por exemplo, em VB6 ou MFC. No entanto, isso requer um TLB para WinForms, que não é mais fornecido, bem como ativação baseada no registro, que também não funcionaria fora da caixa. Geralmente, não havia manutenção de hospedagem baseada em COM de controles WinForms, então o suporte foi removido em vez de deixá-lo em um estado sem suporte.
  • Remoção de ClassInterface atributos de controles: Se a hospedagem via OLE/ActiveX não for suportada, esses atributos não serão mais necessários. Eles são mantidos em outros lugares onde os objetos ainda estão expostos à OCM e o atributo pode ser relevante.
  • Remoção de ComVisible(true) de EventArgs: Eles foram provavelmente utilizados com hospedagem OLE / ActiveX, que já não é suportada. Eles também não são CoCreateable, então o atributo não tem propósito. Além disso, expor instâncias existentes sem fornecer um TLB não faz sentido.
  • Remoção de ComVisible(true) dos delegados: O objetivo é desconhecido, mas como o suporte ao ActiveX para controles WinForms não é mais fornecido, é improvável que tenha qualquer utilidade.
  • Remoção do ComVisible(true) de algum código não público: o único consumidor potencial seria o novo designer do Visual Studio, mas sem um GUID especificado, é improvável que ainda seja necessário.
  • Remoção de ComVisible(true) de algumas classes arbitrárias de editor público: O editor antigo do Visual Studio poderia estar usando interoperabilidade COM para comunicar-se com estas classes. No entanto, o designer antigo não suporta .NET Core, então poucas pessoas precisariam deles como ComVisible.
  • IWin32Window usou o mesmo GUID já definido no .NET Framework, o que tem consequências perigosas. Se você precisar de interoperabilidade com o .NET Framework, use ComImport.
  • O WinForms gerenciado IDataObject foi feito ComVisible. Isso não é necessário, há uma declaração separada de interface ComImport para IDataObject COM interop. É contraproducente ter o IDataObject gerido como ComVisible, uma vez que nenhum TLB é fornecido e o marshalling sempre falhará. Além disso, o GUID não foi especificado e diferiu do .NET Framework, portanto, é improvável que a remoção de um IID não documentado afete negativamente os clientes.
  • Remoção de ComVisible(false): Estes são colocados em lugares aparentemente arbitrários e são redundantes quando o padrão é não expor classes à interoperabilidade COM.

Versão introduzida

.NET 5.0

O exemplo a seguir funciona no .NET Framework e no .NET Core 3.1. Este exemplo depende da biblioteca de tipos do .NET Framework, que permite que o JavaScript chame de volta para a subclasse do formulário por meio de 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:

  • Introduza um objeto declarado ObjectForScripting pelo usuário que ofereça suporte IDispatch (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);
    
            ...
        }
    }
    
  • Declare 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.