Cuadro de diálogo Elemento común

A partir de Windows Vista, el cuadro de diálogo Elemento común sustituye al antiguo cuadro de diálogo Archivo común cuando se utiliza para abrir o guardar un archivo. El cuadro de diálogo Elemento común se usa en dos variaciones: el cuadro de diálogo Abrir y el cuadro de diálogo Guardar. Estos dos cuadros de diálogos comparten la mayor parte de su funcionalidad, pero cada uno tiene sus propios métodos únicos.

Aunque esta nueva versión se denomina cuadro de diálogo de elementos comunes, sigue llamándose cuadro de diálogo de archivos comunes en la mayor parte de la documentación. A menos que esté tratando específicamente con una versión antigua de Windows, debe asumir que cualquier mención del cuadro de diálogo Archivo común se refiere a este cuadro de diálogo Elemento común.

Aquí se describen los siguientes temas:

IFileDialog, IFileOpenDialog e IFileSaveDialog

Windows Vista proporciona implementaciones de los cuadros de diálogo Abrir y Guardar: CLSID_FileOpenDialog y CLSID_FileSaveDialog. Estos cuadros de diálogo se muestran aquí.

screen shot of the open dialog box

screen shot of the save as dialog box

IFileOpenDialog e IFileSaveDialog heredan de IFileDialog y comparten gran parte de su funcionalidad. Además, el cuadro de diálogo Abrir es compatible con IFileOpenDialog, y el cuadro de diálogo Guardar es compatible con IFileSaveDialog.

La implementación del cuadro de diálogo de elemento común que se encuentra en Windows Vista proporciona varias ventajas sobre la implementación proporcionada en versiones anteriores:

  • Admite el uso directo del espacio de nombres Shell a través de IShellItem en lugar de utilizar rutas del sistema de archivos.
  • Permite una personalización sencilla del cuadro de diálogo, como establecer la etiqueta del botón Aceptar, sin necesidad de un procedimiento de enlace.
  • Admite una personalización más amplia del cuadro de diálogo mediante la adición de un conjunto de controles controlados por datos que funcionan sin una plantilla de cuadro de diálogo Win32. Este esquema de personalización libera el proceso de llamada desde el diseño de la interfaz de usuario. Dado que los cambios en el diseño del cuadro de diálogo siguen usando este modelo de datos, la implementación del diálogo no está vinculada a la versión actual específica del cuadro de diálogo.
  • Admite la notificación a la persona que llama de eventos dentro del diálogo, como el cambio de selección o el cambio de tipo de archivo. También permite que el proceso de llamada enlace determinados eventos en el cuadro de diálogo, como el análisis.
  • Presenta nuevas funciones de diálogo, como agregar lugares especificados por el autor de la llamada a la barra de Lugares.
  • En el cuadro de diálogo Guardar, los desarrolladores pueden aprovechar las nuevas características de metadatos del Shell de Windows Vista.

Además, los desarrolladores pueden optar por implementar las siguientes interfaces:

El cuadro de diálogo Abrir o Guardar devuelve un objeto IShellItem o IShellItemArray al proceso de llamada. El autor de la llamada puede entonces utilizar un objeto IShellItem individual para obtener una ruta del sistema de archivos o para abrir un flujo en el elemento para leer o escribir información.

Los indicadores y opciones disponibles para los nuevos métodos de cuadro de diálogo son muy similares a los antiguos indicadores OFN que se encuentran en la estructura OPENFILENAME y se utilizan en GetOpenFileName y GetSaveFileName. Muchos de ellos son exactamente iguales, excepto que comienzan con un prefijo FOS. La lista completa se puede encontrar en los temas IFileDialog::GetOptions and IFileDialog::SetOptions. Los cuadros de diálogo Abrir y Guardar se crean de forma predeterminada con las marcas más comunes. Para el cuadro de diálogo Abrir, es (FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR) y para el cuadro de diálogo Guardar es (FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR).

IFileDialog y sus interfaces descendientes heredan y extienden de IModalWindow. Show toma como único parámetro el controlador de la ventana primaria. Si Show devuelve éxito, hay un resultado válido. Si devuelve HRESULT_FROM_WIN32(ERROR_CANCELLED), significa que el usuario canceló el cuadro de diálogo. También podría devolver legítimamente otro código de error, como E_OUTOFMEMORY.

Ejemplo de uso

Las siguientes secciones muestran ejemplos de código para diversas tareas de cuadro de diálogo.

La mayor parte del código de ejemplo se puede encontrar en el ejemplo de cuadro de diálogo de archivo común de Windows SDK.

Uso básico

En el siguiente ejemplo se muestra cómo iniciar un cuadro de diálogo Abrir. En este ejemplo, se limita a los documentos de Microsoft Word.

Nota:

Varios ejemplos de este tema utilizan la función auxiliar CDialogEventHandler_CreateInstance para crear una instancia de la implementación de IFileDialogEvents. Para usar esta función en su propio código, copie el código fuente de la función CDialogEventHandler_CreateInstance del ejemplo de cuadro de diálogo de archivos comunes, desde el que se toman todos los ejemplos de este tema.

 

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

Limitar los resultados a los elementos del sistema de archivos

El siguiente ejemplo, tomado de arriba, demuestra cómo restringir los resultados a los elementos del sistema de archivos. Tenga en cuenta que IFileDialog::SetOptions agrega la nueva marca a un valor obtenido a través de IFileDialog::GetOptions. Éste es el 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);

Especificar tipos de archivo para un cuadro de diálogo

Para establecer tipos de archivo específicos que el cuadro de diálogo puede controlar, use el método IFileDialog::SetFileTypes. Este método acepta una matriz de estructuras COMDLG_FILTERSPEC, cada una de las cuales representa un tipo de archivo.

El mecanismo de extensión predeterminado en un cuadro de diálogo no cambia con respecto a GetOpenFileName y GetSaveFileName. La extensión del nombre de archivo que se agrega al texto que el usuario escribe en el cuadro de edición del nombre de archivo se inicializa cuando se abre el cuadro de diálogo. Debe coincidir con el tipo de archivo predeterminado (que se ha seleccionado como se abre el cuadro de diálogo). Si el tipo de archivo predeterminado es "*.*" (todos los archivos), el archivo puede ser una extensión de su elección. Si el usuario elige un tipo de archivo diferente, la extensión se actualiza automáticamente a la primera extensión de nombre de archivo asociada a ese tipo de archivo. Si el usuario elige "*.*" (todos los archivos), la extensión vuelve a su valor original.

En el siguiente ejemplo se muestra cómo se ha hecho anteriormente.

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

Controlar la carpeta predeterminada

Casi cualquier carpeta del espacio de nombres Shell puede utilizarse como carpeta predeterminada para el cuadro de diálogo (la carpeta que se presenta cuando el usuario elige abrir o guardar un archivo). Llame a IFileDialog::SetDefaultFolder antes de llamar a Show para hacerlo.

La carpeta predeterminada es la carpeta en la que el cuadro de diálogo se inicia la primera vez que un usuario lo abre desde la aplicación. Después, el cuadro de diálogo se abrirá en la última carpeta que haya abierto el usuario o en la última carpeta que haya utilizado para guardar un elemento. Consulte Persistencia de estado para obtener más detalles.

Puede forzar que el diálogo muestre siempre la misma carpeta cuando se abra, independientemente de la acción previa del usuario, llamando a IFileDialog::SetFolder. Sin embargo, no se recomienda hacerlo. Si llama a SetFolder antes de mostrar el cuadro de diálogo, no se mostrará la ubicación más reciente en la que el usuario guardó o desde la que abrió. A menos que haya una razón muy específica para este comportamiento, no es una experiencia de usuario buena o esperada y debe evitarse. En casi todas las instancias, IFileDialog::SetDefaultFolder es el mejor método.

Al guardar un documento por primera vez en el cuadro de diálogo Guardar, debe seguir las mismas directrices para determinar la carpeta inicial que hizo en el cuadro de diálogo Abrir. Si el usuario está editando un documento ya existente, abra el cuadro de diálogo en la carpeta donde está almacenado ese documento y rellene el cuadro de edición con el nombre de ese documento. Llame a IFileSaveDialog::SetSaveAsItem con el elemento actual antes de llamar Show.

Agregar elementos a la barra Lugares

En el siguiente ejemplo se muestra la adición de elementos a la barra Lugares:

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

Persistencia de estado

Antes de Windows Vista, un estado, como la última carpeta visitada, se guardaba por proceso. Sin embargo, esa información se usó independientemente de la acción concreta. Por ejemplo, una aplicación de edición de vídeo presentaría la misma carpeta en el cuadro de diálogo Renderizar como que en el cuadro de diálogo Importar medios. En Windows Vista puede ser más específico mediante el uso de GUID. Para asignar un GUID al cuadro de diálogo, llame a iFileDialog::SetClientGuid.

Funcionalidades de selección múltiple

La funcionalidad multiselección está disponible en el cuadro de diálogo Abrir utilizando el método GetResults como se muestra aquí.

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

Escuchar eventos desde el cuadro de diálogo

Un proceso de llamada puede registrar una interfaz IFileDialogEvents con el cuadro de diálogo mediante los métodos IFileDialog::Advise e IFileDialog::Unadvise como se muestra aquí.

Esto se toma del ejemplo 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);

La mayor parte del procesamiento del cuadro de diálogo se situaría aquí.

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

