COM Aranabilir Sarmalayıcısı

COM istemcisi bir .NET nesnesini çağırdığında, ortak dil çalışma zamanı yönetilen nesneyi ve nesne için COM çağrılabilen sarmalayıcıyı (CCW) oluşturur. Bir .NET nesnesine doğrudan başvuru yapılamıyor, COM istemcileri yönetilen nesne için ara sunucu olarak CCW'yi kullanır.

Çalışma zamanı, hizmetlerini isteyen COM istemcilerinin sayısından bağımsız olarak yönetilen bir nesne için tam olarak bir CCW oluşturur. Aşağıdaki çizimde gösterildiği gibi, birden çok COM istemcisi INew arabirimini kullanıma sunan CCW'ye bir başvuru tutabilir. CCW ise arabirimi uygulayan ve atık olarak toplanan yönetilen nesneye tek bir başvuru tutar. Hem COM hem de .NET istemcileri aynı yönetilen nesne üzerinde aynı anda istekte bulunabilir.

Multiple COM clients holding a reference to the CCW that exposes INew.

COM çağrılabilen sarmalayıcılar .NET çalışma zamanı içinde çalışan diğer sınıflar için görünmez. Birincil amaçları, yönetilen ve yönetilmeyen kod arasında çağrıları sıralamaktır; ancak CCW'ler, kaydırdıkları yönetilen nesnelerin nesne kimliğini ve nesne ömrünü de yönetir.

Nesne Kimliği

Çalışma zamanı, .NET nesnesi için atık olarak toplanan yığınından bellek ayırır ve bu da çalışma zamanının nesneyi bellekte gerektiği gibi taşımasını sağlar. Buna karşılık, çalışma zamanı CCW için belleği toplamamış bir yığından ayırarak COM istemcilerinin sarmalayıcıya doğrudan başvurmasını mümkün hale getirir.

Nesne Ömrü

Sarmalandığı .NET istemcisinin aksine CCW, geleneksel COM biçiminde başvuru olarak sayılır. CCW'de başvuru sayısı sıfıra ulaştığında, sarmalayıcı yönetilen nesnede başvurusunu serbest bırakır. Bir sonraki çöp toplama döngüsü sırasında, kalan başvuruları olmayan bir yönetilen nesne toplanır.

COM arabirimlerini simulating

CCW, com'un arabirim tabanlı etkileşimi zorlamasıyla tutarlı bir şekilde tüm genel, COM görünür arabirimlerini, veri türlerini ve dönüş değerlerini COM istemcilerine sunar. BIR COM istemcisi için, .NET nesnesindeki yöntemleri çağırma, BIR COM nesnesindeki yöntemleri çağırmayla aynıdır.

CCW, bu sorunsuz yaklaşımı oluşturmak için IUnknown ve IDispatch gibi geleneksel COM arabirimleri üretir. Aşağıdaki çizimde gösterildiği gibi CCW, sarmalayan .NET nesnesinde tek bir başvuru tutar. Hem COM istemcisi hem de .NET nesnesi, CCW'nin proxy ve saplama yapısı aracılığıyla birbirleriyle etkileşim kurar.

Diagram that shows how CCW manufactures COM interfaces.

.NET çalışma zamanı, yönetilen ortamda bir sınıf tarafından açıkça uygulanan arabirimleri ortaya çıkarmanın yanı sıra, nesnesi adına aşağıdaki tabloda listelenen COM arabirimlerinin uygulamalarını sağlar. Bir .NET sınıfı, bu arabirimlerin kendi uygulamasını sağlayarak varsayılan davranışı geçersiz kılabilir. Ancak, çalışma zamanı her zaman IUnknown ve IDispatch arabirimleri için uygulamayı sağlar.

Arabirim Açıklama
Idispatch Geç bağlamanın türüne yönelik bir mekanizma sağlar.
Ierrorınfo Hatanın metinsel açıklamasını, kaynağını, Yardım dosyasını, Yardım bağlamını ve hatayı tanımlayan arabirimin GUID'sini sağlar (.NET sınıfları için her zaman GUID_NULL ).
IProvideClassInfo COM istemcilerinin yönetilen bir sınıf tarafından uygulanan ITypeInfo arabirimine erişim kazanmasını sağlar. COM'dan içeri aktarılmayan türler için .NET Core'da döndürür COR_E_NOTSUPPORTED .
Isupporterrorınfo Yönetilen nesnenin IErrorInfo arabirimini destekleyip desteklemediğini saptamak için BIR COM istemcisi etkinleştirir. Öyleyse, istemcinin en son özel durum nesnesine yönelik bir işaretçi almasını sağlar. Tüm yönetilen türler IErrorInfo arabirimini destekler.
ITypeInfo (yalnızca.NET Framework) Tlbexp.exe tarafından üretilen tür bilgileriyle tam olarak aynı olan bir sınıf için tür bilgileri sağlar.
IUnknown COM istemcisinin CCW'nin ömrünü yönettiği ve tür zorlaması sağladığı IUnknown arabiriminin standart uygulamasını sağlar.

