Megosztás a következőn keresztül:


COM Hívható burkoló

Amikor egy COM-ügyfél meghív egy .NET-objektumot, a közös nyelvi futtatókörnyezet létrehozza a felügyelt objektumot és egy COM-hívható burkolót (CCW) az objektumhoz. A COM-ügyfelek nem hivatkoznak közvetlenül a .NET-objektumokra, a CCW-t használják proxyként a felügyelt objektumhoz.

A futtatókörnyezet pontosan egy CCW-t hoz létre egy felügyelt objektumhoz, függetlenül attól, hogy hány COM-ügyfél kéri a szolgáltatásait. Az alábbi ábrán látható, hogy több COM-ügyfél is rendelkezhet az INew felületet elérhetővé tevő CCW-ra mutató hivatkozással. A CCW viszont egyetlen hivatkozást tartalmaz arra a felügyelt objektumra, amely megvalósítja az interfészt, és szemétgyűjtést hajt végre. A COM- és a .NET-ügyfelek egyszerre is kezdeményezhetnek kéréseket ugyanazon a felügyelt objektumon.

Multiple COM clients holding a reference to the CCW that exposes INew.

A COM hívható burkolói láthatatlanok a .NET-futtatókörnyezetben futó más osztályok számára. Elsődleges céljuk, hogy a felügyelt és a nem felügyelt kód közötti hívásokat kezdeményezzék; A CCW-k azonban az általuk körbefutott felügyelt objektumok objektumidentitását és objektumélettartamát is kezelik.

Objektum identitása

A futtatókörnyezet lefoglalja a .NET-objektum memóriáját a szeméttel összegyűjtött halomból, így a futtatókörnyezet szükség szerint áthelyezheti az objektumot a memóriában. Ezzel szemben a futtatókörnyezet memóriát foglal le a CCW-hez egy nemcollected halomból, így a COM-ügyfelek közvetlenül hivatkozhatnak a burkolóra.

Objektum élettartama

A burkolt .NET-ügyféltől eltérően a CCW-t hagyományos COM-ként számolják. Amikor a CCW referenciaszáma eléri a nullát, a burkoló feloldja a referenciát a felügyelt objektumon. A rendszer a következő szemétgyűjtési ciklus során gyűjt egy felügyelt objektumot, amely nem tartalmaz további hivatkozásokat.

COM-felületek szimulálása

A CCW az összes nyilvános, COM-nézetben látható felületet, adattípust és értéket úgy tesz elérhetővé a COM-ügyfelek számára, hogy azok összhangban legyenek a COM felületalapú interakcióinak alkalmazásával. COM-ügyfél esetén a .NET-objektumok metódusainak meghívása megegyezik a COM-objektumok invokálási módszereivel.

Ennek a zökkenőmentes megközelítésnek a létrehozásához a CCW olyan hagyományos COM-interfészeket gyárt, mint az IUnknown és az IDispatch. Az alábbi ábrán látható, hogy a CCW egyetlen hivatkozást tart fenn a burkoló .NET-objektumon. A COM-ügyfél és a .NET-objektum is együttműködik egymással a CCW proxy- és csonképítésén keresztül.

Diagram that shows how CCW manufactures COM interfaces.

A felügyelt környezetben egy osztály által explicit módon implementált felületek felfedése mellett a .NET-futtatókörnyezet biztosítja az objektum nevében az alábbi táblázatban felsorolt COM-felületek implementációit. A .NET-osztály felülbírálhatja az alapértelmezett viselkedést az interfészek saját implementációjának biztosításával. A futtatókörnyezet azonban mindig biztosítja az IUnknown és az IDispatch interfészek implementálását.

Interfész Leírás
IDispatch Mechanizmust biztosít a késői kötéshez a beíráshoz.
IErrorInfo Szöveges leírást ad a hibáról, a forrásáról, a súgófájlról, a súgókörnyezetről és a hibát definiáló felület GUID-járól (.NET-osztályok esetén mindig GUID_NULL ).
IProvideClassInfo Lehetővé teszi a COM-ügyfelek számára, hogy hozzáférjenek a felügyelt osztály által implementált ITypeInfo felülethez. A .NET Core-on visszaadja COR_E_NOTSUPPORTED a COM-ból nem importált típusok esetén.
ISupportErrorInfo Lehetővé teszi a COM-ügyfél számára annak megállapítását, hogy a felügyelt objektum támogatja-e az IErrorInfo felületet. Ha igen, lehetővé teszi az ügyfél számára, hogy a legújabb kivételobjektumra mutatót szerezzen be. Minden felügyelt típus támogatja az IErrorInfo felületet.
ITypeInfo (csak .NET-keretrendszer) Olyan osztály típusadatait adja meg, amelyek pontosan megegyeznek a Tlbexp.exe által előállított típusadatokkal.
IUnknown Biztosítja az IUnknown felület szabványos implementációját, amellyel a COM-ügyfél felügyeli a CCW élettartamát, és típuskényszerítést biztosít.

A felügyelt osztály az alábbi táblázatban ismertetett COM-felületeket is biztosíthatja.

