2


0

SafeArrayGetElementを使用してVT_UNKNOWNのSafeArrayに正しくアクセスする

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

interface IExample {

  object[] DoSomeOperation()
}

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

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

例1

CComPtr spUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast(&spUnk));

例2

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

この件に関する文書は非常に薄いです。 次の行だけが含まれています。

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

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

2 Answer


2


最初の方法は正しくなければならず、COM全体のオブジェクトの処理に沿ったものになるでしょう。おそらく、あなたが見つけた定義は、消費者が正しい方法を知っていると仮定しているのでしょう。

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

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

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

たとえば、VARIANTまたは他のコンテナに配置されたインターフェイスには少なくとも1つのAddRef()呼び出しを適用する必要があります。 元のオブジェクトは、コールが宛先に到着するまでに期限切れになる可能性があります。 同様に、インターフェースをStreamにマーシャリングするには、AddRef()も必要です。

同様に、参照による呼び出しにも少なくとも1つのAddRef呼び出しが必要です。 そうでない場合は、参照されているオブジェクトがまだ生きていることを保証して、適切な長期実行コール(DCOMなどを介して)が宛先に到着しないことがあります。 ただし、余分なAddRef()/ Release()呼び出しは、呼び出しスコープ内またはその前に作成されているため、オブジェクトはすでに1になっているはずなので、ここでは頻繁にスキップされます。

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

http://msdn.microsoft.com/ja-jp/library/ms693781%28VS.85%29.aspx [グローバルインターフェイステーブルの作成@ MSDN]

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

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


1


それはAddRef:edであるべきです、しかし私はそれが事実であるという直接の情報を持っていません(例えば。 私はそのソースを読んでいません。

ドキュメントはかなり明確だと思います。インタフェースポインタを「正しく」コピーするのはAddRefingです。

本当に確認したい場合は、 `+ IUnknown `を実装する超シンプルなATL COMオブジェクトを構築し、それらの多くを ` SAFEARRAY `に詰めて、ブレークポイントを ` CComObjectBase <>

InternalAddRef `(if私の記憶が役立ちます)。 次に、 ` SafeArrayGetElement +`の呼び出しをデバッグし、ブレークポイントにヒットするかどうかを確認します。