Aracılığıyla paylaş


COM birlikte çalışma için .NET türlerini niteleme

.NET türlerini COM'da kullanıma sunma

Bir derlemedeki türleri COM uygulamalarına kullanıma sunma amacınız varsa, tasarım zamanında COM birlikte çalışma gereksinimlerini göz önünde bulundurun. Yönetilen türler (sınıf, arabirim, yapı ve numaralandırma) aşağıdaki yönergelere uyduğunda COM türleriyle sorunsuz bir şekilde tümleşir:

  • Sınıflar arabirimleri açıkça uygulamalıdır.

    COM birlikte çalışma, bir sınıfın ve onun temel sınıfının tüm üyelerini içeren bir arabirimi otomatik olarak oluşturma mekanizması sağlasa da, açık arabirimler sağlamak çok daha iyidir. Otomatik olarak oluşturulan arabirim, sınıf arabirimi olarak adlandırılır. Yönergeler için bkz. Sınıf arabirimine giriş.

    Arabirim Tanım Dili (IDL) veya eşdeğerini kullanmak yerine, arabirim tanımlarını kodunuzla birleştirmek için Visual Basic, C# ve C++ kullanabilirsiniz. Söz dizimi ayrıntıları için dil belgelerinize bakın.

  • Yönetilen türler genel olmalıdır.

    Yalnızca bir derlemedeki genel türler kaydedilip tür kitaplığına aktarılır. Sonuç olarak, COM'da yalnızca genel türler görünür.

    Yönetilen türler, COM'a sunulmayan diğer yönetilen kodlara özellikler sunar. Örneğin, parametreli oluşturucular, statik yöntemler ve sabit alanlar COM istemcilerine sunulmaz. Ayrıca, çalışma zamanı verileri bir türün içine ve dışına yönlendirdikçe, veriler kopyalanabilir veya dönüştürülebilir.

  • Yöntemler, özellikler, alanlar ve olaylar genel olmalıdır.

    Ortak türlerin üyeleri de COM'a görünür olacaksa genel olmalıdır. Bir derlemenin, genel türün veya genel türün genel üyelerinin görünürlüğünü ComVisibleAttribute uygulayarak kısıtlayabilirsiniz. Varsayılan olarak, tüm genel türler ve üyeler görünür.

  • Türlerin COM'dan etkinleştirilmesi için genel parametresiz bir oluşturucuya sahip olması gerekir.

    Yönetilen, ortak türler COM tarafından görülebilir. Ancak, ortak parametresiz oluşturucu (bağımsız değişkeni olmayan bir oluşturucu) olmadan COM istemcileri türü oluşturamaz. COM istemcileri, başka bir yolla etkinleştirilirse türü kullanmaya devam edebilir.

  • Türler soyut olamaz.

    Ne COM istemcileri ne de .NET istemcileri soyut türler oluşturamazlar.

COM'a aktarıldığında, yönetilen bir türün devralma hiyerarşisi düzleştirilmiştir. Sürüm oluşturma, yönetilen ve yönetilmeyen ortamlar arasında da farklılık gösterir. COM'a sunulan türler, diğer yönetilen türlerle aynı sürüm oluşturma özelliklerine sahip değildir.

.NET'ten COM türlerini kullanma

.NET'ten COM türlerini kullanmayı planlıyorsanız ve Tlbimp.exe (Tür Kitaplığı İçeri Aktarıcısı) gibi araçları kullanmak istemiyorsanız, şu yönergeleri izlemeniz gerekir:

  • Arayüzlere ComImportAttribute uygulanmış olması gerekir.
  • Arabirimlere, COM arabirimi için Arabirim Kimliği GuidAttribute uygulanmalıdır.
  • Arabirimler, bu arabirimin InterfaceTypeAttribute (IUnknown, IDispatchveya IInspectable) temel arabirim türünü belirtmek için uygulanmış olmalıdır.
    • Varsayılan seçenek, temel türüne IDispatch sahip olmak ve bildirilen yöntemleri arabirim için beklenen sanal işlev tablosuna eklemektir.
    • Yalnızca .NET Framework, temel türü belirtmeyi IInspectabledestekler.

Bu yönergeler, yaygın senaryolar için en düşük gereksinimleri sağlar. Daha birçok özelleştirme seçeneği vardır ve Birlikte Çalışma Özniteliklerini Uygulama bölümünde açıklanmıştır.

.NET'te COM arabirimlerini tanımlama

.NET kodu, özniteliğine sahip ComImportAttribute bir arabirim aracılığıyla COM nesnesinde bir yöntemi çağırmaya çalıştığında, çağrılacak yerel kodu belirlemek için arabirimin .NET tanımını oluşturmak için bir sanal işlev tablosu (vtable veya vftable olarak da bilinir) oluşturması gerekir. Bu işlem karmaşıktır. Aşağıdaki örneklerde bazı basit durumlar gösterilmektedir.

Birkaç yöntemi olan bir COM arabirimini göz önünde bulundurun:

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

Bu arabirim için aşağıdaki tabloda sanal işlev tablosu düzeni açıklanmaktadır:

IComInterface sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2

Her yöntem sanal işlev tablosuna bildirildiği sırayla eklenir. Belirli bir sıra C++ derleyicisi tarafından tanımlanır, ancak aşırı yükleme içermeyen basit durumlar için bildirim sırası tablodaki sırayı tanımlar.

Bu arabirime karşılık gelen bir .NET arabirimini aşağıdaki gibi bildirin:

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

InterfaceTypeAttribute temel arabirimini belirtir. Birkaç seçenek sunar:

