Udostępnij za pośrednictwem


Kod macierzysty nie może uzyskać dostępu do obiektów formularzy systemu Windows

Począwszy od platformy .NET 5, nie można już uzyskać dostępu do obiektów windows Forms z kodu natywnego.

Opis zmiany

W poprzednich wersjach platformy .NET niektóre typy formularzy systemu Windows zostały ozdobione jako widoczne dla międzyoperacyjności modelu COM, a tym samym były dostępne dla kodu natywnego. Począwszy od platformy .NET 5, żaden interfejs API formularzy systemu Windows nie jest widoczny dla międzyoperacyjności modelu COM lub jest dostępny dla kodu natywnego. Środowisko uruchomieniowe platformy .NET nie obsługuje już tworzenia niestandardowych bibliotek typów poza ramą. Ponadto środowisko uruchomieniowe platformy .NET nie może zależeć od biblioteki typów programu .NET Framework (co wymagałoby utrzymania kształtu klas, tak jak w programie .NET Framework).

Przyczyna wprowadzenia zmiany

  • ComVisible(true) Usunięcie z wyliczenia, które były używane do generowania biblioteki typów (pliku TLB) i wyszukiwania: ponieważ nie ma TLB WinForms dostarczonego przez platformę .NET Core, nie ma żadnej wartości w utrzymaniu tego atrybutu.
  • ComVisible(true) Usuwanie z AccessibleObject klas: klasy nie są coCreateable (nie mają konstruktora bez parametrów) i uwidacznianie już istniejącego wystąpienia modelu COM nie wymaga tego atrybutu.
  • ComVisible(true) Usuwanie z Control klas iComponent: to było używane do hostowania kontrolek WinForms za pośrednictwem OLE/ActiveX, na przykład w VB6 lub MFC. Wymaga to jednak modułu TLB dla winForms, który nie jest już udostępniany, a także aktywacji opartej na rejestrze, co również nie zadziałałoby z pudełka. Ogólnie rzecz biorąc, nie było konserwacji hostingu opartego na modelu COM kontrolek WinForms, więc obsługa została usunięta zamiast pozostawiać ją w stanie nieobsługiwanym.
  • Usuwanie atrybutów ClassInterface z kontrolek: jeśli hostowanie za pośrednictwem OLE/ActiveX nie jest obsługiwane, te atrybuty nie są już potrzebne. Są one przechowywane w innych miejscach, w których obiekty są nadal widoczne dla modelu COM, a atrybut może być istotny.
  • Usunięcie z ComVisible(true) programu EventArgs: Najprawdopodobniej były używane z hostingiem OLE/ActiveX, który nie jest już obsługiwany. Nie są one również coCreateable, więc atrybut nie ma celu. Ponadto uwidacznianie istniejących wystąpień bez zapewnienia modułu TLB nie ma sensu.
  • ComVisible(true) Usuwanie z delegatów: Cel jest nieznany, ale ponieważ hostowanie kontrolek WinForms w usłudze ActiveX nie jest już obsługiwane, jest mało prawdopodobne, aby mieć jakąkolwiek użyteczność.
  • ComVisible(true) Usunięcie z kodu innego niż publiczny: jedynym potencjalnym użytkownikiem będzie nowy projektant programu Visual Studio, ale bez określonego identyfikatora GUID jest mało prawdopodobne, że jest nadal potrzebny.
  • Usunięcie z niektórych dowolnych klas projektanta ComVisible(true) publicznego: Stary projektant programu Visual Studio mógł używać międzyoperajności modelu COM do komunikacji z tymi klasami. Jednak stary projektant nie obsługuje platformy .NET Core, więc niewiele osób potrzebuje tych elementów jako ComVisible.
  • IWin32Window zdefiniowano ten sam identyfikator GUID, który został zdefiniowany w programie .NET Framework, co ma niebezpieczne konsekwencje. Jeśli potrzebujesz współdziałania z programem .NET Framework, użyj polecenia ComImport.
  • Zarządzane IDataObject przez narzędzie WinForms zostało wykonane .ComVisible Nie jest to wymagane, istnieje oddzielna ComImport deklaracja interfejsu dla IDataObject międzyoperacjności MODELU COM. Jest on przeciwny do zamierzonego IDataObjectComVisible, ponieważ nie podano TLB, a marshalling zawsze zakończy się niepowodzeniem. Ponadto identyfikator GUID nie został określony i różnił się od programu .NET Framework, więc jest mało prawdopodobne, że usunięcie nieudokumentowanego identyfikatora IID wpłynie negatywnie na klientów.
  • Usunięcie elementu ComVisible(false): Są one umieszczane w pozornie dowolnych miejscach i są nadmiarowe, gdy ustawieniem domyślnym jest nie uwidacznianie klas międzyoperacyjnych MODELU COM.

Wprowadzona wersja

.NET 5.0

Poniższy przykład działa w programach .NET Framework i .NET Core 3.1. W tym przykładzie jest oparta biblioteka typów programu .NET Framework, która umożliwia kodowi JavaScript wywołanie z powrotem do podklasy formularza za pośrednictwem odbicia.

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

Istnieją dwa możliwe sposoby działania przykładu na platformie .NET 5 i nowszych wersjach:

  • Wprowadź obiekt zadeklarowany ObjectForScripting przez użytkownika, który obsługuje IDispatch (który jest stosowany domyślnie, chyba że został jawnie zmieniony na poziomie projektu).

    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);
    
            ...
        }
    }
    
  • Zadeklaruj interfejs za pomocą metod do uwidocznienia.

    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;
    
            ...
        }
    }
    

Dotyczy interfejsów API

Wszystkie interfejsy API formularzy systemu Windows.