ATL による DirectMusic ツールの作成

Download sample code サンプル (DMTool.exe) をダウンロードする。

Peter Donnelly
Microsoft Digital Media Division

August 2001
日本語版最終更新日 2001 年 9 月 6 日

MSDN Code Center で DirectMusic ツールをダウンロードまたはブラウズする。

要約: このドキュメントでは、Active Template Library (ATL) を使って、Microsoft DirectMusic ツールグラフに挿入するコンポーネントを作成する方法について説明します。付属のサンプル コードには、プロパティ ページ付きの完全に動作するツールと、コンポーネントの使い方を示すクライアント アプリケーションが含まれています。

はじめに

本書では、Microsoft(R) DirectMusic(R) アプリケーションでパフォーマンス メッセージのカスタム処理を行うために、IDirectMusicTool インターフェイスを実装する COM コンポーネントの作成手順の概要を示します。

Microsoft Visual C++(R) で COM コンポーネントを作成するには、Microsoft Visual Studio(R) の Active Template Library (ATL) ウィザードを使用するのが最も簡単です。ATL はクラス ファクトリ、IUnknown メソッド、および自己登録メカニズムの実装を自動化するので、プログラマはコンポーネントの機能の作成に専念することができます。

残念ながら、DirectMusic はタイプ ライブラリを持っておらず、完全に COM に準拠しているわけではありません。このため、IDirectMusicTool をサポートするコンポーネントのための適切なタイプ ライブラリを作成するのがいくぶん難しくなっています。理論上は、IDirectMusicTool とその他の DirectMusic 宣言を、コンポーネントの IDL ファイルの中の INCLUDE または IMPORT 文を使って MIDL コンパイラに提供することが可能です。Dmplugin.h ヘッダー ファイルをインポートすれば、すべての DirectMusic 型宣言が使用可能になります。しかし現実には、これを試みると MIDL は多数のエラーを生成します。

この記事では、IDirectMusicTool をタイプ ライブラリを通して公開するという問題をあえて回避する方法を示します。その場合でも、ATL ウィザードを使ってコンポーネントを作成し、カスタム クラスにメソッドとプロパティを追加することができます。IDirectMusicTooll インターフェイスはタイプ ライブラリには現われませんが、クラスはこのインターフェイスをサポートします。

LyricsTool サンプルは、歌詞 (Lyrics) を取り出し、アプリケーションに提供するという機能を持っています。これは、メッセージをインターセプトし、新しいメッセージを作成する方法と、Microsoft DirectMusic Producer 内でコンポーネントを使用可能にする方法を示すことを目的とするきわめて単純なツールです。

この記事では以下のトピックを扱います。

  • ATL ウィザードによるコンポーネントの作成
    Visual Studio のウィザードを使って、DirectMusic ツールに組み込める COM コンポーネントの作成方法を説明します。
  • IDirectMusicTool インターフェイスの追加
    DirectMusic アプリケーションから利用できるインターフェイスの追加方法を示します。
  • IDirectMusicTool の実装
    インターフェイス上の個々のメソッドを実装し、ツールの機能を定義する方法を示します。
  • LyricsTool サンプル
    この文章に付属するサンプル コンポーネントについて説明します。
  • LyricsToolClient サンプル
    DirectMusic アプリケーションの中でツールを使用する方法を示しているサンプル クライアントについて説明します。
  • DirectMusic Producer へのツールのプラグイン
    コンポーネントを自己登録形式にし、DirectMusic Producer でオーディオパス作成時にツールを利用可能にするための追加のインターフェイスをサポートする方法について説明します。
  • ツールの配布
    ツールをアプリケーションから利用可能にするために配布しなくてはならないファイルについて説明します。
  • 関連情報

ATL ウィザードによるコンポーネントの作成

Microsoft Visual Studio のウィザードを使って、DirectMusic ツールに組み込める COM コンポーネントを作成することができます。次の手順は、コンポーネントの汎用フレームワークを作成します。その後、インターフェイスと実装を追加していくことになります。

