2

実装とインターフェイス定義がマネージコードに存在するが、ネイティブコンポーネントによって駆動されるCOMコンポーネントがあります。管理対象コンポーネントはSafeArray、次のメソッド宣言を介してネイティブコードに戻ります。

interface IExample {
  <return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UNKNOWN)>
  object[] DoSomeOperation()
}

生成されたネイティブ署名は、これを。として適切に返しますSafeArray

コードレビュー中に、SafeArrayGetElementを使用した結果の配列の呼び出しに関するいくつかの質問がありました。IUnknown問題は、SafeArrayGetElementがAddRefされたインスタンスを返すかどうかです。基本的に、次のうちどれが正しいかを要約します。

例1:

CComPtr<IUnknown> spUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&spUnk));

例2:

IUnknown* pUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&pUnk));

このテーマに関するドキュメントは非常に薄いです。次の行のみが含まれます。

データ要素が文字列、オブジェクト、またはバリアントの場合、関数は要素を正しい方法でコピーします。

正しいの定義は少しあいまいです。

4

2 に答える 2

2

最初の方法は正しくなければならず、COM全体でのオブジェクトの処理と一致しているはずです。おそらく、あなたが見つけた定義は、消費者が正しい方法を知っていることを前提としています。

言及された他のアイテムはそれを必要とします。VARIANTまたはSAFEARRAYをコピーすると、オブジェクトが含まれている場合、暗黙のAddRef()が実行されます。ただし、VT_BYREFが存在する場合、VARIANTはそれを必要としません。

VariantCopy @ MSDN
SafeArrayCopy @ MSDN

この動作は、COMでパラメーターを処理するルールの一部であるため、SAFEARRAYまたはVARIANTに固有のものではありません。ただし、誰かがルールを回避しようとするのを妨げるものは何もありません。

入力パラメーターについては、さらに使用するためにインターフェースポインターを保持するつもりがない限り、AddRef()に対する呼び出し先の責任はありません。ただし、他のパラメータ使用の場合はそれが必要です。

たとえば、VARIANTまたは他のコンテナに配置されたインターフェイスには、少なくとも1つのAddRef()呼び出しを適用する必要があります。そうしないと、データ/参照の転送が一方向であるため、COMメソッドからの出力パラメータとしてVARIANTを使用するときに問題が発生します。元のオブジェクトは、呼び出しが宛先に到着するまでに期限切れになる可能性があります。同様に、インターフェイスをストリームにマーシャリングするには、AddRef()も必要です。

同様に、参照による呼び出しには、少なくとも1つのAddRef呼び出しも必要です。そうでない場合、参照されたオブジェクトがまだ生きていることが保証された状態で、適切な長時間の呼び出し(たとえば、DCOMを介した)が宛先に到達しない可能性があります。ただし、呼び出し元のスコープ内またはその前に作成されたため、オブジェクトはすでに1+になっているはずなので、追加のAddRef()/ Release()呼び出しはここでは頻繁にスキップされます。

コンポーネントを変更することが可能で、呼び出しが進行中の場合は、代わりにGITを使用することが望ましい場合があります。これにより、代わりにトークンを渡すことができ、COMアパートメント間でインターフェイスをマーシャリングするのが簡単になります。関係するオブジェクトの存続期間は、呼び出しの期間を通じて呼び出し元の責任になり、オブジェクトをマーシャリングできなかったケースをトラップできるようになります。

グローバルインターフェイステーブルの作成@MSDN

また、BSTRの脚注も興味深いものです。

BSTR参照パラメーターを受け取る関数の実装が、パラメーターに新しいBSTRを割り当てる場合、以前に参照されたBSTRを解放する必要があります。

文字列操作関数(COM)

于 2009-10-22T20:32:31.550 に答える