2009-11-22 57 views
11

私は、LPSAFEARRAY* outパラメータを介してSafeArrayを返すCOM関数を持っています。 この関数は、ATLのCComSafeArrayテンプレートクラスを使用してSafeArrayを作成します。 私の単純な実装は、出力パラメータにローカル変数の所有権を移動するためにCComSafeArray<T>::Detach()を使用する:ローカルCComSafeArrayをLPSAFEARRAY出力パラメータに戻すにはどうすればよいですか?

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

問題はCComSafeArray::Detach()Unlock動作を行うことになるようにするときのSafeArray(メインのsaこの中の新しい所有者case)が破損した場合、ロックはゼロではなく、DestroyE_UNEXPECTEDでSafeArrayのロックを解除できません(SafeArrayが割り当て解除されていないため、メモリリークが発生します)。

COMメソッド境界を通じてCComSafeArrayに所有権を転送する正しい方法は何ですか?


編集:単一の回答からは、これまでのところ、エラーがサーバ側(foo)からクライアント側(main)とではない上にあるようですが、私はそれは難しいことCComSafeArray wasn信じることを見つけますこの単純なユースケースのために設計されたものでは、SafeメソッドをCOMメソッドから取り出してCComSafeArrayにするエレガントな方法が必要です。

+0

使用しているVisual Studioのバージョンはどれですか? –

+0

これはVS8(2005)とVS9(2008)の両方で発生します – Motti

+2

私の経験に基づいて、CComSafeArrayを設計した人は決してそれを実際に使用したことはありません。必要に応じて独自のラッパークラスを使用できます。 – Amnon

答えて

10

問題は、受信CComSafeArrayの内部ポインタを直接設定することです。 はCComSafeArrayに既存のSAFEARRAYを添付するAttach()メソッドを使用します。

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

確かに、これは 'CComSafeArray'が使用される方法ではなく、' CComVariant'と 'CComBSTR'のグレインに反します。 – Motti

+0

コードで見たように、CComSafeArrayはSAFEARRAYがロックされることを期待しています。何らかの方法でそれをロックする必要があります。 – Amnon

+0

ロック機能を持たないアタッチのような機能はなく、ロックを解除しないデタッチのような機能もありません。そのため、呼び出し元または呼び出し先側で作業が行われなければなりません。 –

1

私は、このようなユースケースを許可する意図はどこになかったことを推測すると思います。おそらくそれは、私は信じていCComVariant & CComPtr :)

を書いた同じ開発者がなかったことを主な目標としてCComSafeArrayの作者とみなさ値のセマンティクス。アタッチ/デタッチは単に「ボーナス」機能である可能性があります。

+1

そして、このような理由でも、私はまだ 'CComSafeArray'のデフォルトのctorと' GetSafeArrayPtr'が設計の欠陥/回避策であると感じています... – Andrey

5

マークされた回答が正しいことを確認するだけです。 RAIIラッパーはCOM境界を越えて動作することはできません。

投稿されたメソッドの実装が正しくないため、発信者が有効なSAFEARRAYを提供すると想定できません。 [アウト]はオートメーションの有効な属性ではありません。[out、retval]または[in、out]のいずれかである必要があります。 [out、retval]であれば、メソッドは最初から新しい配列を作成する必要があります。それが[in、out]の場合、渡された配列が期待した配列型と一致せず、新しい型を作成しなければ、メソッドは渡された配列を破棄する必要があります。

関連する問題