VCDPropertiesの一覧を表示させる

ここでは新しいVCDプロパティインターフェースを使用してビデオキャプチャデバイスの全プロパティを呼び出す方法について説明します。また、定義済みIDを使ったプロパティへのアクセス、調整の仕方についても説明します。

画像取り込みデバイスから呼び出されるプロパティは全てツリービューで表示されます。プロパティの体系自体がツリー状であるためこの表示方法が使用されています。ツリーの根元にあたるのが IVCDPropertyItemsクラスライブラリリファレンス>クラス>IVCDPropertyItems コレクションです。この中には現在の画像取り込みデバイスより提供される全IVCDPropertyItemsクラスライブラリリファレンス>クラス>IVCDPropertyItems が含まれています。全てのIVCDPropertyItemクラスライブラリリファレンス>クラス>IVCDPropertyItem が一つ以上のIVCDPropertyElementクラスライブラリリファレンス>クラス>IVCDPropertyElementsを持ち、さらに その中に一つ以上のIVCDPropertyInterfaceクラスライブラリリファレンス>クラス>IVCDPropertyInterfacesがあります。プロパティにアクセスする 際にはそれらを使用します。

今回のサンプルプログラムのソースコードはサンプルソースディレクトリの%TOPLEVEL%\samples\VCx\ListVCDProperties にございます。 VC++2010バージョンでは%TOPLEVEL%\Samples\VC10となります。

プロジェクトの新規作成

今回のサンプルプログラムはダイアログベースのアプリケーションです。プロジェクトの作成方法ははじめに:Visual C++プロジェクトプログラマーズガイド>はじめに:Visual Studio C++で説明している手順にて行ってください。 今回の例とほぼ同じですが、今回は"シングルドキュメント"ではなく"ダイアログベース"となります。

samples\VCx\Commonディレクトリにはプロパティを調整するためのクラスがいくつか存在し、それらはプロジェクトに追加することで使えるようになります。プロジェクトエクスプローラーでプロジェクトを右クリックし、"新しいフォルダ" を選んでcontrolsと名付けます。"ファイル拡張子"のところはそのままで結構です。作成したフォルダを右クリックし、"フォルダにファイルを追加"を選択します。samples\VCx\Commonディレクトリで"VCD"で始まる全てのファイルを選択し "OK" を押すとプロジェクトにそれらが追加されます。

ツリービュー用にいくつかのビットマップが必要となります。"挿入"  メニューより"リソース..."を選択し、"リソースの挿入"ダイアログで"Bitmap" を選択後"インポート" ボタンをクリックします。次のダイアログで"Files of type"を "All Files (*.*)" に設定しこのサンプルのディレクトリまで移動します。サブディレクトリ "res" を開いてそこにある全てのビットマップファイルを選択し"Import" ボタンをクリックします。それらにIDB_AUTOIDB_BUTTONのような適当なIDを与えてください。

アプリケーションに機能を追加する

ダイアログにボタンを2つ追加し、"Select Device..." と"Property Page"いうラベルをつけ、IDをそれぞれ "IDC_SELECT_DEVICE" 、 "IDC_SHOW_PAGE"とします。ツリーコントロールを追加し"IDC_VCDTREE"というIDを与えます。ツリーコントロールはVCDPropertiesの体系を表示させるために使用します。静的テキストのフィールドを追加しIDを "IDC_DISPLAY"とします。テキストフィールドのプロパティダイアログを開き"Styles"タブの"Border"プロパティにチェックを入れます。このコントロールはライブビデオの表示に使用します。最後にグループボックスを追加し"IDC_CTRL_FRAME"というIDを与えます。プロパティを調整するためのコントロールがランタイム時にこのフレーム内に置かれることになります。
このダイアログを呼び出すには"VCD Property Tree.cpp"ファイルを開きInitInstanceメソッド内のコードを以下の通り変更してください。

CVCDPropertyTreeDlg dlg;

if( !dlg.selectDevice() )
{
  AfxMessageBox( TEXT("No device was selected.") );
  return FALSE;
}

m_pMainWnd = &dlg;
dlg.DoModal();

// ダイアログが閉じられた際にはFALSEを返すことでメッセージポンプを開始せずにアプリケーションを終了します。
return FALSE;