単純なコンポーネントの作成

  1. Visual Studio の [ファイル] メニューの [新規作成] をクリックします。[新規作成] ダイアログ ボックスの [プロジェクト] タブをクリックします。リストボックスの [ATL COM AppWizard] を選択します。プロジェクト名を入力し、[OK] をクリックします。
  2. [ATL COM AppWizard] ダイアログ ボックスで、[ダイナミック リンク ライブラリ(DLL)] をクリックします。他のチェック ボックスは選択しないでください。[終了] をクリックします。[OK] をクリックして、プロジェクトの設定を確認します。
  3. [挿入] メニューの [ATL オブジェクトの新規作成] をクリックします。[ATL オブジェクト ウィザード] ダイアログ ボックスで、[シンプル オブジェクト] をクリックし、[次へ] をクリックします。
  4. ウィザードの [ATL オブジェクト ウィザードのプロパティ] ダイアログ ボックスの [名前] ページで、[ショートネーム] テキスト ボックスにコンポーネント名を入力します。他のテキスト ボックスはウィザードが自動的に入力を行います。
  5. [アトリビュート] ページで、[スレッドモデル][アパートメント][インターフェイス][カスタム][アグリゲーション][いいえ] を選択します。他のチェック ボックスは選択しないでください。[OK] をクリックします。

ATL ウィザードはいくつかのファイルを作成します。サンプル プロジェクトでは、[名前] ページでプロジェクト名として "LyricsTool"、コンポーネント名として "LyricsReader" が入力され、以下のファイルが生成されます。

  • LyricsTool.idl
    COM を通して公開されるインターフェイスを記述するインターフェイス定義言語。このファイルは、ILyricsReader という 1 つのインターフェイスを含んでいます。
  • LyricsReader.h
    CLyricsReader クラスの宣言と、それが実装しているインターフェイスのマップ。この時点では、ILyricsReader が唯一のインターフェイスです。
  • LyricsReader.cpp
    CLyricsReader クラスの実装。この時点では、このファイルはいくつかの include 文のみを含んでいます。
  • LyricsReader.rgs
    自己登録のためのスクリプト ファイル。ツールを DirectMusic Producer Toolgraph Designer から利用できるようにしたい場合は、後でこのファイルを変更します。
  • LyricsTool.cpp
    DLL のエントリ ポイントと登録関数。このファイルは変更してはいけません。
  • LyricsTool.def、LyricsTool.rc、Resource.h、StdAfx.cpp、および StdAfx.h
    これらの標準ファイルも、変更する必要はありません。

IDirectMusicTool インターフェイスの追加

これで ILyricsReader インターフェイスを公開するコンポーネントができました。オブジェクトが DirectMusic ツールとして動作するためには、さらに IDirectMusicTool か、このインターフェイスのそれ以降のバージョンをサポートする必要があります。

