Caixa de diálogo Item comum

A partir do Windows Vista, a caixa de diálogo Item Comum substitui a antiga caixa de diálogo Arquivo Comum quando usada para abrir ou salvar um arquivo. A caixa de diálogo Item comum é usada em duas variações: a caixa de diálogo Abrir e a caixa de diálogo Salvar. Essas duas caixas de diálogo compartilham a maior parte de suas funcionalidades, mas cada uma tem seus próprios métodos exclusivos.

Embora essa versão mais recente seja chamada de caixa de diálogo Item Comum, ela continua a ser chamada de caixa de diálogo Arquivo Comum na maior parte da documentação. A menos que você esteja lidando especificamente com uma versão mais antiga do Windows, você deve presumir que qualquer menção à caixa de diálogo Arquivo Comum se refere a esta caixa de diálogo Item Comum.

Os tópicos a seguir são discutidos aqui:

IFileDialog, IFileOpenDialog e IFileSaveDialog

O Windows Vista fornece implementações das caixas de diálogo Abrir e Salvar: CLSID_FileOpenDialog e CLSID_FileSaveDialog. Essas caixas de diálogo são mostradas aqui.

screen shot of the open dialog box

screen shot of the save as dialog box

IFileOpenDialog e IFileSaveDialog herdam de IFileDialog e compartilham grande parte de sua funcionalidade. Além disso, a caixa de diálogo Abrir dá suporte a IFileOpenDialog e a caixa de diálogo Salvar dá suporte a IFileSaveDialog.

A implementação da caixa de diálogo Item Comum encontrada no Windows Vista fornece várias vantagens em relação à implementação fornecida nas versões anteriores:

  • Dá suporte ao uso direto do namespace do Shell por meio do IShellItem, em vez de usar os caminhos do sistema de arquivos.
  • Permite a personalização simples da caixa de diálogo, como a configuração do rótulo no botão OK, sem a necessidade de um procedimento de gancho.
  • Dá suporte à personalização mais extensa da caixa de diálogo pela adição de um conjunto de controles controlados por dados que operam sem um modelo de caixa de diálogo Win32. Esse esquema de personalização libera o processo de chamada do layout da interface do usuário. Como as alterações no design da caixa de diálogo continuam a usar esse modelo de dados, a implementação da caixa de diálogo não está vinculada à versão atual específica da caixa de diálogo.
  • Dá suporte à notificação do chamador de eventos dentro da caixa de diálogo, como alteração de seleção ou alteração de tipo de arquivo. Também permite que o processo de chamada conecte determinados eventos na caixa de diálogo, como a análise.
  • Introduz novos recursos da caixa de diálogo, como a adição de locais especificados pelo chamador, à barra Locais.
  • Na caixa de diálogo Salvar, os desenvolvedores podem aproveitar os novos recursos de metadados do Shell do Windows Vista.

Além disso, os desenvolvedores podem implementar as seguintes interfaces:

A caixa de diálogo Abrir ou Salvar retorna um objeto IShellItem ou IShellItemArray para o processo de chamada. O chamador pode usar um objeto IShellItem individual para obter um caminho do sistema de arquivos ou para abrir um fluxo no item para ler ou gravar informações.

Os sinalizadores e as opções disponíveis para os novos métodos da caixa de diálogo são muito semelhantes aos sinalizadores OFN mais antigos encontrados na estrutura OPENFILENAME e usados em GetOpenFileName e GetSaveFileName. Muitos deles são exatamente iguais, exceto pelo fato de que começam com o prefixo FOS. A lista completa pode ser encontrada nos tópicos IFileDialog::GetOptions e IFileDialog::SetOptions. As caixas de diálogo Abrir e Salvar são criadas por padrão com os sinalizadores mais comuns. Para a caixa de diálogo Abrir, é (FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR), e para a caixa de diálogo Salvar, é (FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR).

IFileDialog e suas interfaces descendentes herdam e estendem IModalWindow. Show usa como único parâmetro o identificador da janela pai. Se Show retornar com êxito, haverá um resultado válido. Se retornar HRESULT_FROM_WIN32(ERROR_CANCELLED), significa que o usuário cancelou a caixa de diálogo. Ele também pode retornar legitimamente outro código de erro, como E_OUTOFMEMORY.

Exemplo de uso

As seções a seguir mostram o código de exemplo para várias tarefas de diálogo.

A maior parte do código de exemplo pode ser encontrada no exemplo de caixa de diálogo Arquivo Comum do SDK do Windows.

Uso básico

O exemplo a seguir ilustra como iniciar a caixa de diálogo Abrir. Neste exemplo, ela é restrita aos documentos do Microsoft Word.

Observação