これはメインダイアログの前にデバイス選択のダイアログが呼び出されるようにします。そして有効なデバイスがあるかどうか、ない場合にはアプリケーションがメッセージボックスを表示し終了するようにします。
ダイアログクラスに機能を追加するには"VCD Property TreeDlg.h" を開き"VCDPropertyCtrl.h":を追加します。

#include "../Common/VCDPropertyCtrl.h"

さらにクラス定義の上にいくつかusingステートメントを挿入します。

using DShowLib::tIVCDPropertyItemsPtr;
using DShowLib::tIVCDPropertyItemPtr;
using DShowLib::tIVCDPropertyElementPtr;
using DShowLib::tIVCDPropertyInterfacePtr;

CVCDPropertyTreeDlgクラスにpublicメソッドselectDeviceと、いくつかprotectedメソッド、変数をを追加します。

public:
  bool selectDevice();
protected:
   HICON m_hIcon;

   DShowLib::Grabber m_Grabber;

   CImageList m_ImageList;  // ツリービュー用のグラフィック要素を含んでいる

   void QueryVCDProperties();
   void QueryVCDPropertyItems( tIVCDPropertyItemsPtr pItems, HTREEITEM hRoot );
   void QueryVCDPropertyElements( tIVCDPropertyItemPtr pItem, HTREEITEM hItem );
   void QueryVCDPropertyInterfaces( tIVCDPropertyElementPtr pElem, HTREEITEM hElem );

   void ListAllPropertyItems();
       CRect DpiAdjustedRect( int left, int top, int right, int bottom );
   smart_ptr< CWnd > m_pCurrentControl;
   smart_ptr< CWnd > m_pBuddy;
   std::vector< CInterfacePath > m_InterfaceVector;

ではメソッドの実装を行う為に"VCD Property TreeDlg.cpp"を編集します。まずはプロパティ用のインターフェースクラスをインクルードし、ネームスペースDShowLibを宣言します。

#include "../Common/VCDRangeSlider.h"
#include "../Common/VCDSwitchCheck.h"
#include "../Common/VCDButtonButton.h"
#include "../Common/VCDMapStringsCombo.h"
#include "../Common/VCDAbsValSlider.h"

using namespace DShowLib;

ツリービュー用のグラフィック要素はダイアログの構築時にimagelistの中に格納されるため、標準コンストラクタを以下の通り拡張します。

CVCDPropertyTreeDlg::CVCDPropertyTreeDlg(CWnd* pParent /*=NULL*/)
  : CDialog(CVCDPropertyTreeDlg::IDD, pParent)
{
  //{{AFX_DATA_INIT(CVCDPropertyTreeDlg)
    // NOTE: ClassWizard がメンバ初期化を加える
  //}}AFX_DATA_INIT
  // Win32ではLoadIconはその後のDestroyIconを必要としません
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);       

  // ツリービューのためのimagelistの作成とロード
   m_ImageList.Create( 16, 16, ILC_COLOR4, 0, 7 );       

  CBitmap bm;
  bm.LoadBitmap( IDB_ITEM );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
  bm.LoadBitmap( IDB_VALUE );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
  bm.LoadBitmap( IDB_AUTO );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
  bm.LoadBitmap( IDB_RANGE );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
  bm.LoadBitmap( IDB_SWITCH );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
  bm.LoadBitmap( IDB_BUTTON );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
  bm.LoadBitmap( IDB_MAPSTRINGS );
  m_ImageList.Add( &bm, RGB(0,0,0) );
  bm.Detach();
}

これでさきほどリソースに追加したグラフィック要素をイメージリストに入れることになります。
OnInitDialogイベントにおいてはgrabberとツリービューをセットアップする必要があります。
そのためにはOnInitDialogメソッドに以下のコードを追加します。

m_Grabber.setHWND( GetDlgItem( IDC_DISPLAY )->GetSafeHwnd() );
m_Grabber.startLive();

CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem( IDC_VCDTREE );
pTree->SetImageList( &m_ImageList, TVSIL_NORMAL );

// プロパティツリーをデバッグ出力に表示
ListAllPropertyItems();

QueryVCDProperties();