コンポーネントにインターフェイスを追加するには

  1. LyricsReader.h (またはプロジェクトの等価なファイル) で、ファイルの先頭近くに次の行を追加します。

    
    #include <dmplugin.h>
    

    このファイルは、他の必要な DirectMusic ヘッダー ファイルも取り込みます。

  2. LyricsReader.h. のクラス宣言に太字で示した行を追加して、オブジェクト クラス IDirectMusicTool から派生させます。

    
    class ATL_NO_VTABLE CLyricsReader : 
        public CComObjectRootEx<CComSingleThreadModel>,
        public CComCoClass<CLyricsReader, &CLSID_LyricsReader>,
        public IDirectMusicTool,
        public ILyricsReader
    
  3. COM マップに IDirectMusicTool を追加します。COM マップにより、QueryInterface の ATL 実装は、多重継承を行っているオブジェクトについて正しいインターフェイス ポインタを返すことができます。IDirectMusicTool インターフェイスは外部で定義されているので、COM_INTERFACE_ENTRY_IID マクロを使用して、Dmplugin.h に定義されている IID を関連付けます。

    
    BEGIN_COM_MAP(CLyricsReader)
        COM_INTERFACE_ENTRY_IID(IID_IDirectMusicTool, IDirectMusicTool)
        COM_INTERFACE_ENTRY(ILyricsReader)
    END_COM_MAP()
    
  4. クラス宣言の中ですべての IDirectMusicTool メソッドを宣言します。サンプルでは、COMマップの直後に以下の行があります。太字で示した行は手動で追加されています。このコードをコピーして、任意のプロジェクトに貼り付けることができます。

    
    {
    public:
    // IDirectMusicTool
    
        STDMETHOD(Init)                  (IDirectMusicGraph* pGraph);
        STDMETHOD(GetMsgDeliveryType)    (DWORD* pdwDeliveryType );
        STDMETHOD(GetMediaTypeArraySize) (DWORD* pdwNumElements );
        STDMETHOD(GetMediaTypes)         (DWORD** padwMediaTypes, 
                                          DWORD dwNumElements);
        STDMETHOD(ProcessPMsg)           (IDirectMusicPerformance* pPerf, 
                                          DMUS_PMSG* pPMSG);
        STDMETHOD(Flush)                 (IDirectMusicPerformance* pPerf, 
                                          DMUS_PMSG* pPMSG, 
                                          REFERENCE_TIME rtTime);
    
  5. 独自のクラス メソッドとプロパティを追加します。インターフェイスには手動でメソッドを追加することもできますし、ClassView ウィンドウでインターフェイスを右クリックし、[メソッドの追加] または [プロパティの追加] を選択するという方法もあります。

    サンプルでは、次のコードが IDirectMusicTool メソッドの宣言の直後に置かれています。メソッド宣言は Add Property ウィザードによって生成されたもので、太字で示した行は手動で追加されたものです。

    
    // ILyricsReader
    STDMETHOD(get_bstrLyric)(/*[out, retval]*/ BSTR *pVal);
    STDMETHOD(get_dwLeadTime)(/*[out, retval]*/ long *pVal);
    STDMETHOD(put_dwLeadTime)(/*[in]*/ long newVal);    
    
    private:BSTR m_bstrLyric;DWORD m_dwLeadTime;
    };
    

IDirectMusicTool の実装

コンポーネント開発の次のステップでは、クラス メソッドを実装します。この例では、実装は LyricsReader.cpp です。

クラスは、IDirectMusicTool のすべてのメソッドの実装を、名前だけのものであっても提供しなくてはなりません。これらのメソッドは、DirectMusic パフォーマンスが、ツール グラフ内でメッセージを送信するときに呼び出します。以下に各メソッドの目的を示します。

  • Init
    オブジェクトの必要な初期化作業を実行します。このメソッドは、アプリケーションが IDirectMusicPerformance::InsertTool
    を呼び出してグラフにツールを追加するときに呼び出されます。これはつねに S_OK を返します。

  • GetMsgDeliveryType
    パフォーマンスがいつツールの ProcessPMsg
    メソッドを呼び出すかを指定します。*pdwDeliveryType パラメータに返される値は、Dmusici.h に定義されている次のフラグのいずれかでなくてはなりません。

    • DMUS_PMSGF_TOOL_ATTIME
      メッセージ構造体の rtTime または mtTime メンバで指定された時刻にメッセージを処理します。レイテンシは考慮に入れられないので、ツールがスタンプされた時刻に受け取り、次のツールに渡したメッセージは、次のツールではつねにその時刻よりも後に受信されます。
    • DMUS_PMSGF_TOOL_QUEUE
      メッセージをタイムスタンプからレイテンシを差し引いた時刻に処理します。
    • DMUS_PMSGF_TOOL_IMMEDIATE
      メッセージをただちに処理します。

    ツールは、待機すべき十分な理由がない限り、下流にメッセージを待っているツールが存在するかもしれないので、メッセージをただちに配信するよう要求するべきです。ツールが DMUS_PMSGF_TOOL_ATTIME または DMUS_PMSGF_TOOL_QUEUE フラグを指定しており、下流のツールが DMUS_PMSGF_TOOL_IMMEDIATE を指定していると、下流のツールは必要なときにメッセージを受け取れないことになります。

    また、自分のツールの上流のツールが DMUS_PMSGF_TOOL_ATTIME またはDMUS_PMSGF_TOOL_QUEUE 配信タイプを要求している場合には、DMUS_PMSGF_TOOL_IMMEDIATE を要求した場合でも、メッセージの到着が遅れることに注意してください。

  • **GetMediaTypeArraySize
    **ツールが処理するメッセージ タイプの数を返します。

  • GetMediaTypes
    ツールが処理するメッセージ タイプの配列を返します。使用可能な値はDMUS_PMSGT_TYPES 列挙型に定義されています。この配列は、DirectMusic パフォーマンスが、どのメッセージを ProcessPMsg
    メソッドに渡すのかを決定するために使用します。

  • **ProcessPMsg
    **個々のメッセージを処理します。このメソッドは、要求されたタイプにマッチするメッセージが到着するたびにパフォーマンスが呼び出します。このメソッドの実装は、ツールの機能を決定します。このメソッドは、つねに DMUS_S_REQUEUE (メッセージを次のツールに渡す) と DMUS_S_FREE (パフォーマンスにメッセージを解放するよう要求する) のどちらかを返さなくてはなりません。

  • **Flush
    **ツールが不正なデータの結果として送信されたメッセージを受信したときの振る舞いを指定します。これはたとえばノートまたはカーブが進行中のときに、セグメントが予期しない形で停止したときに起こります。ほとんどのツールでは、このメソッドを実装する必要はありません。