Vários exemplos neste tópico usam a função auxiliar CDialogEventHandler_CreateInstance para criar uma instância da implementação IFileDialogEvents. Para usar essa função no seu próprio código, copie o código-fonte da função CDialogEventHandler_CreateInstance do exemplo de caixa de diálogo Arquivo Comum, em que os exemplos neste tópico são obtidos.

 

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;
}

Como limitar os resultados a itens do sistema de arquivos

O exemplo a seguir, retirado do exemplo acima, demonstra como restringir os resultados aos itens do sistema de arquivos. Observe que o IFileDialog::SetOptions adiciona o novo sinalizador a um valor obtido por meio do IFileDialog::GetOptions. Esse é o método recomendado.

                // 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);

Como especificar os tipos de arquivo de uma caixa de diálogo

Para definir os tipos de arquivo específicos que a caixa de diálogo pode manipular, use o método IFileDialog::SetFileTypes. Esse método aceita uma matriz das estruturas COMDLG_FILTERSPEC, dentre as quais, cada uma representa um tipo de arquivo.

O mecanismo de extensão padrão em uma caixa de diálogo é inalterado de GetOpenFileName e GetSaveFileName. A extensão de nome de arquivo anexada ao texto que o usuário digita na caixa de edição de nome de arquivo é inicializada quando a caixa de diálogo é aberta. Ela deve corresponder ao tipo de arquivo padrão (selecionado quando a caixa de diálogo é aberta). Se o tipo de arquivo padrão for "*.*" (todos os arquivos), o arquivo poderá ser uma extensão da sua escolha. Se o usuário escolher um tipo de arquivo diferente, a extensão será atualizada automaticamente para a primeira extensão de nome de arquivo associada a esse tipo de arquivo. Se o usuário escolher "*.*" (todos os arquivos), a extensão será revertida para seu valor original.

O exemplo a seguir ilustra como isso foi feito acima.

                        // 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");

Como controlar a pasta padrão

Quase qualquer pasta no namespace do Shell pode ser usada como a pasta padrão da caixa de diálogo (a pasta apresentada quando o usuário escolhe abrir ou salvar um arquivo). Chame IFileDialog::SetDefaultFolder antes de chamar Show para fazer isso.

A pasta padrão é a pasta na qual a caixa de diálogo é iniciada na primeira vez que um usuário a abre no seu aplicativo. Depois disso, a caixa de diálogo será aberta na última pasta que um usuário abriu ou na última pasta que ele usou para salvar um item. Confira Persistência de Estado para obter mais detalhes.

Você pode forçar a caixa de diálogo a mostrar sempre a mesma pasta quando ela for aberta, independentemente da ação anterior do usuário, chamando IFileDialog::SetFolder. No entanto, não recomendamos fazer isso. Se você chamar SetFolder antes de exibir a caixa de diálogo, o local mais recente em que o usuário salvou ou abriu não será mostrado. A menos que haja uma razão muito específica para esse comportamento, essa não é uma experiência de usuário adequada ou esperada e deve ser evitada. Em quase todos os casos, IFileDialog::SetDefaultFolder é o melhor método.

Ao salvar um documento pela primeira vez na caixa de diálogo Salvar, você deve seguir as mesmas diretrizes para determinar a pasta inicial como fez na caixa de diálogo Abrir. Se o usuário estiver editando um documento já existente, abra a caixa de diálogo na pasta em que esse documento está armazenado e preencha a caixa de edição com o nome desse documento. Chame IFileSaveDialog::SetSaveAsItem com o item atual antes de chamar Show.

Como adicionar itens à barra Locais

O exemplo a seguir demonstra a adição de itens à barra Locais:

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;
}

Persistência de Estado

Antes do Windows Vista, um estado, como a última pasta visitada, era salvo por processo. No entanto, essa informação foi usada independentemente da ação específica. Por exemplo, um aplicativo de edição de vídeo apresentaria a mesma pasta na caixa de diálogo Renderizar como que apresentaria na caixa de diálogo Importar mídia. No Windows Vista, você pode ser mais específico usando GUIDs. Para atribuir um GUID à caixa de diálogo, chame iFileDialog::SetClientGuid.

Recursos de Seleção Múltipla

A funcionalidade de seleção múltipla está disponível na caixa de diálogo Abrir usando o método GetResults, conforme mostrado aqui.

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;
}

Como escutar eventos da caixa de diálogo

Um processo de chamada pode registrar uma interface IFileDialogEvents com a caixa de diálogo usando os métodos IFileDialog::Advise e IFileDialog::Unadvise, conforme mostrado aqui.

Isso é retirado do exemplo de Uso Básico.

        // 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);

A maior parte do processamento da caixa de diálogo seria colocada aqui.

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