上記のコードは最初にgrabberのHWNDを静的テキストのコントロールにセットし、ライブビデオを表示させるようにします。イメージリストはSetImageListによってツリービューに結合され、コントロールがグラフィック要素にアクセスできるようになります。最後にListAllPropertyItemsQueryVCDPropertiesがコールされます。
ListAllPropertyItems
はデバッグ出力画面にサポートされている全プロパティをツリー表示します。デバッグ出力はコントロールなどの他の側面に関係なくVCDProperties の体系を表示します。デバッグ出力画面でプロパティツリーを表示させるにはデバッグモードでプログラムを実行する必要がございます。

起動時にコールされるpublicメソッドであるselectDeviceがデバイス選択ダイアログを表示します。以下の通り実装されます。

bool CVCDPropertyTreeDlg::selectDevice()
{
  m_Grabber.showDevicePage( m_hWnd );

  return m_Grabber.isDevValid();
}

クラスウィザードを使って2つのボタン"IDC_SELECT_DEVICE" と "IDC_SHOW_PAGE"用のクリックイベントを挿入します。これでボタンをクリックすると各ダイアログを表示するようになります。"IDC_SHOW_PAGE"ボタンのクリックイベントの実装はプロパティダイアログをコールするだけで簡単に行うことができます。

void CVCDPropertyTreeDlg::OnShowPage()
{
  // プロパティページの表示
  m_Grabber.showVCDPropertyPage( m_hWnd );
}

"IDC_SELECT_DEVICE"のクリックイベントの実装はもう少しコードが必要となります。デバイスがライブモードかどうかをチェックする必要があるためです。また、デバイスの選択後にツリービューを更新する必要があります。コードは以下のようになります。

void CVCDPropertyTreeDlg::OnSelectDevice()
{
  // デバイスページの表示前にライブモードを停止させる
  m_Grabber.stopLive();

  // デバイスページの表示
  m_Grabber.showDevicePage( m_hWnd );       

  // 有効なデバイスが選択されていればライブモードを開始する
  if( m_Grabber.isDevValid() )
    m_Grabber.startLive();       

  // プロパティツリーをデバッグ出力に表示
  ListAllPropertyItems();      

  // ツリーの再構築
  QueryVCDProperties();
}

ListAllPropertyItemsはデバッグ出力にプロパティツリーを表示させます。以下のように実装されます。

void CVCDPropertyTreeDlg::ListAllPropertyItems()
{ 
  OutputDebugString( TEXT("\n\nVCD Tree:\n\n") );
 
  // 全プロパティ項目の取得
  tIVCDPropertyItemsPtr pVCDProperties = m_Grabber.getAvailableVCDProperties(); 
  if( pVCDProperties != 0 ) 
  { 
    // 繰り返しで項目の名前をを表示させる
    tVCDPropertyItemArray itemArray = pVCDProperties->getItems(); 
    for( tVCDPropertyItemArray::const_iterator itItem = itemArray.begin(); itItem != itemArray.end(); ++itItem )
    { 
      // 項目名の表示
      OutputDebugString( CString( (*itItem)->getName().c_str() ) ); 
      OutputDebugString( TEXT("\n") );               
 
      // 繰り返しで要素の名前を表示させる
      tVCDPropertyElementArray elemArray = (*itItem)->getElements(); 
      for( tVCDPropertyElementArray::iterator itElem = elemArray.begin(); 
                        itElem != elemArray.end(); ++itElem ) 
      { 
        // 要素の表示 
        CString elemStr; 
        elemStr.Format( TEXT("   Element : %s\n"), (*itElem)->getName().c_str() ); 
        OutputDebugString( elemStr );                   
 
        // 繰り返しでインターフェース名を表示させる 
        tVCDPropertyInterfaceArray itfArray = (*itElem)->getInterfaces(); 
        for( tVCDPropertyInterfaceArray::const_iterator itItf = itfArray.begin(); 
                                itItf != itfArray.end(); ++itItf ) 
        { 
          // インターフェースの型をチェックし名前を表示 
          OutputDebugString( TEXT("        Interface : ") );
 
          GUID iid = (*itItf)->getInterfaceID();                      
 
          if( iid == IID_IVCDAbsoluteValueProperty ) 
          { 
            OutputDebugString( TEXT("Absolute Value\n") ); 
          } 
          else if( iid == IID_IVCDMapStringsProperty ) 
          { 
            OutputDebugString( TEXT("Mapstrings\n") ); 
          } 
          else if( iid ==  IID_IVCDSwitchProperty ) 
          { 
            OutputDebugString( TEXT("Switch\n") ); 
          } 
          else if( iid == IID_IVCDButtonProperty ) 
          { 
            OutputDebugString( TEXT("Button\n") ); 
          } 
          else if( iid == IID_IVCDRangeProperty ) 
          { 
            OutputDebugString( TEXT("Range\n") ); 
          } 
        } 
      } 
    }
  }
}

