[共通項目] ダイアログ

Windows Vista 以降では、ファイルを開いたり保存したりするときに、以前の [共通ファイル] ダイアログよりも [共通項目] ダイアログが優先されます。 [共通項目] ダイアログは、[開く] ダイアログと [保存] ダイアログの 2 つのバリエーションで使用されます。 これら 2 つのダイアログはほとんどの機能を共有しますが、それぞれに独自のメソッドがあります。

この新しいバージョンは [共通項目] ダイアログという名前ですが、ほとんどのドキュメントでは引き続き [共通ファイル] ダイアログと呼ばれます。 以前のバージョンの Windows を特に扱っている場合を除き、[共通ファイル] ダイアログのメンションがこの [共通項目] ダイアログを参照していると想定する必要があります。

ここでは、次のトピックについて説明しています:

IFileDialog、IFileOpenDialog、および IFileSaveDialog

Windows Vista には、[開く] ダイアログと [保存] ダイアログの実装 (CLSID_FileOpenDialog と CLSID_FileSaveDialog) が用意されています。 これらのダイアログ ボックスを次に示します。

screen shot of the open dialog box

screen shot of the save as dialog box

IFileOpenDialogIFileSaveDialogIFileDialog を継承し、その機能の多くを共有します。 さらに、[開く] ダイアログでは IFileOpenDialog がサポートされ、[保存] ダイアログでは IFileSaveDialog がサポートされています。

Windows Vista の [共通項目] ダイアログの実装には、以前のバージョンで提供された実装よりもいくつかの利点があります:

  • ファイル システム パスを使用する代わりに、IShellItem を介した Shell 名前空間の直接使用をサポートします。
  • フック手順を必要とせずに、[OK] ボタンにラベルを設定するなど、ダイアログの簡単なカスタマイズを有効にします。
  • Win32 ダイアログ テンプレートなしで動作する一連のデータ ドリブン コントロールを追加することで、ダイアログのより広範なカスタマイズをサポートします。 このカスタマイズ スキームにより、UI レイアウトから呼び出しのプロセスが解放されます。 ダイアログ デザインに対する変更は引き続きこのデータ モデルを使用するため、ダイアログの実装はダイアログの特定の現在のバージョンには関連付けされません。
  • 選択の変更やファイルの種類の変更など、ダイアログ内のイベントの発信者通知をサポートします。 また、呼び出しのプロセスで、解析など、ダイアログ内の特定のイベントをフックすることもできます。
  • 場所 バーに発信者が指定した場所を追加するなど、新しいダイアログ機能を導入します。
  • [保存] ダイアログでは、開発者は Windows Vista Shell の新しいメタデータ機能を利用できます。

さらに、開発者は次のインターフェイスを実装することを選択できます:

[開く] または [保存] ダイアログは、 呼び出しのプロセスに IShellItem オブジェクトまたは IShellItemArray オブジェクトを返します。 発信者は、個々の IShellItem オブジェクトを使用してファイル システム パスを取得したり、項目のストリームを開いて情報を読み書きしたりすることができます。

新しいダイアログ メソッドで使用できるフラグとオプションは、OPENFILENAME 構造体で見つかった古い OFN フラグとよく似ていて、GetOpenFileNameGetSaveFileName で使用されます。 これらの多くは、FOS プレフィックスで始まる点を除いて、まったく同じです。 完全な一覧については、IFileDialog::GetOptions および IFileDialog::SetOptions のトピックを参照してください。 [開く][保存] ダイアログは、既定で最も一般的なフラグで作成されます。 [開く] ダイアログの場合、これは (FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR) と [保存] ダイアログの場合、これは (FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR)。

IFileDialog とその子孫インターフェイス、IModalWindow 継承して拡張します。 Show は、その唯一のパラメーターとして親ウィンドウのハンドルを受け取ります。 Show が正常に返された場合は、有効な結果が返されます。 HRESULT_FROM_WIN32(ERROR_CANCELLED) が返された場合は、ユーザーがダイアログを取り消したことを意味します。 また、E_OUTOFMEMORY などの別のエラー コードが正当に返される場合もあります。

使用例

次のセクションでは、さまざまなダイアログ タスクのコード例を示します。

ほとんどのサンプル コードは、Windows SDK の [共通ファイル] ダイアログ サンプルにあります。

基本的な使用

次の例は、[開く] ダイアログを起動する方法を示しています。 この例では、Microsoft Word 文書に制限されています。

Note