LyricsTool サンプル

次に、サンプル ツールが IDirectMusicTool インターフェイスをどのように実装しているかを見てみましょう。ほとんどのメソッドはきわめて単純です。

Init は、単に 2 つのデータ メンバを初期化します。

GetMediaTypes は、DMUS_PMSGT_LYRIC と DMUS_PMSGT_SCRIPTLYRIC の 2 つのメッセージ タイプを指定します。

GetMsgDeliveryType は、DMUS_PMSGF_TOOL_IMMEDIATE を返します。クライアントが事前に歌詞を取得できるように、メッセージは可能な限り速く処理するべきです。

Flush は、E_NOTIMPL を返します。不正なデータはツールに影響を与えないためです。パフォーマンスは DMUS_PMSGF_TOOL_FLUSH としてフラグ付けされたメッセージについてのみこのメソッドを呼び出しますが、歌詞メッセージがこのようにマークされる可能性はほとんどありません。

ProcessPMsg は、ツールの機能が定義される場所です。まず、メソッドが返ったときにパフォーマンスが次のツールにメッセージを渡せるように、メッセージにスタンプを付けます。


if ((NULL == pPMsg->pGraph ) ||
    (FAILED(pPMsg->pGraph->StampPMsg(pPMsg))))
{
    hr = DMUS_S_FREE;
}

この処理は、メソッドからのリターンを行うコード パスの前に行うことが重要です。メッセージがキューに戻されたときに、次のツールのためのスタンプが付けられていないと、そのメッセージは同じツールに返送され、無限ループが生じる可能性があります。一方、IDirectMusicGraph::StampPMsg がメッセージ構造体の dwPChannel メンバの値を変更する可能性があることにも注意する必要があります。ツールでこの値を使用している場合には、メッセージにスタンプを付ける前に値を保存しておいてください。

次のステップでは、歌詞のテキストを CLyricsReader クラスの m_bstrLyric メンバに格納します。文字列は、クライアントに渡すのに便利なように、BSTR として保存されます。BSTR データ型を使用することで、COM クライアントはサーバーによって割り当てられたメモリを解放できるようになります。


DMUS_LYRIC_PMSG* pLyricMsg = (DMUS_LYRIC_PMSG*) pPMsg;
 
if (!SysReAllocString(&m_bstrLyric, pLyricMsg->wszString))
    hr = DMUS_S_REQUEUE;