Interfész Leírás
A (_classname) osztály felülete A futtatókörnyezet által közzétett és explicit módon nem definiált felület, amely a felügyelt objektumokon explicit módon közzétett összes nyilvános felületet, metódust, tulajdonságot és mezőt elérhetővé teszi.
I Csatlakozás ionPoint és I Csatlakozás ionPointContainer A delegáltalapú eseményeket forrásul szolgáló objektumok felülete (az esemény-előfizetők regisztrálásának felülete).
IDispatchEx (csak .NET-keretrendszer) A futtatókörnyezet által biztosított interfész, ha az osztály az IExpando-t implementálja. Az IDispatchEx interfész az IDispatch felület kiterjesztése, amely az IDispatch-sel ellentétben lehetővé teszi a tagok számbavételét, hozzáadását, törlését és kis- és nagybetűk megkülönböztetését.
IEnumVARIANT A gyűjtemény típusú osztályok felülete, amely számba adja a gyűjtemény objektumait, ha az osztály IEnumerable-t implementál.

Az osztály felületének bemutatása

A felügyelt kódban nem explicit módon definiált osztályfelület egy olyan felület, amely a .NET-objektumon explicit módon közzétett összes nyilvános metódust, tulajdonságot, mezőt és eseményt elérhetővé teszi. Ez az interfész lehet kettős vagy csak küldési felület. Az osztályfelület megkapja magának a .NET-osztálynak a nevét, amelyet aláhúzás előz meg. Az Emlős osztály esetében például az osztály felülete _Mammal.

Származtatott osztályok esetén az osztályfelület az alaposztály összes nyilvános metódusát, tulajdonságát és mezőjét is elérhetővé teszi. A származtatott osztály emellett egy osztályfelületet is elérhetővé tesz az egyes alaposztályokhoz. Ha például az Emlős osztály kibővíti a MammalSuperclass osztályt, amely maga is kiterjeszti a System.Object osztályt, a .NET-objektum három, _Mammal, _MammalSuperclass és _Object nevű osztályfelületet tesz elérhetővé a COM-ügyfelek számára.

Vegyük például a következő .NET-osztályt:

' Applies the ClassInterfaceAttribute to set the interface to dual.
<ClassInterface(ClassInterfaceType.AutoDual)> _
' Implicitly extends System.Object.
Public Class Mammal
    Sub Eat()
    Sub Breathe()
    Sub Sleep()
End Class
// Applies the ClassInterfaceAttribute to set the interface to dual.
[ClassInterface(ClassInterfaceType.AutoDual)]
// Implicitly extends System.Object.
public class Mammal
{
    public void Eat() {}
    public void Breathe() {}
    public void Sleep() {}
}

A COM-ügyfél lekért egy mutatót a nevesített _Mammalosztályfelületre. A .NET-keretrendszer a Type Library Exporter (Tlbexp.exe) eszközzel létrehozhat egy, az _Mammal interfészdefiníciót tartalmazó típustárat. A típuskódtár-exportőr nem támogatott a .NET Core-on. Ha az Mammal osztály egy vagy több illesztőt implementált, az illesztők a társosztály alatt jelennek meg.

[odl, uuid(…), hidden, dual, nonextensible, oleautomation]
interface _Mammal : IDispatch
{
    [id(0x00000000), propget] HRESULT ToString([out, retval] BSTR*
        pRetVal);
    [id(0x60020001)] HRESULT Equals([in] VARIANT obj, [out, retval]
        VARIANT_BOOL* pRetVal);
    [id(0x60020002)] HRESULT GetHashCode([out, retval] short* pRetVal);
    [id(0x60020003)] HRESULT GetType([out, retval] _Type** pRetVal);
    [id(0x6002000d)] HRESULT Eat();
    [id(0x6002000e)] HRESULT Breathe();
    [id(0x6002000f)] HRESULT Sleep();
}
[uuid(…)]
coclass Mammal
{
    [default] interface _Mammal;
}

Az osztályfelület létrehozása nem kötelező. Alapértelmezés szerint a COM interop egy csak küldési felületet hoz létre minden osztályhoz, amelyet egy típustárba exportál. A felület automatikus létrehozását megakadályozhatja vagy módosíthatja az osztályra való alkalmazással ClassInterfaceAttribute . Bár az osztály felülete megkönnyíti a felügyelt osztályok COM-nak való felfedésének feladatát, a használata korlátozott.

Figyelemfelhívás

Az osztály felületének használata ahelyett, hogy explicit módon definiálja a sajátját, bonyolíthatja a felügyelt osztály jövőbeli verziószámozását. Az osztály felületének használata előtt olvassa el az alábbi irányelveket.

Definiáljon explicit felületet a COM-ügyfelek számára az osztályfelület létrehozása helyett.

Mivel a COM interop automatikusan létrehoz egy osztályfelületet, az osztály verzió utáni módosításai megváltoztathatják a közös nyelvi futtatókörnyezet által közzétett osztályfelület elrendezését. Mivel a COM-ügyfelek általában nincsenek felkészülve a felület elrendezésének változásainak kezelésére, az osztály tagelrendezésének módosítása esetén megszakadnak.

