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


.NET-típusok minősítése a COM-együttműködéshez

.NET-típusok elérhetővé tehetők a COM-nak

Ha a szerelvényben lévő típusokat com-alkalmazások számára szeretné elérhetővé tenni, a tervezéskor vegye figyelembe a COM interop követelményeit. A felügyelt típusok (osztály, felület, struktúra és enumerálás) zökkenőmentesen integrálhatók a COM-típusokba, ha betartja az alábbi irányelveket:

  • Az osztályoknak explicit módon kell implementálniuk a felületeket.

    Bár a COM interop egy olyan mechanizmust biztosít, amely automatikusan létrehoz egy felületet, amely tartalmazza az osztály és az alaposztály tagjait, sokkal jobb explicit interfészeket biztosítani. Az automatikusan létrehozott felületet osztályfelületnek nevezzük. Útmutatásért lásd : Az osztály felületének bemutatása.

    A Visual Basic, a C# és a C++ használatával illesztődefiníciókat is beépíthet a kódba ahelyett, hogy az interfészdefiníciós nyelvet (IDL) vagy annak megfelelőjét kellene használnia. A szintaxis részleteiért tekintse meg a nyelvi dokumentációt.

  • A felügyelt típusoknak nyilvánosnak kell lenniük.

    A rendszer csak a szerelvény nyilvános típusait regisztrálja és exportálja a típustárba. Ennek eredményeképpen csak a nyilvános típusok láthatók a COM-nak.

    A felügyelt típusok olyan más felügyelt kódnak teszik elérhetővé a funkciókat, amelyek esetleg nem lesznek közzétéve a COM-nak. A paraméteres konstruktorok, a statikus metódusok és az állandó mezők például nem érhetők el a COM-ügyfelek számára. Továbbá, mivel a futtatókörnyezet egy típuson belül és kívülre alakítja az adatokat, az adatok másolhatók vagy átalakíthatók.

  • A metódusnak, tulajdonságoknak, mezőknek és eseményeknek nyilvánosnak kell lenniük.

    A nyilvános típusok tagjainak is nyilvánosnak kell lenniük, ha a COM-nak láthatónak kell lenniük. A szerelvény, a nyilvános típus vagy a nyilvános típusú nyilvános tagok láthatóságát az ComVisibleAttributealkalmazásával korlátozhatja. Alapértelmezés szerint az összes nyilvános típus és tag látható.

  • A típusoknak nyilvános paraméter nélküli konstruktorsal kell rendelkezniük, amely a COM-ból aktiválható.

    A felügyelt, nyilvános típusok láthatók a COM-nak. Nyilvános paraméter nélküli konstruktor (argumentumok nélküli konstruktor) nélkül azonban a COM-ügyfelek nem tudják létrehozni a típust. A COM-ügyfelek akkor is használhatják a típust, ha más módon aktiválják.

  • A típusok nem lehetnek absztraktak.

    Sem a COM-ügyfelek, sem a .NET-ügyfelek nem hozhatnak létre absztrakt típusokat.

COM-ba exportálva a felügyelt típus öröklési hierarchiája összesimul. A verziószámozás a felügyelt és a nem felügyelt környezetek között is eltér. A COM-nak közzétett típusok verziószámozási jellemzői nem azonosak a többi felügyelt típussal.

COM-típusok felhasználása a .NET-ből

Ha COM-típusokat kíván használni a .NET-ből, és nem szeretne olyan eszközöket használni, mint a Tlbimp.exe (Típustár-importáló), kövesse az alábbi irányelveket:

  • Az illesztőknek rendelkezniük kell az ComImportAttribute alkalmazással.
  • Az illesztőknek a GuidAttribute COM-felület felületazonosítójával kell rendelkezniük.
  • Az illesztőknek alkalmazniuk kell az InterfaceTypeAttribute illesztő alapfelülettípusának (IUnknownIDispatchvagy IInspectable) megadására.
    • Az alapértelmezett beállítás az, hogy a deklarált metódusok alaptípusa IDispatch és hozzáfűzése az interfész várt virtuális függvénytábláihoz.
    • Csak .NET-keretrendszer támogatja az IInspectablealaptípus megadását.

Ezek az irányelvek biztosítják a gyakori forgatókönyvek minimális követelményeit. Számos további testreszabási lehetőség létezik, amelyeket az Interop attribútumok alkalmazása című témakörben ismertetünk.

COM-felületek definiálása a .NET-ben

Amikor a .NET-kód egy COM-objektum metódusát az attribútumot tartalmazó ComImportAttribute felületen keresztül próbálja meghívni, létre kell állítania egy virtuális függvénytáblát (más néven virtuális táblát vagy virtuális gépet), hogy létrehozhassa a felület .NET-definícióját a meghívandó natív kód meghatározásához. Ez a folyamat összetett. Az alábbi példák néhány egyszerű esetet mutatnak be.

Fontolja meg a COM-felületet néhány módszerrel:

struct IComInterface : public IUnknown
{
    STDMETHOD(Method)() = 0;
    STDMETHOD(Method2)() = 0;
};

Ehhez a felülethez a következő táblázat ismerteti a virtuális függvény táblaelrendezését:

IComInterface virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2

A rendszer minden metódust a deklarált sorrendben ad hozzá a virtuális függvény táblához. Az adott sorrendet a C++ fordító határozza meg, de túlterhelés nélküli egyszerű esetekben a deklarációs sorrend határozza meg a táblában szereplő sorrendet.

Deklaráljon egy .NET-felületet, amely megfelel ennek az interfésznek az alábbiak szerint:

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid(/* The IID for IComInterface */)]
interface IComInterface
{
    void Method();
    void Method2();
}