これでクライアント アプリケーションからテキストを利用できるようになりました。そのことをクライアントに知らせるために、ツールは DirectMusic 通知を送信します。このプロセスは標準的な COM イベント通知のセットアップよりもはるかに簡単です。使用するのに適した標準の通知タイプがないため、ツールは LyricsTool.h 内に独自のタイプ GUID_NOTIFICATION_LYRICS を定義しています。

**注   **ATL が生成したヘッダー ファイルにツール固有の宣言と定義を格納して、それらをクライアントから利用可能にできます。ただし、このファイルは、プロジェクトが変更されるたびに ATL が再ビルドします。この際に独自の宣言と定義が削除されないように、IDL ファイルに cpp_quote キーワードを使って文字列として格納するようにしてください。

通知をただちに送信し、応答を行うタイミング(たとえば、ユーザーにメッセージを表示するタイミング)をクライアントに決定させることができます。これを可能にするためには、ツールは通知メッセージ構造体の dwField1 および dwField2 メンバを使用するか、プロパティ メソッドを通して、クライアントに歌詞メッセージのタイムスタンプを渡さなくてはなりません。クライアントはこの情報を、再生中のセグメントの進捗状況と関連付けます。

これよりもはるかに簡単な解決方法は、クライアントが m_dwLeadTime プロパティを設定して、歌詞メッセージのタイムスタンプとの関係でいつ通知を受け取りたいかを指定できるようにすることです (ところでこのタイムスタンプは、つねにミュージックの小節の始まりに対応しています)。使用可能なリード タイムはプリペア タイムによって制限されます。 DirectMusic はタイムスタンプの約 1 秒後までツールにメッセージを提供しないので、ツールはそれよりも前にクライアントにメッセージを送信することはできません。

次に示す、サンプルをベースにしたコードは、通知メッセージを割り当て、歌詞メッセージの時刻からクライアント定義のリード タイムを引いた時刻のスタンプを付けた後に、送信します。


DMUS_NOTIFICATION_PMSG *pNotifyMsg;
if (FAILED(pPerf->AllocPMsg(sizeof(DMUS_NOTIFICATION_PMSG),
        (DMUS_PMSG**)&pNotifyMsg)))
    return DMUS_S_REQUEUE;
 
ZeroMemory(pNotifyMsg, sizeof(DMUS_NOTIFICATION_PMSG));
pNotifyMsg->dwSize = sizeof(DMUS_NOTIFICATION_PMSG);
 
REFERENCE_TIME rtLyric;
pPerf->MusicToReferenceTime(pLyricMsg->mtTime, &rtLyric);
 
pNotifyMsg->dwFlags = DMUS_PMSGF_REFTIME;

pNotifyMsg->rtTime = rtLyric - (REFERENCE_TIME)(m_dwLeadTime * 10000);
pNotifyMsg->dwType = DMUS_PMSGT_NOTIFICATION;
pNotifyMsg->guidNotificationType = GUID_NOTIFICATION_LYRICS;
 
pPerf->SendPMsg((DMUS_PMSG*)pNotifyMsg);

ProcessPMsg は、歌詞メッセージの処理を終えると、DMUS_S_REQUEUE を返すことでメッセージを受け渡します。歌詞メッセージは出力ツールによって破棄されるので、メッセージがそれ以上使用されることは基本的にありません。ただし、DMUS_S_FREE を返すことで、他のアプリケーション定義のツールがメッセージを見られないようにすることができます。

LyricsToolClient サンプル

サンプル クライアントは、DirectMusic Producer で作成された歌詞トラック付きのセグメントを再生する、基本的なカラオケ アプリケーションです。ツールから歌詞が存在することを知らせる通知を受け取ったアプリケーションは、歌詞を取得し、対応するミュージックが再生される数分の 1 秒前に、その歌詞をリスト ボックスに表示します。

