どのようにしてLPSAFEARRAY出力パラメータにローカルCComSafeArrayを返すのですか?
質問
私は、パラメータアウトLPSAFEARRAY*
経由のSafeArrayを返すべきCOM機能を持っています。
関数は、ATLのCComSafeArray
テンプレートクラスを使用してのSafeArrayを作成します。
私の素朴な実装の用途は、出力パラメータにローカル変数から所有権を移動するためにCComSafeArray<T>::Detach()
ます:
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;
}
の問題は、のSafeArray(この場合のメインCComSafeArray::Detach()
)の新しい所有者が破壊されたときにロックがゼロでないとUnlock
はA(このリードsa
とのSafeArrayのロックを解除することができないようにそのDestroy
が実行E_UNEXPECTED
動作でありますSafeArrayので、メモリリーク)が割り当てを解除されていない。
はCOMメソッドの境界を通してCComSafeArraysの間の転送の所有権への正しい方法は何ですか?
<時間>の編集の単一の答えはこれまでのところ、エラーがクライアント側(main
)といないサーバ側から(foo
)上にあるようですが、私はそのCComSafeArray
を信じるのは難しいそれを見つけることから、この些細なユースケースのために設計されていなかったが、CComSafeArray
にCOMメソッドの外のSafeArrayを取得するためのエレガントな方法が存在しなければならない。
解決
問題は、あなたが直接受信CComSafeArray
の内部ポインタを設定することです。
Attach()
に既存のSAFEARRAY
を添付するCComSafeArray
メソッドを使用します:
LPSAFEARRAY ar;
foo(&ar);
CComSafeArray<VARIANT> sa;
sa.Attach(ar);
他のヒント
ただ、マークの答えが正しいものであることを確認します。 RAIIラッパーできないCOMの境界を越えて仕事ます。
ポストされたメソッドの実装が正しくない、あなたは、呼び出し元が有効なSAFEARRAYを供給しようとしていることを前提とすることはできません。ただ、[実行]オートメーションにおける有効な属性ではありません、それは[retvalのアウト]または[アウト、中]のいずれかでなければなりません。それは次のようになります[アウト、RETVAL]、である場合、この方法は、最初から新しい配列を作成する必要があります。それは[アウト、中]であれば、それは予想される配列型と一致して、新しいものを作成しない場合、メソッドは、渡された配列破壊する必要があります。
私は、このようなユースケースを許可する意図はどこになかったことを推測すると思います。おそらくそれはCComVariant
&CComPtr
:)
私は、大きな目標として、そのCComSafeArray
の作者とみなさ値のセマンティクスを信じています。アタッチ/デタッチは、単に「ボーナス」機能かもしれません。