Ez az iránymutatás megerősíti azt a fogalmat, hogy a COM-ügyfelek számára elérhető felületeknek változatlanoknak kell maradniuk. A COM-ügyfelek feltörésének kockázatának csökkentése érdekében a felületelrendezés véletlen átrendezésével különítse el az osztály minden módosítását a felületelrendezéstől az interfészek explicit definiálásával.

A ClassInterfaceAttribute használatával kikapcsolhatja az osztály felületének automatikus generálását, és explicit felületet implementálhat az osztályhoz, ahogy az alábbi kódrészlet mutatja:

<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
    Implements IExplicit
    Sub M() Implements IExplicit.M
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class LoanApp : IExplicit
{
    int IExplicit.M() { return 0; }
}

A ClassInterfaceType.None érték megakadályozza az osztály felületének generálását, amikor az osztály metaadatait exportálja egy típustárba. Az előző példában a COM-ügyfelek csak a felületen keresztül férhetnek hozzá az LoanApp osztályhoz IExplicit .

Kerülje a küldési azonosítók (DispIds) gyorsítótárazását

Az osztályfelület használata elfogadható lehetőség a szkriptelt ügyfelek, a Microsoft Visual Basic 6.0-ügyfelek vagy bármely olyan késői kötésű ügyfél számára, amely nem gyorsítótárazza az interfésztagok DispId-azonosítóit. A DispIds azonosítja az illesztőtagokat a késői kötés engedélyezéséhez.

Az osztályfelület esetében a DispIds létrehozása a tagnak az interfészen belüli pozícióján alapul. Ha módosítja a tag sorrendjét, és egy típustárba exportálja az osztályt, az osztály felületén létrehozott DispId-eket módosítja.

Ha el szeretné kerülni a késői com-ügyfelek törését az osztályfelület használatakor, alkalmazza a ClassInterfaceAttribute értéket a ClassInterfaceType.AutoDispatch értékkel. Ez az érték egy csak küldési osztály felületét valósítja meg, de kihagyja a felület leírását a típustárból. A felület leírása nélkül az ügyfelek fordításkor nem tudják gyorsítótárba helyezni a DispId-eket. Bár ez az osztályfelület alapértelmezett felülettípusa, az attribútumértéket explicit módon alkalmazhatja.

<ClassInterface(ClassInterfaceType.AutoDispatch)> Public Class LoanApp
    Implements IAnother
    Sub M() Implements IAnother.M
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class LoanApp
{
    public int M() { return 0; }
}

Ha futásidőben szeretné lekérni egy felülettag DispId azonosítóját, a COM-ügyfelek meghívhatják az IDispatch.GetIdsOfNames nevet. Ha metódust szeretne meghívni a felületen, adja át a visszaadott DispId azonosítót argumentumként az IDispatch.Invoke fájlnak.

Korlátozza az osztályillesztő kettős felületi beállításának használatát.

A kettős interfészek lehetővé teszik a COM-ügyfelek korai és késői kötését az interfésztagokhoz. A tervezéskor és a tesztelés során hasznos lehet kettősre állítani az osztály felületét. Olyan felügyelt osztály (és alaposztályai) esetében, amelyek soha nem lesznek módosítva, ez a beállítás is elfogadható. Minden más esetben kerülje az osztály felületének kettősre állítását.

Ritkán előfordulhat, hogy az automatikusan létrehozott kettős felület megfelelő; azonban gyakrabban a verzióval kapcsolatos összetettséghez vezet. Egy származtatott osztály osztályfelületét használó COM-ügyfelek például könnyen szakíthatnak az alaposztály módosításaival. Ha egy harmadik fél biztosítja az alaposztályt, az osztály felületének elrendezése nincs önnél szabályozva. A csak küldési felülettől eltérően a kettős felület (ClassInterfaceType.AutoDual) az exportált típustár osztályfelületének leírását tartalmazza. Ez a leírás arra ösztönzi a későn kötött ügyfeleket, hogy fordításkor gyorsítótárazsák a DispId-eket.

Győződjön meg arról, hogy az összes COM-eseményértesítés késik.

Alapértelmezés szerint a COM-típusadatok közvetlenül felügyelt szerelvényekbe lesznek beágyazva, ami szükségtelenné teszi az elsődleges interop szerelvények (PIA-k) szükségességét. A beágyazott típusú információk egyik korlátozása azonban az, hogy nem támogatja a COM-eseményértesítések korai kötésű vtable-hívások útján történő kézbesítését, csak a késedelmes IDispatch::Invoke hívásokat támogatja.

Ha az alkalmazás korai kötésű hívásokat igényel a COM eseményfelületi metódusokhoz, beállíthatja a Beágyazás interop típusok tulajdonságot a Visual Studióban true, vagy felveheti a projektfájlba a következő elemet:

<EmbedInteropTypes>True</EmbedInteropTypes>

Lásd még