クライアントを実行する前に、ツールを登録する必要があります。これには 2 つの方法があります。

  • Visual Studioに LyricsTool プロジェクトをロードして、ビルドする。

    ?または?

  • 配布された DLL を含んでいるディレクトリの中で、次のコマンドを実行する。

    
    regsvr32 lyricstool.dll
    

    必要ならば Regsvr32.exe へのパスを含めます。

Play.cpp では、クライアントは COM を初期化し、パフォーマンスを作成した後に、InitMusic 関数の中でツールのセットアップを行っています。最初のステップでは、ツール オブジェクトを作成し、ILyricsReader インターフェイスを取得します。


if (FAILED(CoCreateInstance(CLSID_LyricsReader, NULL,
    CLSCTX_INPROC_SERVER, IID_ILyricsReader, 
    (void **) &g_pLyricsReader)))
{
    MessageBox( NULL, "Couldn't create tool object.", "Error", MB_OK );
    return 0;
}

次に、クライアントは IDirectMusicTool インターフェイスを取得します。


if (FAILED(g_pLyricsReader->QueryInterface(IID_IDirectMusicTool,
    (void**)&g_pTool)))
{
    MessageBox(NULL, L"QueryInterface failed.", L"Error", MB_OK);
    return 0;
}

ツールに DirectMusic パフォーマンスを関連付けるために、アプリケーションは次のようにグラフを作成し、グラフにツールを挿入します。


IDirectMusicGraph* pGraph;
if( SUCCEEDED(CoCreateInstance( CLSID_DirectMusicGraph, NULL,
    CLSCTX_INPROC, IID_IDirectMusicGraph, (void**)&pGraph)))
{
    if (SUCCEEDED(pGraph->InsertTool(g_pTool, NULL, 0, 0 )))
    {
    hr = g_pPerformance->SetGraph(pGraph);
    }
    pGraph->Release();
}

これでツールは、パフォーマンスの中のすべてのセグメントの歌詞メッセージをインターセプトするようになりました。ツールのアプリケーションを特定のセグメントに制約するには、代わりに IDirectMusicSegment::SetGraph を使用します。

クライアントは、ILyricsReaderput_dwLeadTime メソッドを使用して、通知のリード タイムを設定します。このリード タイムにより、アプリケーションはミュージックの対応する小節が再生される直前に、歌詞の個々の行を表示できます。


g_pLyricsReader->put_dwLeadTime(LEADTIME);

クライアントの初期化作業の最後のステップでは、ツールが送信するタイプの通知を要求し、通知が到着するたびに発生するイベントを設定します。GUID_NOTIFICATION_LYRICS は、ツールとともに配布される LyricsTool.h の中で定義されています。


g_pPerformance->AddNotificationType(GUID_NOTIFICATION_LYRICS);
g_hDMusicMessageEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
g_pPerformance->SetNotificationHandle(g_hDMusicMessageEvent, 0);

イベントが発生すると、ProcessDirectMusicMessages 関数が呼び出されます。この関数は、ILyricsReader::get_bstrLyric メソッドを呼び出して、ツールから歌詞テキストを取得します。クライアントは、BSTR をマルチバイト文字列に変換してリスト ボックスに送信した後に、ツール コンポーネントによって割り当てられた BSTR を解放します。

DirectMusic Producer へのツールのプラグイン

Microsoft(R) DirectX(R) ソフトウェア開発キットとともに配布される DirectMusic Producer アプリケーションには、Toolgraph Designer コンポーネントが含まれています。ツールをデザイナ内で、またツールを使って設計されたセグメントまたはオーディパスの再生時に利用できるようにするためには、2 つの作業を行わなくてはなりません。

  • ATL 登録スクリプトに適切なレジストリ キーと値を追加することで、コンポーネントの登録時にツールが DirectMusic ツールとして登録されるようにします。
  • DirectMusic Producer がツールのロードと保存を行えるように、ツール クラスに IPersistStream インターフェイスを実装します。

さらに、ユーザーが DirectMusic Producer でツールのパラメータを変更できるようにするためには、プロパティ ページを用意し、ISpecifyPropertyPages インターフェイスを実装する必要があります。

ツールを DirectMusic Producer セグメント ファイルの Parameter Control トラックから制御できるようにしたい場合は、さらに IMediaParams インターフェイスをサポートする必要があります。IMediaParams の詳細については、DirectX SDK の Microsoft(R) DirectShow(R) のドキュメントを参照してください。

レジストリ キーと値の追加

コンポーネントが登録時に DirectMusic ツールとして登録されるようにするには、ATL プロジェクトの登録スクリプト (.rgs) ファイルに以下の行を追加します。太字のセクションは、個々のツールに合わせて変更します。


HKEY_LOCAL_MACHINE
{
  'SOFTWARE'
  {
    'Microsoft'
    {
      'DirectMusic'
      {
        'Tools'
        {
          ForceRemove {<code><b class="cfe">FA95E09B-A993-11D4-9AAC-00104BCC1EAA</b></code>}
          {
            val 'Description' = s '<code><b class="cfe">DirectMusic tool to read lyrics</b></code>'
            val ' Name' = s '<code><b class="cfe">LyricsReader</b></code>'
            val 'ShortName' = s '<code><b class="cfe">LyricsReader</b></code>'
           }
        }
      }
    }
  } 
}

ForceRemove の行では、CLSID をツールの CLSID に置き換えます。この値はすでに .rgs ファイルのいくつかの場所に含まれているので、簡単にコピーして貼り付けることができます。

ShortName として入力した値はツール パレットに表示されます。DirectMusic Producer はその他の値は使用しません。

IPersistStream インターフェイスの実装

IPersistStream のサポートを追加するために、まずツール クラスの基本クラスのリストとCOM マップにインターフェイスを追加します。LyricsReader.h の新しい行は太字で示しています。


class ATL_NO_VTABLE CLyricsReader : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CLyricsReader, &CLSID_LyricsReader>,
    public ILyricsReader,
    public IDirectMusicTool,
    public IPersistStream
.
.
BEGIN_COM_MAP(CLyricsReader)
    COM_INTERFACE_ENTRY(ILyricsReader)
    COM_INTERFACE_ENTRY_IID(IID_IDirectMusicTool, IDirectMusicTool)
    COM_INTERFACE_ENTRY(IPersistStream)
END_COM_MAP()

次に、以下のメソッド宣言を追加します。



          
            // IPersistStream
STDMETHOD(GetClassID(/* [out] */ CLSID __RPC_FAR *pClassID));
STDMETHOD(IsDirty( void));
STDMETHOD(Load(/* [unique][in] */ IStream __RPC_FAR *pStm));
STDMETHOD(Save(/* [unique][in] */ IStream __RPC_FAR *pStm, /* [in] */ BOOL fClearDirty));
STDMETHOD(GetSizeMax(/* [out] */ ULARGE_INTEGER __RPC_FAR *pcbSize));

          
        

IPersistStream 実装の目的は、DirectMusic Producer がツールをオーディオパスまたはセグメントの一部として保存できるようにすること、また後に、オーディオパスまたはセグメントのランタイム ファイルが再生のためにロードされるときに、DirectMusic ローダーがツールをセットアップできるようにすることです。プログラマの責任は、ファイルの中の、ツールのカスタム プロパティを含んでいるチャンクを用意することだけです。このチャンクの保存とロードは、IPersistStream::SaveIPersistStream::Load の実装に渡される IStream インターフェイスの Write および Read メソッドを使って行います。DirectMusic Producer は、ツールの CLSID とグラフ内での位置など、ツールの標準的なプロパティを保存する責任を負います。このデータは後に、ユーザーのシステム上でツールを作成するために使用されます。詳細については、DirectMusic SDK ドキュメントの "Tool Form" のトピックを参照してください。

ツールに永続化が必要なプロパティがない場合でも、少なくともチャンク識別子とデータ サイズの保存を行う IPersistStream::Save を実装する必要があります。データ サイズはゼロであってもかまいません。これを行わないと、DirectMusic Producer のユーザーは Toolgraph Designer ウィンドウにツールをドラッグすることができません。