ComInterfaceType Değeri Temel arabirim türü Öznitelikli arabirimdeki üyeler için davranış
InterfaceIsIUnknown IUnknown Sanal işlev tablosu önce IUnknown'ün üyelerini, ardından bildirim sırasında bu arabirimin üyelerini içerir.
InterfaceIsIDispatch IDispatch Üyeler sanal işlev tablosuna eklenmez. Bunlara yalnızca üzerinden IDispatcherişilebilir.
InterfaceIsDual IDispatch Sanal işlev tablosu önce IDispatch'ün üyelerini, ardından bildirim sırasında bu arabirimin üyelerini içerir.
InterfaceIsIInspectable IInspectable Sanal işlev tablosu önce IInspectable'ün üyelerini, ardından bildirim sırasında bu arabirimin üyelerini içerir. Yalnızca .NET Framework'te desteklenir.

COM arabirimi devralma ve .NET

COM birlikte çalışma sistemi ComImportAttribute kullandığında arabirim kalıtımı ile etkileşime girmez. Bu nedenle, bazı önleyici adımlar atılmadığı takdirde beklenmeyen davranışlara yol açabilir.

özniteliğini System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute kullanan COM kaynak oluşturucu, arabirim devralma ile etkileşime girer, bu nedenle beklendiği gibi daha fazla davranır.

C++ dilinde COM arabirimi devralma

C++ dilinde geliştiriciler, diğer COM arabirimlerinden türetilen COM arabirimlerini aşağıdaki gibi bildirebilir:

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

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

Mevcut arabirimlerde yıkıcı değişiklikler yapmadan COM nesnelerine yöntem eklemek için bu bildirim stiline düzenli olarak başvurulur. Bu devralma mekanizması aşağıdaki sanal işlev tablosu düzenlerine neden olur:

IComInterface sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
IComInterface2 sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
5 IComInterface2::Method3

Sonuç olarak, IComInterface üzerinde tanımlanan bir yöntemi IComInterface2* içinden çağırmak kolaydır. Özellikle, temel arayüzde bir yöntemi çağırmak, temel arayüze bir işaretçi almak için QueryInterface'e bir çağrı yapmayı gerektirmez. Buna ek olarak, C++, IComInterface2*'dan IComInterface*'e örtük bir dönüşüme izin verir, bu da iyi tanımlanmıştır ve QueryInterface'yi yeniden çağırmaktan kaçınmanıza olanak tanır. Sonuç olarak, C veya C++'da, istemiyorsanız temel türe ulaşmak için hiçbir zaman QueryInterface çağırmanız gerekmez; bu da bazı performans iyileştirmelerine izin verebilir.

Uyarı

WinRT arabirimleri bu devralma modelini izlemez. .NET'teki [ComImport]-tabanlı COM birlikte çalışma modeliyle aynı modeli izlemek üzere tanımlanmışlardır.

ile arabirim devralma ComImportAttribute

.NET'te, arabirim devralma gibi görünen C# kodu aslında arabirim devralma değildir. Aşağıdaki kodu inceleyin:

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

Bu kod "J uygular I" demiyor. Kod aslında "J'yi uygulayan her türün aynı zamanda I'yi de uygulaması gerektiğini" belirtiyor. Bu fark, ComImportAttribute tabanlı birlikte çalışmada arabirim devralmayı işlevsel olmayan hale getiren temel tasarım kararına yol açar. Arabirimler her zaman kendi başına kabul edilir; bir arabirimin temel arabirim listesi, belirli bir .NET arabirimi için sanal işlev tablosunu belirlemeye yönelik hesaplamaları etkilemez.

Sonuç olarak, önceki C++ COM arabirimi örneğinin doğal eşdeğeri farklı bir sanal işlev tablosu düzenine yol açar.

C# kodu:

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

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

Sanal işlev tablosu düzenleri:

IComInterface sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
IComInterface2 sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface2::Method3

Bu sanal işlev tabloları C++ örneğinden farklı olduğundan çalışma zamanında ciddi sorunlara yol açar. ile ComImportAttribute .NET'te bu arabirimlerin doğru tanımı aşağıdaki gibidir:

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

Meta veri düzeyinde, IComInterface2IComInterface'i uygulamaz, ancak yalnızca IComInterface2 uygulayıcılarının aynı zamanda IComInterface'i de uygulaması gerektiğini belirtir. Bu nedenle, temel arabirim türlerinden her yöntemin yeniden ilan edilmesi gerekir.

(.NET 8 ve üzeri) ile GeneratedComInterfaceAttribute arabirim devralma

GeneratedComInterfaceAttribute tarafından tetiklenen COM kaynak oluşturucu, C# arabirimi devralımını COM arabirimi devralımı olarak uygular, böylece sanal işlev tabloları beklendiği gibi düzenlenir. Önceki örneği ele alırsanız, ile System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute .NET'te bu arabirimlerin doğru tanımı aşağıdaki gibidir:

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

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

Temel arabirimlerin yöntemlerinin yeniden deklare edilmesi gerekmez ve edilmemelidir. Aşağıdaki tabloda, sonuçta elde edilen sanal işlev tabloları açıklanmaktadır:

IComInterface sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
IComInterface2 sanal işlev tablosu yuvası Yöntem adı
0 IUnknown::QueryInterface
1 IUnknown::AddRef
2 IUnknown::Release
3 IComInterface::Method
4 IComInterface::Method2
5 IComInterface2::Method3

Gördüğünüz gibi, bu tablolar C++ örneğiyle eşleşeceğinden, bu arabirimler düzgün çalışır.

Ayrıca bakınız