El proceso de llamada puede usar eventos para la notificación cuando el usuario cambia la carpeta, el tipo de archivo o la selección. Estos eventos son especialmente útiles cuando el proceso de llamada ha agregado controles al cuadro de diálogo (vea Personalizar el cuadro de diálogo) y debe cambiar el estado de esos controles en reacción a estos eventos. Útil en todos los casos es la capacidad del proceso de llamada para proporcionar código personalizado para hacer frente a situaciones tales como infracciones de uso compartido, sobrescribir archivos, o determinar si un archivo es válido antes de que se cierre el cuadro de diálogo. Algunos de esos casos se describen en esta sección.

OnFileOk

Este método se ejecuta después de que el usuario elija un elemento, justo antes de que se cierre el cuadro de diálogo. A continuación, la aplicación puede llamar a IFileDialog::GetResult o IFileOpenDialog::GetResults como se haría una vez cerrado el cuadro de diálogo. Si el elemento elegido es aceptable, pueden devolver S_OK. En caso contrario, devuelven S_FALSE y muestran una interfaz de usuario que indica al usuario por qué el elemento elegido no es válido. Si se devuelve S_FALSE, el cuadro de diálogo no se cierra.

El proceso de llamada puede utilizar el controlador de ventana del propio diálogo como elemento primario de la interfaz de usuario. Ese controlador se puede obtener llamando primero a IOleWindow::QueryInterface y luego llamando a IOleWindow::GetWindow con el controlador como se muestra en este ejemplo.

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

Si el usuario decide sobrescribir un archivo en el cuadro de diálogo Guardar, o si un archivo que se está guardando o reemplazando está en uso y no se puede escribir en él (una infracción de uso compartido), la aplicación puede proporcionar funciones personalizadas para invalidar el comportamiento predeterminado del cuadro de diálogo. De forma predeterminada, al sobrescribir un archivo, el cuadro de diálogo muestra un mensaje que permite al usuario comprobar esta acción. En el caso de las infracciones de uso compartido, de forma predeterminada el cuadro de diálogo muestra un mensaje de error, no se cierra y se pide al usuario que haga otra elección. El proceso de llamada puede invalidar estos valores predeterminados y mostrar su propia interfaz de usuario si lo desea. Se puede indicar al cuadro de diálogo que rechace el archivo y permanezca abierto o que lo acepte y se cierre correctamente.

Personalización del cuadro de diálogo

Se puede agregar una variedad de controles al cuadro de diálogo sin proporcionar una plantilla de diálogo Win32. Estos controles incluyen controles PushButton, ComboBox, EditBox, CheckButton, Listas de RadioButton, Grupos, Separadores y Texto estático. Llama a QueryInterface en el objeto de diálogo (IFileDialog, IFileOpenDialog o IFileSaveDialog) para obtener un puntero IFileDialogCustomize. Use esa interfaz para agregar controles. Cada control tiene asociado un Id. proporcionado por el autor de la llamada, así como un estado visible y habilitado que puede ser establecido por el proceso de llamada. Algunos controles, como PushButton, también tienen texto asociado a ellos.

Se pueden agregar varios controles en un "grupo visual" que se desplaza como una sola unidad en el diseño del cuadro de diálogo. Los grupos pueden tener una etiqueta asociada a ellos.

Los controles solo se pueden agregar antes de que se muestre el cuadro de diálogo. Sin embargo, una vez que se muestra el cuadro de diálogo, los controles pueden ocultarse o mostrarse según se desee, quizás en respuesta a una acción del usuario. Los siguientes ejemplos muestran cómo agregar una lista de botones de opción al cuadro 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;
}

Agregar opciones al botón Aceptar

De forma similar, se pueden agregar opciones a los botones Abrir o Guardar, que son el botón Aceptar para sus respectivos tipos de diálogo. Las opciones son accesibles a través de un cuadro de lista desplegable adjunto al botón. El primer elemento de la lista se convierte en el texto del botón. En el ejemplo siguiente se muestra cómo proporcionar un botón Abrir con dos posibilidades: "Abrir" y "Abrir como solo lectura".

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

La opción del usuario se puede comprobar después de que el cuadro de diálogo vuelva del método Show como lo haría para un ComboBox, o bien puede comprobarse como parte del control por IFileDialogEvents::OnFileOk.

Responder a eventos en controles agregados

El controlador de eventos proporcionado por el proceso de llamada puede implementar IFileDialogControlEvents además de IFileDialogEvents. IFileDialogControlEvents permite que el proceso de llamada reaccione a estos eventos:

  • PushButton en el que se hace clic
  • Estado checkButton cambiado
  • Elemento seleccionado en un menú, ComboBox o lista RadioButton
  • Controlar la activación. Se envía cuando un menú está a punto de mostrar una lista desplegable, en caso de que el proceso de llamada quiera cambiar los elementos de la lista.

Ejemplos completos

Los siguientes son ejemplos C++ completos y descargables del kit de desarrollo de software (SDK) de Windows que demuestran el uso y la interacción con el cuadro de diálogo de elementos comunes.

IID_PPV_ARGS