プロパティ ページの追加

DirectMusic Producer 内でツールのプロパティを変更できるように、次のようにしてプロパティ ページを実装します。

  • Visual Studio の [挿入] メニューの [ATL オブジェクトの新規作成] をクリックします。[ATL Object Wizard] ダイアログ ボックスで、[コントロール] カテゴリの [プロパティ ページ] をクリックします。[次へ] をクリックします。[名前] ページの [ショートネーム] に文字列を入力します。[アトリビュート] ページで、[インターフェイス][カスタム][アグリゲーション][いいえ] オプションをクリックします。[ストリング] ページで、説明文を入力し、また存在するならばヘルプ ファイルの名前を入力します。[タイトル] 文字列は、DirectMusic Producer ツール プロパティ シートのプロパティ ページのタブに表示される文字列です。

  • Visual Studio リソース エディタが開き、空のプロパティ ページが表示されます。コントロールとハンドラを追加してください (詳しい操作方法については、ATL のドキュメントを参照してください)。ATL は、プロパティ クラスの宣言に、IPropertyPageImpl::Apply メソッドのスケルトン 実装を挿入します。このメソッドの中で、ツールのプロパティを更新することになります。これは DirectMusic Producer ツール プロパティ シートの [OK] ボタンがクリックされたときに呼び出されます。

  • プロパティ ページの存在を DirectMusic Producer に知らせるために、IPersistStream を追加したときと同じように、ツール クラス宣言と COM マップに ISpecifyPropertyPages インターフェイスを追加します。その後、パブリック メソッドのリストに、次に示す ISpecifyPropertyPages メソッドの宣言を追加します。

    
    STDMETHOD(GetPages)(CAUUID *pPages);
    

    ツール クラスの実装で、GetPages メソッドを定義します。次に示すサンプルの実装は、1つのプロパティ ページを識別しています。CLSID_LyricsProp は、ウィザードがプロパティ ページを作成したときに、ATL によって定義されたものです。この定数は LyricsProp.h で宣言されており、LyricsReader.cpp に手動でインクルードされています。

    
    STDMETHODIMP CLyricsReader::GetPages(CAUUID *pPages)
    {
        if (!pPages) return E_POINTER;
        pPages->cElems = 1;
        pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
        if (pPages->pElems == NULL)
            return E_OUTOFMEMORY;
        *(pPages->pElems) = CLSID_LyricsProp;
        return S_OK;
    }
    

    DirectMusic Producer は、ツールのプロパティ ページを探すために、このメソッドを呼び出します。このページは、ユーザーが Toolgraph Designer コンテキスト メニューの [Propaty] をクリックし、リスト中でツールのインスタンスを選択し、[Edit Tool Properties] ボタンをクリックしたときに表示されます。

ツールの配布

ツールのソフトウェア開発キットとともに、以下のファイルを配布する必要があります。"LyricsTool" はコンポーネントの名前に置き換えてください。

  • **LyricsTool.dll
    **コンポーネント DLL。アプリケーション開発者は、自分のプロダクトとともにこのツールを配布し、ユーザーのシステム上に正しく登録されたことを確認する責任を負います。

  • **LyricsTool_i.c
    **アプリケーションがオブジェクトを作成するために必要な、コンポーネントの CLSID の定義を含んでいます。また、オブジェクトのカスタム インターフェイスの IID も含んでいます。

  • **LyricsTool.h
    **オブジェクトのカスタム インターフェイスの宣言を含んでいます。IDirectMusicTool メソッドを手動で追加した場合には、このファイルには現われません。ただし、アプリケーションはこれらのメソッドを直接には呼び出しません。

    前に述べたように、IDL にリテラル文字列として含めることで、このファイルにその他の必要な宣言を追加することができます。

関連情報

Microsoft DirectMusic ツールの詳細については、DirectX Software Development Kit とDirectMusic Producer のヘルプを参照してください。これらの製品は Microsoft DirectX 8.0a SDK ダウンロード ページからダウンロードできます。