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, sınıfın tüm üyelerini ve temel sınıfının üyelerini içeren bir arabirimi otomatik olarak oluşturmak için bir mekanizma 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 ortak türler kaydedilir ve tür kitaplığına dışarı aktarılır. Sonuç olarak, COM'da yalnızca genel türler görünür.
Yönetilen türler, COM'a sunulmamış olabilecek diğer yönetilen kodlarda özellikleri kullanıma 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çinde ve dışında sıraladıkça, 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. uygulamasını uygulayarak ComVisibleAttributebir derlemenin, genel türün veya ortak türün genel üyelerinin görünürlüğünü 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:
- Arabirimlerin uygulanmış olması gerekir ComImportAttribute .
- Arabirimler, COM arabirimi için GuidAttribute Arabirim Kimliği ile uygulanmış olmalıdır.
- Arabirimler, bu arabirimin InterfaceTypeAttribute (
IUnknown
,IDispatch
veyaIInspectable
) 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
IInspectable
destekler.
- Varsayılan seçenek, temel türüne
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ğer | Temel arabirim türü | Öznitelikli arabirimdeki üyeler için davranış |
---|---|---|
InterfaceIsIUnknown |
IUnknown |
Sanal işlev tablosunda önce üyeleri IUnknown , ardından bildirim sırasına göre bu arabirimin üyeleri bulunur. |
InterfaceIsIDispatch |
IDispatch |
Üyeler sanal işlev tablosuna eklenmez. Bunlara yalnızca üzerinden IDispatch erişilebilir. |
InterfaceIsDual |
IDispatch |
Sanal işlev tablosunda önce üyeleri IDispatch , ardından bildirim sırasına göre bu arabirimin üyeleri bulunur. |
InterfaceIsIInspectable |
IInspectable |
Sanal işlev tablosunda önce üyeleri IInspectable , ardından bildirim sırasına göre bu arabirimin üyeleri bulunur. Yalnızca .NET Framework'te desteklenir. |
COM arabirimi devralma ve .NET
kullanan ComImportAttribute COM birlikte çalışma sistemi arabirim devralma ile etkileşim kurmaz, bu nedenle bazı hafifletici adımlar atılmadığı sürece beklenmeyen davranışlara neden olabilir.
ö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;
};
Bu bildirim stili, mevcut arabirimleri değiştirmeden COM nesnelerine yöntem eklemek için düzenli olarak bir mekanizma olarak kullanılır ve bu da hataya neden olur. 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, üzerinde tanımlanan IComInterface
bir yönteminden IComInterface2*
çağırmak kolaydır. Özellikle, temel arabirimde bir yöntemi çağırmak, temel arabirime QueryInterface
bir işaretçi almak için bir çağrı gerektirmez. Buna ek olarak, C++ ile IComInterface2*
arasında örtük bir dönüştürmeye IComInterface*
izin verir ve iyi tanımlanmıştır ve yeniden QueryInterface
ç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 aramanız QueryInterface
gerekmez; bu da bazı performans iyileştirmelerine izin verebilir.
Not
WinRT arabirimleri bu devralma modelini izlemez. .NET'teki tabanlı COM birlikte çalışma modeliyle [ComImport]
aynı modeli izlemek için tanımlanı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 "uygulayan J
her tür de uygulamalıdır I
" diyor. Bu fark, tabanlı birlikte çalışmada ComImportAttributearabirim devralmayı çapraz 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 uygulamaz IComInterface2
IComInterface
, ancak yalnızca uygulayıcılarının IComInterface2
da uygulaması IComInterface
gerektiğini belirtir. Bu nedenle, temel arabirim türlerinden her yöntemin yeniden yüklenmesi gerekir.
(.NET 8 ve üzeri) ile GeneratedComInterfaceAttribute
arabirim devralma
tarafından GeneratedComInterfaceAttribute
tetiklenen COM kaynak oluşturucu, C# arabirimi devralmayı COM arabirimi devralma 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 yüklenmesi gerekmez ve yeniden işlenmemelidir. 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.