none
idlファイル文法について RRS feed

  • 質問

  • いつもお世話になっております。

    VS2015UD3で作業しています。

    idlファイルの文法についてよく分からず、下記ご教示いただけますでしょうか?
    宜しくお願いいたします。

    手元のidlファイルでは、
    [
    	uuid(...),
    	version(1.0),
    	helpstring("ABC 1.0 Type Library")
    ]
    library ABC
    {
    	importlib("stdole32.tlb");
    	importlib("stdole2.tlb");
    	importlib(STDOLE_TLB);
    	importlib(STDTYPE_TLB);
    	
    ...
    	enumとか
    ...
    	interfaceとか
    ...
    	coclassとか
    ...
    	
    }
    

    などとなっているのですが、coclassに対応するinterfaceがlibraryの括りの中にあったり外側にあったりしています。

    coclassもそうですが、interfaceやその他enumなど、libraryの括りには全て入れてもいいのでしょうか?
    それとも先に定義済みでないといけないなどはございますでしょうか?

    どうぞ宜しくお願いいたします。
    2016年11月28日 4:18

回答

  • >「理想は#include」

    .idl にも、ヘッダーファイルのように別のファイルをincludeする仕組みがあります。
    .h にクラスの定義とか書いてそれをあちこちで使いますよね?それと同じです。

    ・interface の定義位置

    結果的にidlの中で閉じている限り(定義が外部に波及しない)、library ブロックの中にあるか外にあるかはあまり影響はしません。

    どちらにあるからと言って、TLB や _i.h の内容が変わることもありません。

    なので、どちらに置くのがいいか?をことさら意識する必要はありません。

    前回のコメントは強いて分けるならというものです。

    >coclassも外側は可能だけど、定義なしで外部参照不可となり使えないものになるから、常に内側。という認識で宜しいでしょうか?

    coclass はCOMサーバーの外部からCOMオブジェクトを生成するための情報ですので、外部から見えなくてもいいけど必要ということはほとんどありません(例外的な対応として必要という程度と思っていいです)。

    なので、coclass は原則内側に定義するでいいと思います。外に定義する必要がある場合は外に定義してください。

    なんだかんだと 3ケタは余裕で coclass を作ってますがまだ外に定義する必要に迫られたことはありません。

    >そうすると、libraryバージョンのアップの観点からだと、通常やはりinterface/enumは外側に置き、coclassは内側にしておくのが無難ということになりますでしょうか?

    coclass を変えるようなバージョンアップをするのであれば。。。ですね。

    coclass は同じままでバージョンアップするのであれば、とくに意識しなくていいと思います。

    バージョンアップと言ってもいくつもパターンがありますし、共有するとかプロジェクトを分けるとかでも変わるので、一概には言えませんが。

    >ついでですが、アップ時の作業は、追加する関数などをinterfaceに追加し(idとかも追加)、libraryバージョン番号を上げて、全てのuuid変更せずという感じになりますでしょうか?
    (新規のinterface/enumの追加の際は、当然uuidなどは新設)

    一度公開したら interface は変更してはいけません。interfaceは一度公開したら、以後未来永劫バイナリ互換をとり続けなければなりません(enumはインターフェースではないのでこの限りではありません)。

    また、coclass もバイナリ互換をとる必要があるため、一度公開したcoclass から取得できるインターフェースは増えてもいいですが減ってはいけません。

    なので、メソッドを追加する場合は、新たに interface を派生し、そこで追加するか、新たに coclass を定義するかのいずれかになります。

    library のバージョンやuuidについては、特に規約はありませんが、TLBが変わるので、バージョンまたはuuidは変更となります。どちらを変えるか?については好みで決めていいと思います。

    なお、uuidを変える場合は、library "HogeHoge" の部分も変更することをお勧めします。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年11月30日 1:57
    2016年11月28日 10:05
  • importlib も含めて、library ブロックの外に定義出来た気がします(importlibは出来なかったかも。。。手元に手ごろなidlがなくて確認できてません)。

    定義が外にあるか中にあるかの違いは、

    ビルドされるTLBにその定義を含むか、含まなくてもよいかで分かれます。

    基本的に、TLBに含まれるものは、library ブロック内にある定義だけとなります。

    ただし、その定義を行うために必要なものがブロック外に定義されている場合は、その定義を持ち込みます(そうしないと定義がないため)。

    基準は何か?という点では

    1.複数のlibraryバージョンで同一の定義を使いたい(interface/enumなど)場合は外に置く(理想は#include)。

    2.特定のlibraryバージョンに固有のものは、library の内側に配置する(coclassはlibraryバージョンごとで固有なので内側)。

    の2つでいいと思います。ちなみに、coclass もlibraryブロックの外側に配置することは可能です。その場合、そのTLBには定義が含まれないため、外部参照はできません。

    一応。import, importlib で定義されているものは、参照されていても再定義しません(外部定義を参照する形で扱われる)。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年11月30日 1:57
    2016年11月28日 5:01
  • >書き方も同じで、interfaceやenumをそのまま移動した感じでしょうか?

    はい。

    #include "hoge.idl" のように取り込みたいところ(library ブロック内でも外でもOK)に記述すればそこに、hoge.idl の内容が展開されてからIDLのコンパイルが行われます。

    仕組みは C の #include と全く同じです。なので共有したい部分を切り出して別ファイルにするという格好です。

    似たものに import という構文もあります(こちらはSDKで提供されているもののみ参照でいいかと)。

    通常は、

    coclass Hoge
    {
      [default] interface IHoge;
      interface IHoge2;
      [default, source] dispinterface _IHogeEvents;
    };
    

    上記のように書くことが多いですが、複数定義して初手(CoCreateInstance のパラメータ)で指定してよいインターフェースを列挙することができます。

    ただし、coclass で直接取り出せる interface はどれを取り出してもほかのものが QueryInterface できる必要があるので(これもCOMの規約)、実体のオブジェクトは1種類(インターフェースを複数搭載するクラスインスタンスとして実装)です。

    >uuidを変える場合は、全く別の新しいlibraryという感覚でということですね。

    わかりやすい形としては、そのIDLで作成されるCOMサーバーが上書きアップデート(機能追加のみ、要するに旧バージョンから見てバイナリレベルで完全互換がとれる)なら、library のバージョンで対応が可能。

    それ以外(機能が変わる or 減る、全く別物など、バイナリレベルで互換性が維持できない部分がある)ならuuid は別物と思っておけばいいと思います。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年11月30日 1:57
    2016年11月29日 8:21

すべての返信

  • importlib も含めて、library ブロックの外に定義出来た気がします(importlibは出来なかったかも。。。手元に手ごろなidlがなくて確認できてません)。

    定義が外にあるか中にあるかの違いは、

    ビルドされるTLBにその定義を含むか、含まなくてもよいかで分かれます。

    基本的に、TLBに含まれるものは、library ブロック内にある定義だけとなります。

    ただし、その定義を行うために必要なものがブロック外に定義されている場合は、その定義を持ち込みます(そうしないと定義がないため)。

    基準は何か?という点では

    1.複数のlibraryバージョンで同一の定義を使いたい(interface/enumなど)場合は外に置く(理想は#include)。

    2.特定のlibraryバージョンに固有のものは、library の内側に配置する(coclassはlibraryバージョンごとで固有なので内側)。

    の2つでいいと思います。ちなみに、coclass もlibraryブロックの外側に配置することは可能です。その場合、そのTLBには定義が含まれないため、外部参照はできません。

    一応。import, importlib で定義されているものは、参照されていても再定義しません(外部定義を参照する形で扱われる)。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年11月30日 1:57
    2016年11月28日 5:01
  • とっちゃん 様

    早速のレスありがとうございました。
    すいません。いつもお世話になります。ありがとうございます。


    >1.複数のlibraryバージョンで同一の定義を使いたい(interface/enumなど)場合は外に置く(理想は#include)。

    「理想は#include」ということについてもよく分からなかったのですが、手元のidlファイルをよく見ますと、
    下記のようになっていました。これは次の2の件も含めて、冗長になりますでしょうか?それとも両方対応になりますでしょうか?

    interface IElmA;
    
    	[
    		object,
    		uuid(...),
    		dual,
    		helpstring("IElmB Interface"),
    		pointer_default(unique)
    	]
    	interface IElmB : IDispatch
    	{...}
    
    
    
    [
    	uuid(...),
    	version(1.0),
    	helpstring("ABC 1.0 Type Library")
    ]
    library ABC
    {
    ...
    	enumとか
    ...
    	
    	[
    		object,
    		uuid(...),
    		dual,
    		helpstring("IElmA Interface"),
    		pointer_default(unique)
    	]
    	interface IElmA : IDispatch
    	{...}
    	
    ...
    	
    	coclass IElmB
    	...
    	coclass IElmA
    	...
    	
    ...
    	
    }


    >2.特定のlibraryバージョンに固有のものは、library の内側に配置する(coclassはlibraryバージョンごとで固有なので内側)。

    coclassも外側は可能だけど、定義なしで外部参照不可となり使えないものになるから、常に内側。という認識で宜しいでしょうか?


    そうすると、libraryバージョンのアップの観点からだと、通常やはりinterface/enumは外側に置き、coclassは内側にしておくのが無難ということになりますでしょうか?


    ついでですが、アップ時の作業は、追加する関数などをinterfaceに追加し(idとかも追加)、libraryバージョン番号を上げて、全てのuuid変更せずという感じになりますでしょうか?
    (新規のinterface/enumの追加の際は、当然uuidなどは新設)

    次から次へと申し訳ございません。どうぞ宜しくお願いいたします。



    • 編集済み SHIN109 2016年11月28日 7:05
    2016年11月28日 7:04
  • >「理想は#include」

    .idl にも、ヘッダーファイルのように別のファイルをincludeする仕組みがあります。
    .h にクラスの定義とか書いてそれをあちこちで使いますよね?それと同じです。

    ・interface の定義位置

    結果的にidlの中で閉じている限り(定義が外部に波及しない)、library ブロックの中にあるか外にあるかはあまり影響はしません。

    どちらにあるからと言って、TLB や _i.h の内容が変わることもありません。

    なので、どちらに置くのがいいか?をことさら意識する必要はありません。

    前回のコメントは強いて分けるならというものです。

    >coclassも外側は可能だけど、定義なしで外部参照不可となり使えないものになるから、常に内側。という認識で宜しいでしょうか?

    coclass はCOMサーバーの外部からCOMオブジェクトを生成するための情報ですので、外部から見えなくてもいいけど必要ということはほとんどありません(例外的な対応として必要という程度と思っていいです)。

    なので、coclass は原則内側に定義するでいいと思います。外に定義する必要がある場合は外に定義してください。

    なんだかんだと 3ケタは余裕で coclass を作ってますがまだ外に定義する必要に迫られたことはありません。

    >そうすると、libraryバージョンのアップの観点からだと、通常やはりinterface/enumは外側に置き、coclassは内側にしておくのが無難ということになりますでしょうか?

    coclass を変えるようなバージョンアップをするのであれば。。。ですね。

    coclass は同じままでバージョンアップするのであれば、とくに意識しなくていいと思います。

    バージョンアップと言ってもいくつもパターンがありますし、共有するとかプロジェクトを分けるとかでも変わるので、一概には言えませんが。

    >ついでですが、アップ時の作業は、追加する関数などをinterfaceに追加し(idとかも追加)、libraryバージョン番号を上げて、全てのuuid変更せずという感じになりますでしょうか?
    (新規のinterface/enumの追加の際は、当然uuidなどは新設)

    一度公開したら interface は変更してはいけません。interfaceは一度公開したら、以後未来永劫バイナリ互換をとり続けなければなりません(enumはインターフェースではないのでこの限りではありません)。

    また、coclass もバイナリ互換をとる必要があるため、一度公開したcoclass から取得できるインターフェースは増えてもいいですが減ってはいけません。

    なので、メソッドを追加する場合は、新たに interface を派生し、そこで追加するか、新たに coclass を定義するかのいずれかになります。

    library のバージョンやuuidについては、特に規約はありませんが、TLBが変わるので、バージョンまたはuuidは変更となります。どちらを変えるか?については好みで決めていいと思います。

    なお、uuidを変える場合は、library "HogeHoge" の部分も変更することをお勧めします。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年11月30日 1:57
    2016年11月28日 10:05
  • とっちゃん 様

    レスありがとうございました。
    詳細にありがとうございます。


    >.idl にも、ヘッダーファイルのように別のファイルをincludeする仕組みがあります。
    >.h にクラスの定義とか書いてそれをあちこちで使いますよね?それと同じです。

    知りませんでした。ありがとうございます。
    書き方も同じで、interfaceやenumをそのまま移動した感じでしょうか?


    >なんだかんだと 3ケタは余裕で coclass を作ってますがまだ外に定義する必要に迫られたことはありません。

    なんと3ケタ!!!すごい量ですね。それほど外側には必要ないということですね。


    >一度公開したcoclass から取得できるインターフェースは増えてもいいですが減ってはいけません。

    coclassには複数のインターフェイスの紐付けが出来るのでしょうか?
    一対だと思っていました。


    >TLBが変わるので、バージョンまたはuuidは変更となります。どちらを変えるか?については好みで決めていいと思います。
    >なお、uuidを変える場合は、library "HogeHoge" の部分も変更することをお勧めします。

    uuidを変える場合は、全く別の新しいlibraryという感覚でということですね。


    どうぞ宜しくお願いいたします。
    2016年11月29日 7:36
  • >書き方も同じで、interfaceやenumをそのまま移動した感じでしょうか?

    はい。

    #include "hoge.idl" のように取り込みたいところ(library ブロック内でも外でもOK)に記述すればそこに、hoge.idl の内容が展開されてからIDLのコンパイルが行われます。

    仕組みは C の #include と全く同じです。なので共有したい部分を切り出して別ファイルにするという格好です。

    似たものに import という構文もあります(こちらはSDKで提供されているもののみ参照でいいかと)。

    通常は、

    coclass Hoge
    {
      [default] interface IHoge;
      interface IHoge2;
      [default, source] dispinterface _IHogeEvents;
    };
    

    上記のように書くことが多いですが、複数定義して初手(CoCreateInstance のパラメータ)で指定してよいインターフェースを列挙することができます。

    ただし、coclass で直接取り出せる interface はどれを取り出してもほかのものが QueryInterface できる必要があるので(これもCOMの規約)、実体のオブジェクトは1種類(インターフェースを複数搭載するクラスインスタンスとして実装)です。

    >uuidを変える場合は、全く別の新しいlibraryという感覚でということですね。

    わかりやすい形としては、そのIDLで作成されるCOMサーバーが上書きアップデート(機能追加のみ、要するに旧バージョンから見てバイナリレベルで完全互換がとれる)なら、library のバージョンで対応が可能。

    それ以外(機能が変わる or 減る、全く別物など、バイナリレベルで互換性が維持できない部分がある)ならuuid は別物と思っておけばいいと思います。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年11月30日 1:57
    2016年11月29日 8:21
  • とっちゃん 様

    レスありがとうございました。

    いつも細やかにご教示いただき、ありがとうございました。
    不明点だけでなく、知識もより深くさせていただくことが出来、すっきり解決しました。ありがとうございました。

    「回答としてマーク」は、全部ですね。
    ありがとうございました。
    2016年11月30日 1:57