このトピックのいくつかの例では、CDialogEventHandler_CreateInstance ヘルパー関数を使用して、IFileDialogEvents 実装のインスタンスを作成します。 この関数を独自のコードで使用するには、共通ファイル ダイアログ サンプルから CDialogEventHandler_CreateInstance 関数のソース コードをコピーします。このサンプルでは、このトピックのすべての例を参照してください。

 

HRESULT BasicFileOpen()
{
    // CoCreate the File Open Dialog object.
    IFileDialog *pfd = NULL;
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
                      NULL, 
                      CLSCTX_INPROC_SERVER, 
                      IID_PPV_ARGS(&pfd));
    if (SUCCEEDED(hr))
    {
        // Create an event handling object, and hook it up to the dialog.
        IFileDialogEvents *pfde = NULL;
        hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
        if (SUCCEEDED(hr))
        {
            // Hook up the event handler.
            DWORD dwCookie;
            hr = pfd->Advise(pfde, &dwCookie);
            if (SUCCEEDED(hr))
            {
                // Set the options on the dialog.
                DWORD dwFlags;

                // Before setting, always get the options first in order 
                // not to override existing options.
                hr = pfd->GetOptions(&dwFlags);
                if (SUCCEEDED(hr))
                {
                    // In this case, get shell items only for file system items.
                    hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
                    if (SUCCEEDED(hr))
                    {
                        // Set the file types to display only. 
                        // Notice that this is a 1-based array.
                        hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
                        if (SUCCEEDED(hr))
                        {
                            // Set the selected file type index to Word Docs for this example.
                            hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
                            if (SUCCEEDED(hr))
                            {
                                // Set the default extension to be ".doc" file.
                                hr = pfd->SetDefaultExtension(L"doc;docx");
                                if (SUCCEEDED(hr))
                                {
                                    // Show the dialog
                                    hr = pfd->Show(NULL);
                                    if (SUCCEEDED(hr))
                                    {
                                        // Obtain the result once the user clicks 
                                        // the 'Open' button.
                                        // The result is an IShellItem object.
                                        IShellItem *psiResult;
                                        hr = pfd->GetResult(&psiResult);
                                        if (SUCCEEDED(hr))
                                        {
                                            // We are just going to print out the 
                                            // name of the file for sample sake.
                                            PWSTR pszFilePath = NULL;
                                            hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, 
                                                               &pszFilePath);
                                            if (SUCCEEDED(hr))
                                            {
                                                TaskDialog(NULL,
                                                           NULL,
                                                           L"CommonFileDialogApp",
                                                           pszFilePath,
                                                           NULL,
                                                           TDCBF_OK_BUTTON,
                                                           TD_INFORMATION_ICON,
                                                           NULL);
                                                CoTaskMemFree(pszFilePath);
                                            }
                                            psiResult->Release();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                // Unhook the event handler.
                pfd->Unadvise(dwCookie);
            }
            pfde->Release();
        }
        pfd->Release();
    }
    return hr;
}

ファイル システム項目への結果の制限

以下の例は、結果をファイル システム項目に制限する方法を示しています。 IFileDialog::SetOptions は、IFileDialog::GetOptions で取得した値に新しいフラグを追加することにご注意ください。 これが推奨される方法です。

                // Set the options on the dialog.
                DWORD dwFlags;

                // Before setting, always get the options first in order 
                // not to override existing options.
                hr = pfd->GetOptions(&dwFlags);
                if (SUCCEEDED(hr))
                {
                    // In this case, get shell items only for file system items.
                    hr = pfd->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);

ダイアログのファイルの種類の指定

ダイアログで処理できる特定のファイルの種類を設定するには、IFileDialog::SetFileTypes メソッドを使用します。 そのメソッドは、COMDLG_FILTERSPEC 構造体の配列を受け取り、それぞれがファイルの種類を表します。

ダイアログの既定の拡張メカニズムは、GetOpenFileNameGetSaveFileName から変更されません。 ユーザーがファイル名編集ボックスに入力したテキストに追加されるファイル名拡張子は、ダイアログが開いたときに初期化されます。 既定のファイルの種類と一致する必要があります (ダイアログが開くと選択されます)。 既定のファイルの種類が "*.*" (すべてのファイル) の場合、ファイルは任意の拡張子にすることができます。 ユーザーが別のファイルの種類を選択した場合、拡張子は、そのファイルの種類に関連付けられている最初のファイル名拡張子に自動的に更新されます。 ユーザーが "*.*" (すべてのファイル) を選択した場合、拡張子は元の値に戻ります。

次の例は、上記でどのように行われたかを示しています。

                        // Set the file types to display only. 
                        // Notice that this is a 1-based array.
                        hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
                        if (SUCCEEDED(hr))
                        {
                            // Set the selected file type index to Word Docs for this example.
                            hr = pfd->SetFileTypeIndex(INDEX_WORDDOC);
                            if (SUCCEEDED(hr))
                            {
                                // Set the default extension to be ".doc" file.
                                hr = pfd->SetDefaultExtension(L"doc;docx");

既定のフォルダーの制御

シェル名前空間のほぼすべてのフォルダーは、ダイアログの既定のフォルダー (ユーザーがファイルを開くか保存することを選択したときに表示されるフォルダー) として使用できます。 Show を呼び出す前に IFileDialog::SetDefaultFolder を呼び出します。

既定のフォルダーは、ユーザーがアプリケーションからダイアログを初めて開く際にダイアログを開始するフォルダーです。 その後、ユーザーが最後に開いたフォルダーまたはアイテムの保存に使用した最後のフォルダーでダイアログが開きます。 詳細については、「状態の永続化」を参照してください。

IFileDialog::SetFolder を呼び出すことで、以前のユーザー操作に関係なく、ダイアログが開いたときに常に同じフォルダーを表示するように強制できます。 ただし、これを行うことはお勧めしません。 ダイアログ ボックスを表示する前に SetFolder を呼び出した場合、ユーザーが保存または開いた最新の場所は表示されません。 この動作に非常に具体的な理由がない限り、これは適切または期待されるユーザー エクスペリエンスではなく、避ける必要があります。 ほぼすべてのインスタンスで、IFileDialog::SetDefaultFolder が優れたメソッドです。

[保存] ダイアログでドキュメントを初めて保存する場合は、[開く] ダイアログで行ったのと同じガイドラインに従って初期フォルダーを決定する必要があります。 ユーザーが以前に既存のドキュメントを編集している場合は、そのドキュメントが保存されているフォルダーでダイアログを開き、そのドキュメントの名前を編集ボックスに入力します。 Show を呼び出す前に、現在の項目で IFileSaveDialog::SetSaveAsItem を呼び出します。

場所バーへの項目の追加

次の例は、[場所] バーへの項目の追加を示しています。

HRESULT AddItemsToCommonPlaces()
{
    // CoCreate the File Open Dialog object.
    IFileDialog *pfd = NULL;
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
                      NULL, 
                      CLSCTX_INPROC_SERVER, 
                      IID_PPV_ARGS(&pfd));
    if (SUCCEEDED(hr))
    {
        // Always use known folders instead of hard-coding physical file paths.
        // In this case we are using Public Music KnownFolder.
        IKnownFolderManager *pkfm = NULL;
        hr = CoCreateInstance(CLSID_KnownFolderManager, 
                      NULL, 
                      CLSCTX_INPROC_SERVER, 
                      IID_PPV_ARGS(&pkfm));
        if (SUCCEEDED(hr))
        {
            // Get the known folder.
            IKnownFolder *pKnownFolder = NULL;
            hr = pkfm->GetFolder(FOLDERID_PublicMusic, &pKnownFolder);
            if (SUCCEEDED(hr))
            {
                // File Dialog APIs need an IShellItem that represents the location.
                IShellItem *psi = NULL;
                hr = pKnownFolder->GetShellItem(0, IID_PPV_ARGS(&psi));
                if (SUCCEEDED(hr))
                {
                    // Add the place to the bottom of default list in Common File Dialog.
                    hr = pfd->AddPlace(psi, FDAP_BOTTOM);
                    if (SUCCEEDED(hr))
                    {
                        // Show the File Dialog.
                        hr = pfd->Show(NULL);
                        if (SUCCEEDED(hr))
                        {
                            //
                            // You can add your own code here to handle the results.
                            //
                        }
                    }
                    psi->Release();
                }
                pKnownFolder->Release();
            }
            pkfm->Release();
        }
        pfd->Release();
    }
    return hr;
}

状態の永続性

Windows Vista より前では、最後にアクセスしたフォルダーなどの状態がプロセスごとに保存されていました。 ただし、その情報は、特定のアクションに関係なく使用されました。 たとえば、ビデオ編集アプリケーションは、[メディアのインポート] ダイアログと同じフォルダーを [レンダリング] ダイアログに表示します。 Windows Vista では、GUID を使用してより具体的にすることができます。 ダイアログに GUID を割り当てるには、iFileDialog::SetClientGuid を呼び出します。

複数選択機能

次に示すように、GetResults メソッドを使用して、[開く] ダイアログで複数選択機能を使用できます。

HRESULT MultiselectInvoke()
{
    IFileOpenDialog *pfd;
    
    // CoCreate the dialog object.
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
                                  NULL, 
                                  CLSCTX_INPROC_SERVER, 
                                  IID_PPV_ARGS(&pfd));

    if (SUCCEEDED(hr))
    {
        DWORD dwOptions;
        // Specify multiselect.
        hr = pfd->GetOptions(&dwOptions);
        
        if (SUCCEEDED(hr))
        {
            hr = pfd->SetOptions(dwOptions | FOS_ALLOWMULTISELECT);
        }

        if (SUCCEEDED(hr))
        {
            // Show the Open dialog.
            hr = pfd->Show(NULL);

            if (SUCCEEDED(hr))
            {
                // Obtain the result of the user interaction.
                IShellItemArray *psiaResults;
                hr = pfd->GetResults(&psiaResults);
                
                if (SUCCEEDED(hr))
                {
                    //
                    // You can add your own code here to handle the results.
                    //
                    psiaResults->Release();
                }
            }
        }
        pfd->Release();
    }
    return hr;
}

ダイアログからのイベントにリッスン

呼び出しプロセスでは、次に示すように IFileDialog::Advise メソッドと IFileDialog::Unadvise メソッドを使用して、IFileDialogEvents インターフェイスをダイアログに登録できます。

これは、基本的な使用法のサンプルから取得します。

        // Create an event handling object, and hook it up to the dialog.
        IFileDialogEvents *pfde = NULL;
        hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
        if (SUCCEEDED(hr))
        {
            // Hook up the event handler.
            DWORD dwCookie;
            hr = pfd->Advise(pfde, &dwCookie);

ダイアログ処理の大部分はここに配置されます。

                // Unhook the event handler.
                pfd->Unadvise(dwCookie);
            }
            pfde->Release();
        }
        pfd->Release();
    }
    return hr;
}

呼び出しのプロセスでは、ユーザーがフォルダー、ファイルの種類、または選択を変更したときの通知にイベントを使用できます。 これらのイベントは、呼び出し元プロセスがダイアログにコントロールを追加し (「ダイアログのカスタマイズ」を参照)、これらのイベントに対応してこれらのコントロールの状態を変更する必要がある場合に特に便利です。 すべてのケースで役立つのは、呼び出しプロセスが、共有違反、ファイルの上書き、ダイアログが閉じる前にファイルが有効かどうかを判断するなどの状況に対処するカスタム コードを提供できることです。 これらのケースの一部については、このセクションで説明します。

OnFileOk

このメソッドは、ユーザーが項目を選択した後、ダイアログが閉じる直前に呼び出されます。 その後、アプリケーションは、ダイアログが閉じられたら行われるように、IFileDialog::GetResult または IFileOpenDialog::GetResults を呼び出すことができます。 選択した項目が許容される場合は、S_OK を返すことができます。 それ以外の場合は、S_FALSES_FALSE が返され、選択した項目が無効な理由をユーザーに通知する UI が表示されます。 S_FALSE が返された場合、ダイアログは閉じません。

呼び出しのプロセスでは、ダイアログ自体のウィンドウ ハンドルを UI の親として使用できます。 このハンドルを取得するには、最初に IOleWindow::QueryInterface を呼び出してから、次の例に示すように、ハンドル IOleWindow::GetWindow を呼び出します。

HRESULT CDialogEventHandler::OnFileOk(IFileDialog *pfd) 
{ 
    IShellItem *psiResult;
    HRESULT hr = pfd->GetResult(&psiResult);
    
    if (SUCCEEDED(hr))
    {
        SFGAOF attributes;
        hr = psiResult->GetAttributes(SFGAO_COMPRESSED, &attributes);
    
        if (SUCCEEDED(hr))
        {
            if (attributes & SFGAO_COMPRESSED)
            {
                // Accept the file.
                hr = S_OK;
            }
            else
            {
                // Refuse the file.
                hr = S_FALSE;
                
                _DisplayMessage(pfd, L"Not a compressed file.");
            }
        }
        psiResult->Release();
    }
    return hr;
};

HRESULT CDialogEventHandler::_DisplayMessage(IFileDialog *pfd, PCWSTR pszMessage)
{
    IOleWindow *pWindow;
    HRESULT hr = pfd->QueryInterface(IID_PPV_ARGS(&pWindow));
    
    if (SUCCEEDED(hr))
    {
        HWND hwndDialog;
        hr = pWindow->GetWindow(&hwndDialog);
    
        if (SUCCEEDED(hr))
        {
            MessageBox(hwndDialog, pszMessage, L"An error has occurred", MB_OK);
        }
        pWindow->Release();
    }
    return hr;
}

OnShareViolation と OnOverwrite

ユーザーが [保存] ダイアログでファイルを上書きすることを選択した場合、または保存または置き換えられるファイルが使用中で書き込むことができない (共有違反) 場合、アプリケーションはダイアログの既定の動作をオーバーライドするカスタム機能を提供できます。 既定では、ファイルを上書きすると、ダイアログにプロンプトが表示され、ユーザーはこのアクションを確認できます。 共有違反の場合、既定ではダイアログにエラー メッセージが表示され、閉じず、ユーザーは別の選択を行う必要があります。 呼び出し元のプロセスは、これらの既定値をオーバーライドし、必要に応じて独自の UI を表示できます。 ダイアログは、ファイルを拒否し、ファイルを開いたままにするか、ファイルを受け入れて正常に閉じるよう指示できます。

デスクトップをカスタマイズする

Win32 ダイアログ テンプレートを指定しなくても、さまざまなコントロールをダイアログに追加できます。 これらのコントロールには、PushButton、ComboBox、EditBox、CheckButton、RadioButton リスト、グループ、区切り記号、および静的テキスト コントロールが含まれます。 ダイアログ オブジェクト (IFileDialogIFileOpenDialog、または IFileSaveDialog) で QueryInterface を呼び出して、IFileDialogCustomize ポインターを取得します。 そのインターフェイスを使用してコントロールを追加します。 各コントロールには、呼び出し元が指定した ID と、 呼び出しプロセスによって設定できる表示 および 有効 な状態が関連付けられています。 PushButton などの一部のコントロールには、テキストも関連付けられています。

ダイアログのレイアウトで 1 つの単位として移動する "ビジュアル グループ" に複数のコントロールを追加できます。 グループにはラベルを関連付けることができます。

コントロールは、ダイアログが表示される前にのみ追加できます。 ただし、ダイアログが表示されると、ユーザーの操作に応じて、コントロールを非表示にしたり、必要に応じて表示したりできます。 次の例では、ラジオ ボタンリストをダイアログに追加する方法を示します。

// Controls
#define CONTROL_GROUP           2000
#define CONTROL_RADIOBUTTONLIST 2
#define CONTROL_RADIOBUTTON1    1
#define CONTROL_RADIOBUTTON2    2       // It is OK for this to have the same ID
                    // as CONTROL_RADIOBUTTONLIST, because it 
                    // is a child control under CONTROL_RADIOBUTTONLIST


// This code snippet demonstrates how to add custom controls in the Common File Dialog.
HRESULT AddCustomControls()
{
    // CoCreate the File Open Dialog object.
    IFileDialog *pfd = NULL;
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
                                  NULL, 
                                  CLSCTX_INPROC_SERVER, 
                                  IID_PPV_ARGS(&pfd));
    if (SUCCEEDED(hr))
    {
        // Create an event handling object, and hook it up to the dialog.
        IFileDialogEvents   *pfde       = NULL;
        DWORD               dwCookie    = 0;
        hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
        if (SUCCEEDED(hr))
        {
            // Hook up the event handler.
            hr = pfd->Advise(pfde, &dwCookie);
            if (SUCCEEDED(hr))
            {
                // Set up a Customization.
                IFileDialogCustomize *pfdc = NULL;
                hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
                if (SUCCEEDED(hr))
                {
                    // Create a Visual Group.
                    hr = pfdc->StartVisualGroup(CONTROL_GROUP, L"Sample Group");
                    if (SUCCEEDED(hr))
                    {
                        // Add a radio-button list.
                        hr = pfdc->AddRadioButtonList(CONTROL_RADIOBUTTONLIST);
                        if (SUCCEEDED(hr))
                        {
                            // Set the state of the added radio-button list.
                            hr = pfdc->SetControlState(CONTROL_RADIOBUTTONLIST, 
                                               CDCS_VISIBLE | CDCS_ENABLED);
                            if (SUCCEEDED(hr))
                            {
                                // Add individual buttons to the radio-button list.
                                hr = pfdc->AddControlItem(CONTROL_RADIOBUTTONLIST,
                                                          CONTROL_RADIOBUTTON1,
                                                          L"Change Title to ABC");
                                if (SUCCEEDED(hr))
                                {
                                    hr = pfdc->AddControlItem(CONTROL_RADIOBUTTONLIST,
                                                              CONTROL_RADIOBUTTON2,
                                                              L"Change Title to XYZ");
                                    if (SUCCEEDED(hr))
                                    {
                                        // Set the default selection to option 1.
                                        hr = pfdc->SetSelectedControlItem(CONTROL_RADIOBUTTONLIST,
                                                                          CONTROL_RADIOBUTTON1);
                                    }
                                }
                            }
                        }
                        // End the visual group.
                        pfdc->EndVisualGroup();
                    }
                    pfdc->Release();
                }

                if (FAILED(hr))
                {
                    // Unadvise here in case we encounter failures 
                    // before we get a chance to show the dialog.
                    pfd->Unadvise(dwCookie);
                }
            }
            pfde->Release();
        }

        if (SUCCEEDED(hr))
        {
            // Now show the dialog.
            hr = pfd->Show(NULL);
            if (SUCCEEDED(hr))
            {
                //
                // You can add your own code here to handle the results.
                //
            }
            // Unhook the event handler.
            pfd->Unadvise(dwCookie);
        }
        pfd->Release();
    }
    return hr;
}

[OK] ボタンへのオプションの追加

同様に、[開く] または [保存] ボタンにも選択肢を追加できます。これは、それぞれのダイアログの種類の [OK] ボタンです。 オプションには、ボタンに添付されたドロップダウン リスト ボックスからアクセスできます。 リストの最初の項目がボタンのテキストになります。 次の例は、"開く" と "読み取り専用で開く" の 2 つの可能性がある [開く] ボタンを指定する方法を示しています。

// OpenChoices options
#define OPENCHOICES 0
#define OPEN 0
#define OPEN_AS_READONLY 1


HRESULT AddOpenChoices()
{
    // CoCreate the File Open Dialog object.
    IFileDialog *pfd = NULL;
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
                      NULL, 
                      CLSCTX_INPROC_SERVER, 
                      IID_PPV_ARGS(&pfd));
    if (SUCCEEDED(hr))
    {
        // Create an event handling object, and hook it up to the dialog.
        IFileDialogEvents   *pfde       = NULL;
        DWORD               dwCookie    = 0;
        hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
        if (SUCCEEDED(hr))
        {
            // Hook up the event handler.
            hr = pfd->Advise(pfde, &dwCookie);
            if (SUCCEEDED(hr))
            {
                // Set up a Customization.
                IFileDialogCustomize *pfdc = NULL;
                hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
                if (SUCCEEDED(hr))
                {
                    hr = pfdc->EnableOpenDropDown(OPENCHOICES);
                    if (SUCCEEDED(hr))
                    {
                        hr = pfdc->AddControlItem(OPENCHOICES, OPEN, L"&Open");
                    }                    
                    if (SUCCEEDED(hr))
                    {
                        hr = pfdc->AddControlItem(OPENCHOICES, 
                                                OPEN_AS_READONLY, 
                                                L"Open as &read-only");
                    }
                    if (SUCCEEDED(hr))
                    {
                        pfd->Show(NULL);
                    }
                }
                pfdc->Release();
            }
            pfd->Unadvise(dwCookie);
        }
        pfde->Release();
    }
    pfd->Release();
    return hr;
}

コンボ ボックスの場合と同様に、Show メソッドからダイアログが戻った後にユーザーの選択を確認するか、IFileDialogEvents::OnFileOk によって処理の一部として検証できます。

追加されたコントロールのイベントへの応答

呼び出しのプロセスによって提供されるイベント ハンドラーは、IFileDialogEvents に加えて、IFileDialogControlEvents 実装できます。 IFileDialogControlEvents を使用すると、呼び出しプロセスは次のイベントに対応できます:

  • PushButton がクリックされました
  • CheckButton の状態が変更されました
  • メニュー、ComboBox、または RadioButton リストから選択された項目
  • コントロールがアクティブ化中です。 これは、呼び出し元のプロセスがリスト内の項目を変更する場合に、メニューがドロップダウン リストを表示しようとしているときに送信されます。

完全なのサンプル

次に、Windows ソフトウェア開発キット (SDK) からダウンロードできる完全な C++ サンプルを示します。このサンプルでは、共通項目ダイアログの使用方法と操作を示します。

IID_PPV_ARGS