Yönetilen sınıf, aşağıdaki tabloda açıklanan COM arabirimlerini de sağlayabilir.

Arabirim Açıklama
(_classname) sınıf arabirimi Çalışma zamanı tarafından kullanıma sunulan ve açıkça tanımlanmayan, yönetilen bir nesnede açıkça kullanıma sunulan tüm genel arabirimleri, yöntemleri, özellikleri ve alanları kullanıma sunan arabirim.
I Bağlan ionPoint ve I Bağlan ionPointContainer Temsilci tabanlı olayları (olay abonelerini kaydetmeye yönelik bir arabirim) kaynak oluşturan nesneler için arabirim.
IDispatchEx (yalnızca.NET Framework) Sınıf IExpando uygularsa çalışma zamanı tarafından sağlanan arabirim. IDispatchEx arabirimi, IDispatch'ın aksine üyelerin numaralandırmasını, toplamasını, silinmesini ve büyük/küçük harfe duyarlı çağrısını etkinleştiren IDispatch arabiriminin bir uzantısıdır.
Ienumvarıant Sınıf IEnumerable uygularsa koleksiyondaki nesneleri numaralandıran koleksiyon türü sınıfları arabirimi.

Sınıf arabirimine giriş

Yönetilen kodda açıkça tanımlanmayan sınıf arabirimi, .NET nesnesinde açıkça kullanıma sunulan tüm genel yöntemleri, özellikleri, alanları ve olayları kullanıma sunan bir arabirimdir. Bu arabirim çift veya yalnızca dağıtım arabirimi olabilir. Sınıf arabirimi, önünde bir alt çizgi bulunan .NET sınıfının adını alır. Örneğin Memeliler sınıfı için sınıf arabirimi _Mammal.

Türetilmiş sınıflar için, sınıf arabirimi temel sınıfın tüm genel yöntemlerini, özelliklerini ve alanlarını da kullanıma sunar. Türetilmiş sınıf, her temel sınıf için bir sınıf arabirimi de sunar. Örneğin, Memeliler sınıfı, System.Object'i genişleten MammalSuperclass sınıfını genişletiyorsa, .NET nesnesi COM istemcilerine _Mammal, _MammalSuperclass ve _Object adlı üç sınıf arabirimini kullanıma sunar.

Örneğin, aşağıdaki .NET sınıfını göz önünde bulundurun:

' 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() {}
}

COM istemcisi adlı _Mammalbir sınıf arabirimine işaretçi alabilir. .NET Framework'te, arabirim tanımını içeren _Mammal bir tür kitaplığı oluşturmak için Tür Kitaplığı Verme (Tlbexp.exe) aracını kullanabilirsiniz. Tür Kitaplığı Verme .NET Core'da desteklenmez. Sınıfı bir Mammal veya daha fazla arabirim uyguladıysa, arabirimler ortak sınıfın altında görünür.

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

Sınıf arabirimini oluşturmak isteğe bağlıdır. Varsayılan olarak, COM birlikte çalışma, bir tür kitaplığına dışarı aktardığınız her sınıf için yalnızca dağıtım arabirimi oluşturur. sınıfınıza uygulayarak bu arabirimin otomatik olarak oluşturulmasını ClassInterfaceAttribute engelleyebilir veya değiştirebilirsiniz. Sınıf arabirimi, yönetilen sınıfları COM'a gösterme görevini kolaylaştırsa da, kullanımları sınırlıdır.

Dikkat

Kendi sınıfınızı açıkça tanımlamak yerine sınıf arabirimini kullanmak, yönetilen sınıfınızın gelecekteki sürümünü karmaşık hale getirebilir. Sınıf arabirimini kullanmadan önce lütfen aşağıdaki yönergeleri okuyun.

Sınıf arabirimini oluşturmak yerine COM istemcilerinin kullanması için açık bir arabirim tanımlayın.

COM birlikte çalışma otomatik olarak bir sınıf arabirimi oluşturduğundan, sınıfınızdaki sürüm sonrası değişiklikler ortak dil çalışma zamanı tarafından kullanıma sunulan sınıf arabiriminin düzenini değiştirebilir. COM istemcileri genellikle bir arabirimin düzenindeki değişiklikleri işlemek için hazır olmadığından, sınıfın üye düzenini değiştirirseniz bozulırlar.

