5

私はIDispatchインターフェースの実装に直面しています。4つの方法があり、幸い3つは簡単です。

function TIEEventsSink.GetTypeInfoCount(...): HResult;
{
   Result := E_NOTIMPL;
}

function TIEEventsSink.GetTypeInfo(...): HResult;
{
   Result := E_NOTIMPL;
}

function TIEEventsSink.GetIDsOfNames(...): HResult;
{
   Result := E_NOTIMPL;
}

それが最後の方法です、Invokeそれは難しいです。ここで、実際にDispIDをケースに入れて、適切なメソッドを呼び出す必要があります。バリアント配列からのパラメーターのマーシャリング解除。

function Invoke(  
  dispIdMember: DISPID;
  riid: REFIID;
  lcid: LCID;
  wFlags: WORD;
  var pDispParams: DISPPARAMS;
  var pVarResult: VARIANT;
  var pExcepInfo: EXCEPINFO;
  var puArgErr: DWORD
): HRESULT;

面倒な定型コードをすべて書く必要はなく、バグがあると確信しているので、作業を行うのではなく、グーグルで調べました。

私はこのスニペットをMSDNドキュメントでIDispatch.Invoke見つけました:

通常、 Invokeを直接実装しないでください。

素晴らしい!とにかくそれを実装したくありませんでした!続きを読む:

代わりに、ディスパッチインターフェイスを使用して、関数CreateStdDispatchおよびDispInvokeを作成します。詳細については、CreateStdDispatchDispInvokeIDispatchインターフェイスの作成、およびActiveXオブジェクトの公開を参照してください。

IDispatchインターフェイスの作成リンクには次のように記載されています。

IDispatchは、次のいずれかの方法で実装できます。

  • [をちょきちょきと切る]
  • CreateStdDispatch関数を呼び出します。このアプローチは最も単純ですが、豊富なエラー処理や複数の国語を提供していません。
  • [をちょきちょきと切る]

すばらしい、CreateStdDispatchは次のとおりです。

単一の関数呼び出しを介してIDispatchインターフェースの標準実装を作成します。これにより、自動化によるオブジェクトの公開が簡単になります。

HRESULT CreateStdDispatch(  
  IUnknown FAR*  punkOuter,        
  void FAR*  pvThis,               
  ITypeInfo FAR*  ptinfo,          
  IUnknown FAR* FAR* ppunkStdDisp  
);

私はそれを次のように呼ぶつもりでした:

CreateStdDispatch(
    myUnk,          //Pointer to the object's IUnknown implementation.
    anotherObject,  //Pointer to the object to expose.
    nil             //Pointer to the type information that describes the exposed object (i has no type info)
    dispInterface   //the IUnknown of the object that implements IDispatch for me
);

私が理解できないのは、Windows APIの実装がCreateStdDispatch、オブジェクトで呼び出すメソッドをどのように知っているかです。特に、CreateStdDispatch使用しているオブジェクト指向言語やその呼び出し規約がわからないためです。

どうやっCreateStdDispatchて知るのか

  • 特定のメソッドを呼び出す方法は何dispidですか?
  • 私の言語の呼び出し規約?
  • オブジェクト指向オブジェクトが書かれている言語からの例外を処理する方法は?

:私はdispinterface;を実装する以外に選択肢はありません。私はインターフェースを定義しませんでした。私はそれが単純な早期の限界IUnknownであったことを望みます、しかしそれはそうではありません。

4

2 に答える 2

5

ITypeInfoに渡されたパラメーターはCreateStdDispatch、すべてのメソッド情報を公開 しませんか?

したがって、最初に呼び出して型情報を作成CreateDispTypeInfoし、それを渡すと、型情報を使用して、このすべての情報を含む必要があるCreateStdDispatchため、どのメソッドを呼び出すかを決定できます。CreateDispTypeInfoINTERFACEDATA

調べる時間がないので、私はかなり間違っている可能性がありますが、それは私には理にかなっています。これについては後で調査し、回答を更新します。

于 2011-06-28T16:43:50.203 に答える
1

あなたの質問に対する簡単な答えは次のとおりです。それが作成CreateStdDispatch()する実装も、呼び出されるメソッドについても何もIDispatch知りません。

返されるオブジェクトは、渡したパラメーターを格納するだけCreateStdDispatch()であり、すべてのIDispatchメソッドについて、オブジェクトは向きを変えて、指定したに対応する呼び出しを行うだけITypeInfoです。以上です。

ptinfoコードに示されているようにnilを渡すと、が得られるだけです。これは、実装オブジェクトは、すべての作業を委任するE_INVALIDARG対象がないと何もできないためです。ITypeInfo

oleaut32.dllのコードを調べると、メソッドを直接呼び出すのではなく、(そのDLLにも存在する)のCStdDispようなAPI関数を呼び出すことがわかりますが、これらの関数はすべて、メソッドを呼び出すための単純なラッパーであり、さらなる機能。DispInvoke()ITypeInfoITypeInfo

誰かが不思議に思う場合:追加の魔法CreateStdDispatch()CStdDisp実行もしません。彼らがすることは、あなたが渡したIDispatchものが何でもITypeInfoできることをあなたに与えることだけです。ITypeInfoをソケットに差し込むことができる一種のアダプターと考えてくださいIDispatch

TAutoIntfObject.Create()タイプライブラリが必要なのは事実です。ただし、コンストラクターが行うのはGetTypeInfoOfGuid()、型情報ポインターを取得するためにコンストラクターを呼び出すことだけです。このポインターに対して、オブジェクトは、ディスパッチに関連するほとんどの作業を委任します。

Borlandは、その知恵で型情報ポインターのメンバー変数を作成しましたprivate。つまり、単に別のコンストラクターを記述したり、仮想関数をオーバーライドしたりするのではなく、問題のインターフェイスを含む型ライブラリーなどをコンストラクターに渡す必要があります。一方、レジストリを介してタイプライブラリをロードしたり、その一部をTLBファイルにダンプしたりするのはそれほど難しくありません。OleViewを使用してTLBを検査すると、実際にコンパイル可能なIDLが得られます。これは、多くの場合、Borlandでコンパイル可能なRIDLでもあります。

CreateStdDispatch()例外についても何も知りません。COMメソッドからスローされた例外のキャッチとHRESULTへの変換、および/または実装メソッドIErrorInfoのDelphiのキーワードによって引き起こされるコンパイラの魔法です。safecall

インターフェイス宣言でsafecallとして指定されたCOMメソッドを呼び出すときの、HRESULTの例外への変換についても同じことが言えます。コンパイラ@CheckAutoResultは、safecallメソッドを呼び出すたびにへの呼び出しを挿入するだけです。この関数はHRESULTをチェックし、必要に応じてスローしEOleSysErrorます。

Delphiデバッガーを逆アセンブル(「CPUビュー」)に切り替えるだけで、コンパイラーが行うすべての魔法を調べることができます。

于 2021-04-21T19:04:39.030 に答える