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.
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.
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 _Mammal
osztá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
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: