instance method WIN32OLE#ole_query_interface

ole_query_interface(iid) -> WIN32OLE[permalink][rdoc]

IID(インターフェイスID)を指定してオブジェクトの別のインターフェイスを持つオブジェクトを取得します。

オブジェクトが複数のオートメーション用インターフェイスを持つ場合に、当メソッドを利用して既定のインターフェイスとは異なるインターフェイスを取得します。

[PARAM] iid:
取得するインターフェイスのIIDを文字列で指定します。
[RETURN]
iidパラメータで指定したインターフェイスを持つWIN32OLEオブジェクト
[EXCEPTION] WIN32OLERuntimeError:
指定したIIDをオブジェクトが持たない場合に通知されます。
ie = WIN32OLE.new('InternetExplorer.Application')
ie_web_app = ie.ole_query_interface('{0002DF05-0000-0000-C000-000000000046}')

上例のie_web_appは、ieと同じインスタンスとなります。

COMの仕様では1つのインターフェイスについて同じIID問い合わせに対しては常に同一のインターフェイスを返すことが決められています。

このため、正しく実装されたOLEオートメーションサーバでは本メソッドが意味を持つことはありません。というのは、2つ以上の異なるWIN32OLEで操作可能なインターフェイスを持つということは、IID_IDispatch(OLEオートメーションのインターフェイスID)を指定した問い合わせに対して異なるインターフェイスを返すということになるからです。これは、結果的に呼び出し側プログラムがいつでも間違えたインターフェイスを呼び出す可能性を持つということを意味します。当然、それはサーバ実装のバグです。

問題は、C++のvtblアクセスや.NET FrameworkのCOM Interopのために静的型情報が必要となることです。このため、一度あるインターフェイスを返すことに決めた場合、実際に返すインターフェイスが元のインターフェイスを継承していたとしても、ドキュメント上は異なるインターフェイスとして定義しなければ追加のメソッドが呼び出せません。

たとえば、当メソッドの存在理由である http://www.ruby-forum.com/topic/109954(なお、元のパッチと異なりGUIDの統一フォーマットを利用するように改造されているため、IIDの前後に {}が必要です)には、Solutionオブジェクトに対してSolution2オブジェクトの取得を依頼するために、必要ということになっています。実際、Solutionプロパティが返すのは、この場合はSolutionインターフェイスを継承した Solution2インターフェイスです。しかし、Solutionプロパティの型情報は Solutionインターフェイスを返すことになっているため、静的に型を解決している場合は、追加のメソッドの呼び出しを記述できません。

しかし、WIN32OLEが利用するIDispatchインターフェイスは、メソッド名による動的なメソッド検索が行われます。このため、Solutionオブジェクト(しかしその実態はSolution2オブジェクト)に対してSolution2で追加されたメソッド(たとえばGetProjectTemplate)を指定したとしても正しく呼び出せます。つまり、http://www.ruby-forum.com/topic/109954で例示されているようなole_query_interfaceメソッドの呼び出しは不要です。

もし、当メソッドの呼び出しが本当に必要なのであれば、まず、該当するOLEオートメーションサーバの修正を依頼してください。その実装は正しくありません。

正しく実装されたオブジェクトに対して当メソッドを適用すると、結果として、同一オブジェクトの参照カウント値を無駄に増加させることになります。

なお、サポートしているインターフェイスのバージョンを調べたい場合に、以下のような方法で、インターフェイスのバージョンを調べることができます。

def check_solution_version(obj)
  [['{CDA7305C-78B6-4D9D-90AD-93EBE71F9341}', 4],
   ['{DF23915F-FDA3-4DD5-9CAA-2E1372C2BB16}', 3],
   ['{FA238614-FBB1-4314-A7F7-49AE8BB6C6BA}', 2]].each do |iid, ver|
    begin
      intf = obj.ole_query_interface(iid)
      intf.ole_free
      return ver
    rescue WIN32OLERuntimeError
    end
  end
  1
end

しかし、ole_query_interfaceのような特異なメソッドを利用するよりも、 WIN32OLE.new('VisualStudio.DTE.8.0') のように生成時にバージョン番号(この例では8.0)を指定するほうが良いスタイルです。

また、単に特定のメソッドをサポートしているかどうかを知りたいだけであれば、WIN32OLE#ole_respond_to?を利用したダックタイピングをしてください。