O processo de chamada pode usar eventos para notificação quando o usuário altera a pasta, o tipo de arquivo ou a seleção. Esses eventos são particularmente úteis quando o processo de chamada adiciona controles à caixa de diálogo (confira Como personalizar a caixa de diálogo) e devem alterar o estado desses controles em reação a esses eventos. Em todos os casos é útil ter a capacidade do processo de chamada de fornecer código personalizado para lidar com situações como violações de compartilhamento, substituição de arquivos ou determinar se um arquivo é válido antes do fechamento da caixa de diálogo. Alguns desses casos são descritos nesta seção.

OnFileOk

Esse método é chamado depois que o usuário escolhe um item, pouco antes do fechamento da caixa de diálogo. O aplicativo pode então chamar IFileDialog::GetResult ou IFileOpenDialog::GetResults como seria feito depois que a caixa de diálogo fosse fechada. Se o item escolhido for aceitável, eles podem retornar S_OK. Caso contrário, eles retornarão S_FALSE e exibirão a interface do usuário que informa ao usuário por que o item escolhido não é válido. Se S_FALSE for retornado, a caixa de diálogo não será fechada.

O processo de chamada pode usar o identificador de janela da própria caixa de diálogo como o pai da interface do usuário. Esse identificador pode ser obtido chamando primeiro IOleWindow::QueryInterface e, em seguida, chamando IOleWindow::GetWindow com o identificador, conforme mostrado neste exemplo.

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 e OnOverwrite

Se o usuário substituir um arquivo na caixa de diálogo Salvar ou se um arquivo que está sendo salvo ou substituído estiver em uso e não puder ser gravado (uma violação de compartilhamento), o aplicativo poderá fornecer a funcionalidade personalizada para substituir o comportamento padrão da caixa de diálogo. Por padrão, ao substituir um arquivo, a caixa de diálogo exibe um prompt permitindo que o usuário verifique essa ação. Para violações de compartilhamento, por padrão, a caixa de diálogo exibe uma mensagem de erro, ela não fecha e o usuário é obrigado a fazer outra escolha. O processo de chamada pode substituir esses padrões e exibir sua própria interface do usuário, se desejado. A caixa de diálogo pode ser instruída a recusar o arquivo e permanecer aberta ou aceitar o arquivo e fechar.

Como personalizar a caixa de diálogo

Uma variedade de controles pode ser adicionada à caixa de diálogo sem fornecer um modelo de caixa de diálogo Win32. Esses controles incluem os controles PushButton, ComboBox, EditBox, CheckButton, RadioButton, Groups, Separators e Static Text. Chame QueryInterface no objeto de da caixa diálogo (IFileDialog, IFileOpenDialog ou IFileSaveDialog) para obter um ponteiro IFileDialogCustomiz. Use essa interface para adicionar os controles. Cada controle tem uma ID fornecida pelo chamador associado, bem como um estado visível e habilitado que pode ser definido pelo processo de chamada. Alguns controles, como PushButton, também têm um texto associado.

Vários controles podem ser adicionados a um "grupo visual" que se move como uma única unidade no layout da caixa de diálogo. Os grupos podem ter um rótulo associado.

Os controles podem ser adicionados somente antes que a caixa de diálogo seja exibida. No entanto, uma vez que a caixa de diálogo é exibida, os controles podem ser ocultos ou mostrados como desejado, talvez em resposta à ação do usuário. Os exemplos a seguir mostram como adicionar uma lista de botões de opção à caixa de diálogo.

// 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;
}

Como adicionar opções ao botão OK

Da mesma forma, as opções podem ser adicionadas aos botões Abrir ou Salvar, que são o botão OK dos respectivos tipos de caixa de diálogo. As opções são acessíveis através de uma caixa de listagem suspensa anexada ao botão. O primeiro item da lista torna-se o texto do botão. O exemplo a seguir mostra como fornecer um botão Abrir com duas possibilidades: "Abrir" e "Abrir como somente leitura".

// 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;
}

A escolha do usuário pode ser verificada depois que a caixa de diálogo retorna do método Show, como você faria para um ComboBox, ou pode ser verificada como parte da manipulação de IFileDialogEvents::OnFileOk.

Como responder a eventos nos controles adicionados

O manipulador de eventos fornecido pelo processo de chamada pode implementar IFileDialogControlEvents, além de IFileDialogEvents. IFileDialogControlEvents permite que o processo de chamada reaja a estes eventos:

  • PushButton clicado
  • Estado do CheckButton alterado
  • Item selecionado em um menu, ComboBox ou lista RadioButton
  • Ativação de controle. Isso é enviado quando um menu está prestes a exibir uma lista suspensa, caso o processo de chamada queira alterar os itens na lista.

Amostras Completas

Veja a seguir exemplos completos de C++ para download no SDK do Windows que demonstram o uso e a interação com a caixa de diálogo Item Comum.

IID_PPV_ARGS