Bu kılavuz, COM istemcilerine sunulan arabirimlerin değiştirilemez kalması gerektiğiyle ilgili bir ilkeyi güçlendirir. Arabirim düzenini yanlışlıkla yeniden sıralayarak COM istemcilerini bozma riskini azaltmak için, arabirimleri açıkça tanımlayarak sınıfındaki tüm değişiklikleri arabirim düzeninden yalıtın.

Aşağıdaki kod parçasında gösterildiği gibi sınıf arabiriminin otomatik neslini devre dışı bırakma ve sınıf için açık bir arabirim uygulama için ClassInterfaceAttribute kullanın:

<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; }
}

ClassInterfaceType.None değeri, sınıf meta verileri bir tür kitaplığına aktarıldığında sınıf arabiriminin oluşturulmasını engeller. Yukarıdaki örnekte, COM istemcileri sınıfa LoanApp yalnızca arabirim üzerinden IExplicit erişebilir.

Gönderme tanımlayıcılarını önbelleğe almaktan kaçının (DispId'ler)

Sınıf arabirimini kullanmak betikli istemciler, Microsoft Visual Basic 6.0 istemcileri veya arabirim üyelerinin DispId'lerini önbelleğe almayan geç bağlanan istemciler için kabul edilebilir bir seçenektir. DispId'ler, geç bağlamayı etkinleştirmek için arabirim üyelerini tanımlar.

Sınıf arabirimi için DispId'lerin oluşturulması, üyenin arabirimdeki konumunu temel alır. Üyenin sırasını değiştirir ve sınıfı bir tür kitaplığına aktarırsanız, sınıf arabiriminde oluşturulan DispId'leri değiştirirsiniz.

Sınıf arabirimini kullanırken geç bağlanan COM istemcilerinin kırılmasını önlemek için ClassInterfaceType.AutoDispatch değeriyle ClassInterfaceAttribute'u uygulayın. Bu değer yalnızca dağıtım sınıfı arabirimini uygular, ancak tür kitaplığından arabirim açıklamasını atlar. Arabirim açıklaması olmadan istemciler derleme zamanında DispId'leri önbelleğe alamaz. Bu, sınıf arabirimi için varsayılan arabirim türü olsa da, öznitelik değerini açıkça uygulayabilirsiniz.

<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; }
}

Çalışma zamanında bir arabirim üyesinin DispId değerini almak için COM istemcileri IDispatch.GetIdsOfNames'i çağırabilir. Arabirimde bir yöntemi çağırmak için döndürülen DispId değerini IDispatch.Invoke bağımsız değişkeni olarak geçirin.

Sınıf arabirimi için çift arabirim seçeneğini kullanarak kısıtlayın.

Çift arabirimler, COM istemcileri tarafından arabirim üyelerine erken ve geç bağlamayı etkinleştirir. Tasarım zamanında ve test sırasında sınıf arabirimini ikili olarak ayarlamayı yararlı bulabilirsiniz. Hiçbir zaman değiştirilmeyecek yönetilen bir sınıf (ve temel sınıfları) için bu seçenek de kabul edilebilir. Diğer tüm durumlarda sınıf arabirimini ikili olarak ayarlamaktan kaçının.

Otomatik olarak oluşturulan çift arabirim nadir durumlarda uygun olabilir; ancak daha sık sürümle ilgili karmaşıklık oluşturur. Örneğin, türetilmiş bir sınıfın sınıf arabirimini kullanan COM istemcileri, temel sınıfta yapılan değişikliklerle kolayca kesilebilir. Bir üçüncü taraf temel sınıfı sağladığında, sınıf arabiriminin düzeni denetiminizin dışındadır. Ayrıca, yalnızca dağıtım arabiriminden farklı olarak, çift arabirim (ClassInterfaceType.AutoDual), dışarı aktarılan tür kitaplığındaki sınıf arabiriminin açıklamasını sağlar. Böyle bir açıklama, geç bağlanan istemcilerin derleme zamanında DispId'leri önbelleğe almalarını teşvik eder.

Tüm COM olay bildirimlerinin geç bağlı olduğundan emin olun.

Varsayılan olarak, COM türü bilgileri doğrudan yönetilen derlemelere eklenir ve bu da birincil birlikte çalışma derlemeleri (PIA) gereksinimini ortadan kaldırır. Ancak, ekli tür bilgilerinin sınırlamalarından biri, COM olay bildirimlerinin erken bağlanan vtable çağrıları tarafından teslimini desteklememesi, ancak yalnızca geç bağlı IDispatch::Invoke çağrıları desteklemesidir.

Uygulamanız COM olay arabirimi yöntemlerine erken bağlanan çağrılar gerektiriyorsa, Visual Studio'daki Birlikte Çalışma Türlerini Ekle özelliğini olarak trueayarlayabilir veya proje dosyanıza aşağıdaki öğeyi ekleyebilirsiniz:

<EmbedInteropTypes>True</EmbedInteropTypes>

Ayrıca bkz.