上記コード内にネストされたforループはVCDPropertiesのツリー構造を反映しています。最初のループは利用可能な全IVCDPropertyItemクラスライブラリリファレンス>クラス>IVCDPropertyItemsをカバーしておりデバッグ出力にそれらの名前を表示します。各項目ごとに次のループが利用可能なIVCDPropertyElementクラスライブラリリファレンス>クラス>IVCDPropertyElementを表示します。最後に3つ目のループで要素が提供する全タイプのインターフェースを表示します。インターフェースは値の詳細度の順でソートされます。最も詳細なものとしては "AbsoluteValue"インターフェースが、次に"MapStrings"が続きます。"Switch" と"Button" はOn/Offの切換えやトリガーなどシンプルな機能を提供するディテールインターフェースです。 "Range"インターフェースは最も包括的なものですが表す値は意味を持ちません。例えば "Brightness" の範囲は0から255となりますが、0と255のどちらがbrightnessの最大値かというのは判断することはできません。

メソッドQueryVCDPropertiesが現在選択中のデバイスのプロパティでツリービューを初期化。

void CVCDPropertyTreeDlg::QueryVCDProperties()
{
  CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem( IDC_VCDTREE );

  // ツリーのクリア
  pTree->DeleteAllItems();       

  // ルート項目の挿入
  HTREEITEM hRoot = pTree->InsertItem( TEXT("VCD Properties") );       

  // インターフェースでない項目データをMAXDWORDにセット
  pTree->SetItemData( hRoot, MAXDWORD );

  tIVCDPropertyItemsPtr pVCDProperties = m_Grabber.getAvailableVCDProperties();
  if( pVCDProperties != 0 )
  {
    QueryVCDPropertyItems( pVCDProperties, hRoot );
  }

  // ツリーが拡張することを確認
  pTree->Expand( hRoot, TVE_EXPAND );
}

上記のプロシージャはツリービューをクリアし新しいルートノードを作成します。ルートノードは"VCDPropertyItems"というラベルになります。プロシージャQueryVCDPropertyItemsが利用可能なプロパティ項目を挿入します。
QueryVCDPropertyItemsは以下のようなコードとなります。

void CVCDPropertyTreeDlg::QueryVCDPropertyItems( tIVCDPropertyItemsPtr pItems, HTREEITEM hRoot )
{     
  CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem( IDC_VCDTREE );       
    
  // 繰り返しで項目をツリーに挿入していき、要素をクエリする     
  tVCDPropertyItemArray itemArray = pItems->getItems();     
  for( tVCDPropertyItemArray::const_iterator i = itemArray.begin(); i != itemArray.end(); ++i )     
  {     
    // 項目ノードの挿入     
    HTREEITEM hItem = pTree->InsertItem( CString( (*i)->getName().c_str() ), 0, 0, hRoot );           
    
    // ノードのデータをMAXDWORDに設定     
    pTree->SetItemData( hItem, MAXDWORD );           
    
    // 要素をクエリ     
    QueryVCDPropertyElements( *i, hItem );           
    
    // ツリーが拡張することを確認     
    pTree->Expand( hItem, TVE_EXPAND );
  }
}

QueryVCDPropertyItemsが繰り返しによって全プロパティ項目ごとに新しいノードを作成します。項目を表すノード全てがルートノードの直接の子となります。ノードのラベル名はIVCDPropertyItemクラスライブラリリファレンス>クラス>IVCDPropertyItem(e.g. "Brightness", "Gain" , "Exposure"など)の名前が適用されます。QueryVCDPropertyElementsは新しいノードのためにコールされます。
QueryVCDPropertyElementsは以下のようなコードとなります。

