11

LPSAFEARRAY*outパラメータを介してSafeArrayを返すCOM関数があります。CComSafeArrayこの関数は、ATLのテンプレートクラスを使用して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の新しい所有者(この場合はmain)が破棄されたときに、ロックがゼロではなく、SafeArrayのロック解除に失敗するように操作をCComSafeArray::Detach()実行することです(SafeArrayがないため、メモリリークが発生します)。割り当て解除)。UnlocksaDestroyE_UNEXPECTED

COMメソッドの境界を介してCComSafeArrays間で所有権を譲渡する正しい方法は何ですか?


編集:これまでの単一の回答から、エラーはmainサーバー側()ではなくクライアント側()にあるようですが、この些細なユースケース向けに設計されたものではないfooとは信じがたいです。 CComSafeArraySafeArrayをCOMメソッドからに取得するためのエレガントな方法になりますCComSafeArray

4

3 に答える 3

11

問題は、受信側CComSafeArrayの内部ポインタを直接設定することです。メソッドを使用して、既存のものを:Attach()にアタッチします。SAFEARRAYCComSafeArray

LPSAFEARRAY ar;
foo(&ar);
CComSafeArray<VARIANT> sa;
sa.Attach(ar);
于 2009-11-22T12:21:11.743 に答える
5

マークされた答えが正しいものであることを確認するためだけに。RAIIラッパーはCOMの境界を越えて機能することはできません。

投稿されたメソッドの実装は正しくありません。呼び出し元が有効なSAFEARRAYを提供しようとしていると想定することはできません。[out]は自動化の有効な属性ではなく、[out、retval]または[in、out]のいずれかである必要があります。[out、retval]のように見える場合、メソッドは新しい配列を最初から作成する必要があります。[in、out]の場合、メソッドは、渡された配列が予期された配列タイプと一致しない場合は破棄し、新しい配列タイプを作成する必要があります。

于 2013-08-06T03:35:21.130 に答える
1

そのようなユースケースを許可する意図はどこになかったと思います。おそらくそれは書いたのと同じ開発者ではなかったCComVariantCComPtr:)

CComSafeArrayの作者は価値のセマンティクスを主要な目標と考えていたと思います。アタッチ/デタッチは、単に「ボーナス」機能である可能性があります。

于 2010-08-04T22:43:40.883 に答える