Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Exponovat typy .NET pro COM
Pokud máte v úmyslu zveřejnit typy v sestavení aplikacím COM, zvažte požadavky COM interoperability již při návrhu. Spravované typy (třída, rozhraní, struktura a výčty) se bezproblémově integrují s typy modelu COM, pokud dodržujete následující pokyny:
Třídy by měly implementovat rozhraní explicitně.
Přestože interoperabilita modelu COM poskytuje mechanismus pro automatické generování rozhraní obsahujícího všechny členy třídy a členů její základní třídy, je mnohem lepší poskytovat explicitní rozhraní. Automaticky generované rozhraní se nazývá rozhraní třídy. Pokyny najdete v tématu Úvod do rozhraní třídy.
Pomocí jazyka Visual Basic, C# a C++ můžete do kódu začlenit definice rozhraní, a nemusíte tak používat jazyk IDL (Interface Definition Language) nebo jeho ekvivalent. Podrobnosti o syntaxi najdete v dokumentaci k jazyku.
Spravované typy musí být veřejné.
Pouze veřejné typy v sestavení jsou registrovány a exportovány do knihovny typů. V důsledku toho jsou pro COM viditelné pouze veřejné typy.
Spravované typy zveřejňují funkce pro jiný spravovaný kód, který nemusí být vystaven modelu COM. Například parametrizované konstruktory, statické metody a konstantní pole nejsou vystaveny klientům modelu COM. Kromě toho, protože modul runtime zařazuje data z jednoho typu do druhého, mohou být data zkopírovaná nebo transformovaná.
Metody, vlastnosti, pole a události musí být veřejné.
Členové veřejných typů musí být také veřejní, pokud mají být viditelné v COM. Viditelnost sestavení, veřejného typu nebo veřejných členů veřejného typu můžete omezit použitím objektu ComVisibleAttribute. Ve výchozím nastavení jsou viditelné všechny veřejné typy a členy.
Typy musí mít veřejný konstruktor bez parametrů, aby mohly být aktivovány z COM.
Spravované, veřejné typy jsou viditelné pro COM. Bez veřejného konstruktoru bez parametrů (konstruktor bez argumentů) však klienti modelu COM nemohou typ vytvořit. Klienti modelu COM můžou typ dál používat, pokud je aktivovaný jiným způsobem.
Typy nemohou být abstraktní.
Klienti modelu COM ani klienti .NET nemohou vytvářet abstraktní typy.
Při exportu do modelu COM je dědičná hierarchie spravovaného typu zploštěna. Správa verzí se také liší mezi spravovanými a nespravovanými prostředími. Typy vystavené modelu COM nemají stejné charakteristiky správy verzí jako jiné spravované typy.
Používání typů COM z .NET
Pokud máte v úmyslu využívat typy COM z .NET a nechcete používat nástroje jako Tlbimp.exe (Import knihovny typů), musíte postupovat podle těchto pokynů:
- Rozhraní musí mít aplikované ComImportAttribute.
- Rozhraní musí mít GuidAttribute aplikováno s ID rozhraní COM.
- Rozhraní by mělo mít InterfaceTypeAttribute k určení základního typu tohoto rozhraní (
IUnknown,IDispatchneboIInspectable).- Výchozí možností je mít základní typ
IDispatcha připojit deklarované metody k očekávané virtuální tabulce funkcí pro rozhraní. - Pouze rozhraní .NET Framework podporuje zadávání základního
IInspectabletypu .
- Výchozí možností je mít základní typ
Tyto pokyny poskytují minimální požadavky pro běžné scénáře. Existuje mnoho dalších možností přizpůsobení a jsou popsány v části Použití atributů vzájemné spolupráce.
Definování rozhraní COM v .NET
Když se kód .NET pokusí volat metodu objektu COM prostřednictvím rozhraní s ComImportAttribute atributem, musí vytvořit virtuální tabulku funkcí (označovanou také jako vtable nebo vftable), aby vytvořila definici rozhraní .NET, aby bylo možné určit nativní kód, který se má volat. Tento proces je složitý. Následující příklady ukazují některé jednoduché případy.
Zvažte rozhraní COM s několika metodami:
struct IComInterface : public IUnknown
{
STDMETHOD(Method)() = 0;
STDMETHOD(Method2)() = 0;
};
Pro toto rozhraní popisuje následující tabulka rozložení tabulky virtuálních funkcí:
IComInterface slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
Každá metoda se přidá do tabulky virtuálních funkcí v pořadí, v jakém byla deklarována. Konkrétní pořadí je definováno kompilátorem jazyka C++, ale v jednodušších případech bez přetížení určuje pořadí deklarací pořadí v tabulce.
Deklarujte rozhraní .NET, které odpovídá tomuto rozhraní následujícím způsobem:
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid(/* The IID for IComInterface */)]
interface IComInterface
{
void Method();
void Method2();
}
Určuje InterfaceTypeAttribute základní rozhraní. Nabízí několik možností:
| hodnota ComInterfaceType | Základní typ rozhraní | Chování členů v atributovaném rozhraní |
|---|---|---|
InterfaceIsIUnknown |
IUnknown |
Tabulka virtuálních funkcí má nejprve členy IUnknown, pak členy tohoto rozhraní v pořadí deklarace. |
InterfaceIsIDispatch |
IDispatch |
Členy nejsou přidány do tabulky virtuálních funkcí. Jsou přístupné jenom prostřednictvím IDispatch. |
InterfaceIsDual |
IDispatch |
Tabulka virtuálních funkcí má nejprve členy IDispatch, pak členy tohoto rozhraní v pořadí deklarace. |
InterfaceIsIInspectable |
IInspectable |
Tabulka virtuálních funkcí má nejprve členy IInspectable, pak členy tohoto rozhraní v pořadí deklarace. Podporováno pouze v rozhraní .NET Framework. |
Dědičnost rozhraní COM a .NET
Systém komunikace s objekty COM, který využívá ComImportAttribute, nepracuje s dědičností rozhraní, takže může způsobit neočekávané chování, pokud nejsou přijaty některé zmírňující kroky.
Zdrojový generátor modelu COM, který používá System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute atribut, komunikuje s dědičností rozhraní, takže se chová podle očekávání.
Dědičnost rozhraní COM v C++
V jazyce C++ můžou vývojáři deklarovat rozhraní MODELU COM, která jsou odvozena z jiných rozhraní modelu COM, následujícím způsobem:
struct IComInterface : public IUnknown
{
STDMETHOD(Method)() = 0;
STDMETHOD(Method2)() = 0;
};
struct IComInterface2 : public IComInterface
{
STDMETHOD(Method3)() = 0;
};
Tento styl deklarace se pravidelně používá jako mechanismus pro přidání metod do objektů MODELU COM beze změny stávajících rozhraní, což by byla zásadní změna. Výsledkem tohoto mechanismu dědičnosti jsou následující rozložení tabulky virtuálních funkcí:
IComInterface slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
IComInterface2 slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
| 5 | IComInterface2::Method3 |
V důsledku toho je snadné volat metodu definovanou IComInterface z objektu IComInterface2*. Konkrétně volání metody na základní rozhraní nevyžaduje volání na QueryInterface, aby se získal ukazatel na základní rozhraní. Kromě toho C++ umožňuje implicitní převod z IComInterface2*IComInterface*, který je dobře definovaný a umožňuje vyhnout se volání QueryInterface znovu. V důsledku toho v jazyce C nebo C++ nemusíte volat QueryInterface , abyste se dostali k základnímu typu, pokud nechcete, což může umožnit určitá vylepšení výkonu.
Poznámka:
Rozhraní WinRT nedodržují tento model dědičnosti. Jsou definované tak, aby sledovaly stejný model jako [ComImport]model komunikace modelu COM v .NET.
Dědičnost rozhraní s využitím ComImportAttribute
V .NET C# kód, který vypadá jako dědičnost rozhraní, ve skutečnosti není dědičnost rozhraní. Vezměte v úvahu následující kód:
interface I
{
void Method1();
}
interface J : I
{
void Method2();
}
Tento kód neříká, "J implements I." Kód ve skutečnosti říká, že "jakýkoli typ, který implementuje J, musí také implementovat I." Tento rozdíl vede k základnímu návrhovému rozhodnutí, které činí dědičnost rozhraní ve vzájemné spolupráci založené na ComImportAttribute neergonomickou. Rozhraní jsou vždy považována za vlastní; Základní seznam rozhraní rozhraní nemá žádný vliv na žádné výpočty k určení tabulky virtuálních funkcí pro dané rozhraní .NET.
V důsledku toho přirozený ekvivalent předchozího příkladu rozhraní modelu COM jazyka C++ vede k jinému rozložení tabulky virtuálních funkcí.
Kód jazyka C#:
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
void Method();
void Method2();
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
void Method3();
}
Rozložení tabulky virtuálních funkcí:
IComInterface slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
IComInterface2 slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface2::Method3 |
Vzhledem k tomu, že se tyto tabulky virtuálních funkcí liší od příkladu jazyka C++, to povede k vážným problémům za běhu. Správná definice těchto rozhraní v .NET s ComImportAttribute je následující:
[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();
}
Na úrovni metadat neimplementuje, IComInterface2 ale pouze určuje, že implementátory IComInterface musí také implementovat IComInterface2.IComInterface Proto musí být každá metoda ze základních typů rozhraní předefinována.
Dědičnost rozhraní s GeneratedComInterfaceAttribute (.NET 8 a novějších verzích)
Generátor zdroje COM aktivovaný GeneratedComInterfaceAttribute implementuje dědičnost rozhraní C# jako dědičnost rozhraní COM, takže virtuální tabulky funkcí jsou rozloženy podle očekávání. Pokud vezmete předchozí příklad, správná definice těchto rozhraní v .NET s System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute je následující:
[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
void Method();
void Method2();
}
[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
void Method3();
}
Metody základních rozhraní nemusí být předefinovány a neměly by být předefinovány. Následující tabulka popisuje výsledné virtuální tabulky funkcí:
IComInterface slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
IComInterface2 slot virtuální tabulky funkcí |
Název metody |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
| 5 | IComInterface2::Method3 |
Jak vidíte, tyto tabulky odpovídají příkladu jazyka C++, takže tato rozhraní budou fungovat správně.