void CVCDPropertyTreeDlg::QueryVCDPropertyElements( tIVCDPropertyItemPtr pItem, HTREEITEM hItem )
{
  CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem( IDC_VCDTREE );

  CString name;
  int imgIndex;       

  tVCDPropertyElementArray elemArray = pItem->getElements();
  for( tVCDPropertyElementArray::const_iterator i = elemArray.begin(); i != elemArray.end(); ++i )
  {

     GUID eid = (*i)->getElementID();
     if( eid == VCDElement_Value )
     {
       name = "VCDElement_Value";
       imgIndex = 1;
     }
     else if( eid == VCDElement_Auto )
     {
       name = "VCDElement_Auto";
       imgIndex = 2;
     }
     else if( eid == VCDElement_OnePush )
     {
       name = "VCDElement_OnePush";
       imgIndex = 5;
     }
     else if( eid == VCDElement_WhiteBalanceBlue )
     {
       name = "VCDElement_WhiteBalanceBlue";
       imgIndex = 1;
     }
     else if( eid == VCDElement_WhiteBalanceRed )
     {
       name = "VCDElement_WhiteBalanceRed";
       imgIndex = 1;
     }
     else
     {
       name = "Unknown element";
       imgIndex = 1;
     }
     name = name + ": '" + (*i)->getName().c_str() + "'";
     HTREEITEM hElem = pTree->InsertItem( name, imgIndex, imgIndex, hItem );

     // ノードのデータをMAXDWORDに設定
     pTree->SetItemData( hElem, MAXDWORD );           

      QueryVCDPropertyInterfaces( *i, hElem );           

     pTree->Expand( hElem, TVE_EXPAND );     
  }
}

QueryVCDPropertyElementsが繰り返しによって要素ごとに新しいノードを作成します。
各ノードはIVCDPropertyElementクラスライブラリリファレンス>クラス>IVCDPropertyElementが属するIVCDPropertyItemクラスライブラリリファレンス>クラス>IVCDPropertyItemを表すノードの子となります。if..then..elseブロックがノードに適したグラフィックツリー要素を決定し、要素の型に応じてベース名を設定します。IVCDPropertyElementクラスライブラリリファレンス>クラス>IVCDPropertyElement (e.g. "Value", "Auto" , "Enable"など)の名前はベース名に追加され、ノードのラベル名をつけるのに使用されます。その後 QueryVCDPropertyInterfacesが新しいノードためにコールされます。QueryVCDPropertyInterfacesは以下のようなコードとなります。

void CVCDPropertyTreeDlg::QueryVCDPropertyInterfaces( tIVCDPropertyElementPtr pElem, HTREEITEM hElem )
{
  CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem( IDC_VCDTREE );

  CWnd* pCtrl = 0;

  CString name;
  int imgIndex;       

  tVCDPropertyInterfaceArray itfArray = pElem->getInterfaces();
  for( tVCDPropertyInterfaceArray::const_iterator i = itfArray.begin(); i != itfArray.end(); ++i )
  {
    GUID iid = (*i)->getInterfaceID();
    if( iid == IID_IVCDRangeProperty )
    {
      name = "Range";
      imgIndex = 3;
    }
    else if( iid == IID_IVCDSwitchProperty )
    {
      name = "Switch";
      imgIndex = 4;
    }
    else if( iid == IID_IVCDButtonProperty )
    {
      name = "Button";
      imgIndex = 5;
    }
    else if( iid == IID_IVCDMapStringsProperty )
    {
      name = "MapStrings";
      imgIndex = 6;
    }
    else if( iid == IID_IVCDAbsoluteValueProperty )
    {
      name = "AbsoluteValue";
      imgIndex = 3;
    }
    else
    {
      name = "Unknown Interface";
      imgIndex = 3;
    }           

    // インターフェース項目の挿入
    HTREEITEM hItf = pTree->InsertItem( name, imgIndex, imgIndex, hElem );           

    // vector内にインターフェースパスを格納
    CInterfacePath ItfPath;           

    ItfPath.itemID = (*i)->getParent()->getParent()->getItemID();
    ItfPath.elementID = (*i)->getParent()->getElementID();
    ItfPath.interfaceID = (*i)->getInterfaceID();

    m_InterfaceVector.push_back( ItfPath );

    // ノードのデータとしてvector内にポジションを格納
    pTree->SetItemData( hItf, m_InterfaceVector.size()-1 );
  }
}