Az InterfaceTypeAttribute alapfelületet adja meg. A következő lehetőségek közül választhat:

ComInterfaceType Érték Alapfelület típusa A tagok viselkedése az attribútumalapú felületen
InterfaceIsIUnknown IUnknown A virtuális függvénytáblában először a tagok IUnknown, majd a felület tagjai vannak deklarációs sorrendben.
InterfaceIsIDispatch IDispatch A tagok nem lesznek hozzáadva a virtuális függvénytáblához. Csak a IDispatch.
InterfaceIsDual IDispatch A virtuális függvénytáblában először a tagok IDispatch, majd a felület tagjai vannak deklarációs sorrendben.
InterfaceIsIInspectable IInspectable A virtuális függvénytáblában először a tagok IInspectable, majd a felület tagjai vannak deklarációs sorrendben. Csak .NET-keretrendszer támogatott.

COM-felület öröklése és .NET

A com interop rendszer, amely a ComImportAttribute felületet használja, nem kommunikál az interfész öröklésével, így váratlan viselkedést okozhat, hacsak nem végez néhány enyhítő lépést.

Az attribútumot használó COM-forrásgenerátor interakcióba lép a System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute felület öröklésével, így a vártnál jobban viselkedik.

COM-felület öröklése c++ nyelven

A C++-ban a fejlesztők az alábbiak szerint deklarálhatják az egyéb COM-felületekből származó COM-felületeket:

struct IComInterface : public IUnknown
{
    STDMETHOD(Method)() = 0;
    STDMETHOD(Method2)() = 0;
};

struct IComInterface2 : public IComInterface
{
    STDMETHOD(Method3)() = 0;
};

Ezt a deklarációs stílust rendszeresen használják olyan mechanizmusként, amely metódusokat ad hozzá a COM-objektumokhoz a meglévő felületek módosítása nélkül, ami kompatibilitástörő változás lenne. Ez az öröklési mechanizmus a következő virtuális függvénytáblázat-elrendezéseket eredményezi:

IComInterface virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
IComInterface2 virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
5 IComInterface2::Method3

Ennek eredményeképpen könnyen meghívható egy metódus, amely egy adott helyről van definiálva IComInterfaceIComInterface2*. A metódusok alapillesztőn való meghívásához nincs szükség hívásra az alapfelületre mutató mutató lekéréséhez QueryInterface . Emellett a C++ lehetővé teszi az implicit átalakítást a másikról IComInterface2* a másikraIComInterface*, amely jól definiált, és lehetővé teszi, hogy ne hívjon újra.QueryInterface Ennek eredményeképpen C vagy C++-ban soha nem kell meghívnia QueryInterface az alaptípust, ha nem szeretné, ami néhány teljesítménybeli javulást is lehetővé tehet.

Feljegyzés

A WinRT-felületek nem követik ezt az öröklési modellt. Úgy vannak definiálva, hogy ugyanazt a modellt kövessék, mint a .NET-ben a [ComImport]-based COM interop modell.

Interfészöröklés a ComImportAttribute

A .NET-ben a felületöröklésnek tűnő C# kód valójában nem interfészöröklés. Tekintse meg az alábbi kódot:

interface I
{
    void Method1();
}
interface J : I
{
    void Method2();
}

Ez a kód nem azt mondja, hogy "J implementálja I." A kód valójában azt mondja, hogy "minden olyan típust, amely implementálja J azt is implementálnia Ikell." Ez a különbség ahhoz az alapvető kialakítási döntéshez vezet, amely a felület öröklését a -based interop unergonomic-ban ComImportAttributeteszi lehetővé. A felületeket mindig önállónak tekintik; az interfész alapillesztőlistájának nincs hatása semmilyen számításra egy adott .NET-adapter virtuális függvénytáblájának meghatározásához.

Ennek eredményeképpen az előző C++ COM felületi példa természetes megfelelője egy másik virtuális függvénytábla-elrendezéshez vezet.

C#-kód:

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
    void Method();
    void Method2();
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
    void Method3();
}

Virtuális függvénytáblázat elrendezései:

IComInterface virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
IComInterface2 virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface2::Method3

Mivel ezek a virtuális függvénytáblák eltérnek a C++ példától, ez futásidőben komoly problémákhoz fog vezetni. Ezeknek a felületeknek a helyes definíciója a .NET-ben ComImportAttribute a következő:

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
    void Method();
    void Method2();
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
    new void Method();
    new void Method2();
    void Method3();
}

Metaadatok szintjén nem implementálhatóIComInterface, IComInterface2 csak azt határozza meg, hogy a implementálóknak IComInterface2 is implementálniuk IComInterfacekell. Ezért az alapfelület-típusok minden metódusát újra kell alkalmazni.

Interfészöröklés ( GeneratedComInterfaceAttribute .NET 8 és újabb verziók)

A COM-forrásgenerátort a GeneratedComInterfaceAttribute C# interfész öröklése com-interfészöröklésként aktiválja, így a virtuális függvénytáblák a várt módon vannak elrendezve. Az előző példában a .NET-felületek System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute helyes definíciója a következő:

[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
    void Method();
    void Method2();
}

[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
    void Method3();
}

Az alapfelületek módszereit nem kell újból bejelenteni, és nem szabad újra bejelenteni. Az alábbi táblázat az eredményként kapott virtuális függvénytáblákat ismerteti:

IComInterface virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
IComInterface2 virtuális függvénytábla pont Metódus neve
0 IUnknown::QueryInterface
0 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
5 IComInterface2::Method3

Mint látható, ezek a táblák megfelelnek a C++ példának, így ezek a felületek megfelelően fognak működni.

Lásd még