2009-11-22 17 views
11

LPSAFEARRAY* çıkış parametresi üzerinden bir SafeArray döndürmesi gereken bir COM işlevim var. Bu işlev, ATL'nin CComSafeArray şablon sınıfını kullanarak SafeArray öğesini oluşturur. Benim saf uygulama çıkış parametresine yerel değişkenden sahipliğini taşımak amacıyla CComSafeArray<T>::Detach() kullanır:Yerel bir CComSafeArray bir LPSAFEARRAY çıkış parametresine nasıl geri döner?

void foo(LPSAFEARRAY* psa) 
{ 
    CComSafeArray<VARIANT> ret; 
    ret.Add(CComVariant(42)); 
    *psa = ret.Detach(); 
} 

int main() 
{ 
    CComSafeArray<VARIANT> sa; 
    foo(sa.GetSafeArrayPtr()); 

    std::cout << sa[0].lVal << std::endl; 
} 

sorun CComSafeArray::Detach() bir Unlock operasyonu gerçekleştirir, böylece zaman SafeArray (ana en sa bu yeni sahibi case) yok kilit sıfır değildir ve GüvenliArray kilidini açmak için başarısız olur E_UNEXPECTED (Bu SafeArray ayrılmış olduğundan bir bellek sızıntısına yol açar).

Bir COM yöntemi sınırı aracılığıyla sahipliğini CComSafeArrays arasında aktarmanın doğru yolu nedir?


Düzenleme: Tek bir cevap itibaren şimdiye kadar hata sunucu tarafında (foo) istemci tarafında (main) ve üzerinde olduğu görülmektedir, ama zor olduğunu CComSafeArray degildim inanmak bulmak Bu önemsiz kullanım durumu için tasarlanmamıştır, bir SafeArray'i bir COM yönteminden CComSafeArray içine almak için şık bir yol olmalıdır.

+0

Hangi Visual Studio sürümünü kullanıyorsunuz? –

+0

Bu, hem VS8 (2005) hem de VS9 (2008) – Motti

+2

için geçerlidir. Deneyimlerime dayanarak, CComSafeArray'i tasarlayan kimsenin aslında hiç kullanmadığını düşünüyorum. İsterseniz kendi sarmalayıcı sınıfınızı kullanabilirsiniz. – Amnon

cevap

10

Sorun şu ki, alıcı CComSafeArray iç işaretçisini doğrudan ayarlamanızdır. bir CComSafeArray için varolan SAFEARRAY takmak için Attach() yöntemi kullanın:

LPSAFEARRAY ar; 
foo(&ar); 
CComSafeArray<VARIANT> sa; 
sa.Attach(ar); 
+0

Şüphesiz bu, CComSafeArray'ın kullanılmasının gerektiği anlamına gelmez, "CComVariant" ve "CComBSTR" öğelerinin hububatına karşı gider. – Motti

+0

Kodda gördüğünüz gibi, CComSafeArray SAFEARRAY'ın kilitlenmesini bekler. Bir şekilde ya da diğerini kilitlemelisin. – Amnon

+0

Ve Unlock benzeri olmayan kilitli ve benzeri olmayan hiçbir işleve sahip değildir. Bu nedenle, iş arayanlar veya callees tarafında yapılmalıdır. –

1

Ben tahmin ediyorum böyle bir kullanım durumunda izin için hiçbir niyet nerede. Muhtemelen İnanıyorum CComVariant & CComPtr :)

yazdığı aynı geliştirici olmadığını başlıca hedefleri arasına CComSafeArray 'ın yazarı düşünülen değer semantik; Attach/Detach basitçe "bonus" bir özellik olabilir.

+1

Ve hatta bu sebeple, hala 'CComSafeArray'ın varsayılan ctor'u ve' GetSafeArrayPtr 'tasarım kusurları/çözümleri gibi hissediyorum. – Andrey

5

Sadece işaretli cevabın doğru olduğunu onaylayın. RAII paketleyicileri COM sınırlarında çalışamaz.

Gönderilen yöntem uygulaması doğru değil, arayanın geçerli bir SAFEARRAY sağlayacağını varsayamazsınız. Sadece [out] Otomasyonda geçerli bir özellik değil, [out, retval] veya [in, out] olmalıdır. Göründüğü gibi olan [out, retval] ise, yöntem sıfırdan yeni bir dizi oluşturmalıdır. Eğer [in, out] ise, yöntem beklenen dizi türüyle uyuşmuyorsa ve yeni bir tane oluşturuyorsa, geçirilen diziyi yok etmelidir.