QueryVCDPropertyInterfacesが繰り返しによって要素のインターフェースごとに新しいノードを作成します。各ノードはIVCDPropertyInterfaceクラスライブラリリファレンス>クラス>IVCDPropertyInterfaceがEach属するIVCDPropertyElementクラスライブラリリファレンス>クラス>IVCDPropertyElementを表すノードの事なります。if..then..elseブロックがノードに適したグラフィックツリー要素を決定し、インターフェースの型に応じてベース名を設定します。その名前はノードのラベル名となります。インターフェースノードができましたので、パスが作成されます。インターフェースパスは itemID, elementID, interfaceIDの3つからなります。 interfaceID は現在のインターフェースより直接取得することができます。 elementID はインターフェースの親より取得されなければなりません。親はIVCDPropertyInterface::getParentクラスライブラリリファレンス>クラス>IVCDPropertyInterface>IVCDPropertyInterface::getParent Methodで取得します。最後にitemIDはインターフェースの親の親から取得されるということになります。前述の通り、vectorにインターフェースパスを格納するためにコンテナクラスのCInterfacePathを使用します。vectorのインデックスはノード内にSetItemDataと一緒に格納されます。インターフェースノードがツリーのリーフを作成します。

VCDPropertyへのアクセスと制御

ツリーができあがったので次はプロパティにアクセスしたいと思います。そのためにはツリービューにSelChangedイベントを追加し、以下のコードを挿入します。

void CVCDPropertyTreeDlg::OnSelchangedVcdtree(NMHDR* pNMHDR, LRESULT* pResult) 
{
  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem( IDC_VCDTREE );

  DWORD index = pTree->GetItemData( pNMTreeView->itemNew.hItem );

  // indexがMAXDWORDと等しい場合、そのノードはリーフではない
  if( index == MAXDWORD )
    return;

  // バディウィンドウの破壊
  m_pBuddy = 0;

  // インターフェースパスの取得
  CInterfacePath ItfPath = m_InterfaceVector.at( index );

  // itemID, elementID, interfaceID によって指定されたインターフェースへのポインタを取得
  tIVCDPropertyInterfacePtr pItf = m_Grabber.getAvailableVCDProperties()->findInterface( ItfPath.itemID,
                                               ItfPath.elementID,
                                               ItfPath.interfaceID );

  // フレームに適したテキストのビルド
   CString frameText( pItf->getParent()->getParent()->getName().c_str() );

   // インターフェースがIVCDRangeProperty かどうかをチェック
  if( ItfPath.interfaceID == IID_IVCDRangeProperty )
  {
    // インターフェースポインタを取得
    tIVCDRangePropertyPtr pRangeItf;
    pItf->QueryInterface( pRangeItf );
    if( pRangeItf == 0 )
       return;

     // レンジスライダコントロールの作成
    CVCDRangeSlider* pSlider = new CVCDRangeSlider();          pSlider->Create( WS_CHILD|TBS_NOTICKS, CRect( 300, 450, 500, 480 ), this, 0 );

    // 値テキスト表示のためのバディウィンドウの作成
    CStatic* pBuddy = new CStatic();
    pBuddy->Create( TEXT("0"), WS_VISIBLE|WS_CHILD|SS_CENTERIMAGE, CRect( 0, 0, 100, 23 ), this );
    pBuddy->SetFont( GetDlgItem( IDC_VCDTREE )->GetFont() );
    pSlider->SetBuddy( pBuddy, FALSE );
    m_pBuddy = pBuddy;

    pSlider->setupCtrl( pRangeItf );

    m_pCurrentControl = pSlider;

    // フレームテキストに要素名を追加
    frameText += TEXT(": ");
    frameText += pItf->getParent()->getName().c_str();
   }
   // インターフェースがIVCDSwitchPropertyかどうかをチェック
   else if( ItfPath.interfaceID == IID_IVCDSwitchProperty )
   {
     // インターフェースポインタを取得
     tIVCDSwitchPropertyPtr pSwitchItf;
     pItf->QueryInterface( pSwitchItf );
     if( pSwitchItf == 0 )
       return;

     // スイッチチェックコントロールの作成
     CVCDSwitchCheck* pButton = new CVCDSwitchCheck();
    pButton->Create( CString( pItf->getParent()->getName().c_str() ), 
                  WS_CHILD|BS_CHECKBOX, CRect( 300, 450, 500, 480 ), this, 0 );
    pButton->SetFont( GetDlgItem( IDC_VCDTREE )->GetFont() );
    pButton->setupCtrl( pSwitchItf, 0 );

    m_pCurrentControl = pButton;
   }
   // インターフェースがIVCDButtonPropertyかどうかをチェック
   else if( ItfPath.interfaceID == IID_IVCDButtonProperty )
   {
   // インターフェースポインタを取得
    tIVCDButtonPropertyPtr pButtonItf;
    pItf->QueryInterface( pButtonItf );
    if( pButtonItf == 0 )
       return;

     // ボタンコントロールを作成
    CVCDButtonButton* pButton = new CVCDButtonButton();
    pButton->Create( CString( pItf->getParent()->getName().c_str() ), 
                WS_CHILD|BS_PUSHBUTTON, CRect( 300, 450, 380, 474 ), this, 0 );
     pButton->SetFont( GetDlgItem( IDC_VCDTREE )->GetFont() );
    pButton->setupCtrl( pButtonItf, 0 );

    m_pCurrentControl = pButton;
   }
   // インターフェースがIVCDMapStringsPropertyかどうかをチェック
   else if( ItfPath.interfaceID == IID_IVCDMapStringsProperty )
   {
    // インターフェースポインタを取得
    tIVCDMapStringsPropertyPtr pMapStringsItf;
    pItf->QueryInterface( pMapStringsItf );
    if( pMapStringsItf == 0 )
       return;

    // コンボコントロールを作成
    CVCDMapStringsCombo* pCombo = new CVCDMapStringsCombo();
    pCombo->Create( WS_CHILD|CBS_DROPDOWNLIST|WS_VSCROLL, CRect( 300, 450, 500, 550 ), this, 0 );
     pCombo->SetFont( GetDlgItem( IDC_VCDTREE )->GetFont() );
    pCombo->setupCtrl( pMapStringsItf );

    m_pCurrentControl = pCombo;

    // フレームテキストに要素名を追加
    frameText += TEXT(": ");
    frameText += pItf->getParent()->getName().c_str();
   }
  // インターフェースがIVCDAbsoluteValuePropertyかどうかをチェック
  else if( ItfPath.interfaceID == IID_IVCDAbsoluteValueProperty )
  {
    // インターフェースポインタを取得
    tIVCDAbsoluteValuePropertyPtr pAbsValItf;
    pItf->QueryInterface( pAbsValItf );
    if( pAbsValItf == 0 )
      return;

    // 絶対値スライダコントロールを作成
    CVCDAbsValSlider* pSlider = new CVCDAbsValSlider();
    pSlider->Create( WS_CHILD|TBS_NOTICKS, CRect( 300, 450, 500, 480 ), this, 0 );

    CStatic* pBuddy = new CStatic();
    pBuddy->Create( TEXT("0"), WS_VISIBLE|WS_CHILD|SS_CENTERIMAGE, CRect( 0, 0, 100, 23 ), this );
    pBuddy->SetFont( GetDlgItem( IDC_VCDTREE )->GetFont() );
    pSlider->SetBuddy( pBuddy, FALSE );
    m_pBuddy = pBuddy;

    pSlider->setupCtrl( pAbsValItf );

    m_pCurrentControl = pSlider;

    // フレームテキストに要素名を追加
    frameText += TEXT(": ");
     frameText += pItf->getParent()->getName().c_str();
  }
   // コントロールが(初期設定で)隠れている場合には表示させる
   if( m_pCurrentControl != 0 )
     m_pCurrentControl->ShowWindow( SW_SHOW );

   // フレームタイトルを設定
   GetDlgItem( IDC_CTRL_FRAME )->SetWindowText( frameText );

   *pResult = 0;
}

ツリービューでノードをチェックすると上記のメソッドがコールされます。リーフがクリックされるとインターフェースパスがvectorより取得されインターフェースがfindInterfaceクラスライブラリリファレンス>クラス>IVCDPropertyItems>IVCDPropertyItems::findInterface Methodメソッドより返されます。次に受け取ったインターフェースの型がチェックされ、正しいコントロールが初期化、表示されることになります。これはif..then..elseブロックで行われます。ここでコントロールが動的に作成されます。