Agregar un comando contextual del Explorador de archivos a una aplicación de escritorio empaquetada

Windows 11 aplicaciones amplían el menú contextual del Explorador de archivos moderno mediante la implementación de IExplorerCommand y el registro del comando con la identidad de la aplicación. Esto se aplica a las aplicaciones de escritorio empaquetadas y a las aplicaciones Win32 sin empaquetar que usan un paquete disperso.

Una asociación de tipo de archivo puede hacer que una aplicación esté disponible en Open con o agregue un verbo de edición para un tipo de archivo que controla la aplicación. No proporciona la extensión de menú contextual de uso general descrita en este artículo. Para agregar un comando para archivos, carpetas o fondos arbitrarios de carpetas, use IExplorerCommand.

Para consultar el diseño del menú contextual de Windows 11 y obtener orientación sobre cuándo agregar un comando, consulte Extensión del menú contextual y del cuadro de diálogo Compartir en Windows 11.

Funcionamiento de las extensiones de menú contextual

Una extensión de menú contextual tiene estas partes:

  1. Un archivo DLL nativo implementa una o varias clases COM que exponen IExplorerCommand.
  2. El manifiesto del paquete registra cada clase COM como una windows.comServer extensión.
  3. El manifiesto del paquete registra el comando como una windows.fileExplorerContextMenus extensión y asocia un tipo de elemento de shell al CLSID de la clase COM.

El Explorador de archivos activa la clase COM cuando compila el menú contextual. La IExplorerCommand implementación proporciona el título, el icono, el estado y la acción. Los comandos de la misma aplicación se pueden agrupar en un menú flotante asociado a la aplicación; implemente EnumSubCommands para proporcionar comandos secundarios.

Importante

El Explorador de archivos carga el código de la extensión del shell como parte de la experiencia del shell. Mantén la rapidez de GetTitle, GetIcon, GetState y otros métodos de construcción de menús. No realice operaciones costosas en la interfaz de usuario del Explorador de archivos. Ejecute operaciones de mayor duración después de que se llame a Invoke.

Implementación de IExplorerCommand

Implemente IExplorerCommand en un archivo DLL COM nativo. C++ es la opción habitual porque el comando se ejecuta en la ruta de integración del intérprete de comandos. La siguiente implementación abreviada proporciona un título de comando, habilita el comando y recibe los elementos seleccionados cuando el usuario lo invoca.

class EditCommand final : public IExplorerCommand
{
public:
    IFACEMETHODIMP GetTitle(IShellItemArray*, PWSTR* title)
    {
        return SHStrDup(L"Edit with Contoso", title);
    }

    IFACEMETHODIMP GetState(
        IShellItemArray*, BOOL, EXPCMDSTATE* state)
    {
        *state = ECS_ENABLED;
        return S_OK;
    }

    IFACEMETHODIMP Invoke(IShellItemArray* items, IBindCtx*)
    {
        // Obtain selected items from items and start the app or operation.
        return S_OK;
    }

    IFACEMETHODIMP GetIcon(IShellItemArray*, PWSTR* icon)
    {
        return SHStrDup(L"ContosoCommand.dll,-101", icon);
    }

    IFACEMETHODIMP GetToolTip(IShellItemArray*, PWSTR* tooltip)
    {
        *tooltip = nullptr;
        return E_NOTIMPL;
    }

    IFACEMETHODIMP GetCanonicalName(GUID* canonicalName)
    {
        *canonicalName = GUID_NULL;
        return S_OK;
    }

    IFACEMETHODIMP GetFlags(EXPCMDFLAGS* flags)
    {
        *flags = ECF_DEFAULT;
        return S_OK;
    }

    IFACEMETHODIMP EnumSubCommands(IEnumExplorerCommand** commands)
    {
        *commands = nullptr;
        return E_NOTIMPL;
    }
};

Use el IShellItemArray pasado a Invoke para enumerar la selección actual. GetState puede devolver estados como ECS_HIDDEN, ECS_DISABLEDo ECS_ENABLED para controlar si el comando aparece y se puede seleccionar. Para obtener el contrato completo, consulte IExplorerCommand.

Asigne la clase COM a CLSID y asegúrese de que se usa el mismo CLSID en el manifiesto del paquete. Por ejemplo:

class __declspec(uuid("01234567-89AB-CDEF-0123-456789ABCDEF"))
    EditCommand;

Registro del comando en el manifiesto del paquete

Declare los espacios de nombres com, desktop4 y desktop5 en el elemento raíz Package y agréguelos a IgnorableNamespaces.

<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
  xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
  IgnorableNamespaces="com desktop4 desktop5">
  <!-- ... -->
</Package>

En el elemento de aplicación Extensions , primero registre el archivo DLL como servidor COM. com:Class/@Id es el CLSID del comando y Path es la ruta relativa al paquete del archivo DLL.

<com:Extension Category="windows.comServer">
  <com:ComServer>
    <com:SurrogateServer DisplayName="Contoso commands">
      <com:Class
        Id="01234567-89AB-CDEF-0123-456789ABCDEF"
        Path="ContosoCommand.dll"
        ThreadingModel="STA" />
    </com:SurrogateServer>
  </com:ComServer>
</com:Extension>

A continuación, asocie el CLSID con el contexto en el que debe aparecer el comando.

<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop4:FileExplorerContextMenus>
    <desktop5:ItemType Type="*">
      <desktop5:Verb
        Id="EditWithContoso"
        Clsid="01234567-89AB-CDEF-0123-456789ABCDEF" />
    </desktop5:ItemType>
  </desktop4:FileExplorerContextMenus>
</desktop4:Extension>

desktop5:ItemType/@Type identifica los elementos del shell de destino. Use * para archivos, Directory para carpetas seleccionadas o Directory\Background para el fondo de una carpeta. Puede registrar varias ItemType entradas para el mismo CLSID cuando un comando admite varios contextos.

El desktop5:Verb/@Id identifica el registro del manifiesto. desktop5:Verb/@Clsid debe coincidir con el valor de com:Class/@Id y con el CLSID de la clase COM.

Para obtener el esquema de manifiesto completo, consulte desktop4:FileExplorerContextMenus y com:Class.

Empaquetar el archivo DLL

Incluya la DLL del comando y todos los recursos que necesite en el paquete, en la ruta de acceso especificada por com:Class/@Path. Si usa un proyecto de empaquetado de aplicaciones de Windows, agregue el archivo DLL al proyecto y configúrelo para que se copie en la salida del paquete. Configure una dependencia de compilación o una copia posterior a la compilación para que el paquete contenga el archivo DLL actual.

La arquitectura DLL debe coincidir con la arquitectura del Explorador de archivos que la carga. Compile y empaquete la arquitectura adecuada para el dispositivo de destino.

Uso de un paquete disperso para una aplicación sin empaquetar

Una aplicación Win32 sin empaquetar puede usar los mismos registros de manifiesto y IExplorerCommand mediante la instalación de un paquete disperso que otorga a la aplicación una identidad de paquete. Un paquete disperso no contiene los archivos binarios de la aplicación; hace referencia a la aplicación instalada externamente en su lugar.

Además de las extensiones com y de menú contextual mostradas anteriormente, un manifiesto de paquete disperso normalmente declara uap10:AllowExternalContent y configura la aplicación como una aplicación Win32. En el ejemplo siguiente se muestran las declaraciones de paquetes dispersos pertinentes.

<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap10 rescap">

  <Properties>
    <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
  </Properties>

  <Applications>
    <Application
      Id="ContosoApp"
      Executable="ContosoApp.exe"
      uap10:TrustLevel="mediumIL"
      uap10:RuntimeBehavior="win32App">
      <!-- VisualElements and the COM/context-menu Extensions go here. -->
    </Application>
  </Applications>

  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <rescap:Capability Name="unvirtualizedResources" />
  </Capabilities>
</Package>

Consulte Paquetes dispersos para conocer los requisitos de empaquetado y registro de las aplicaciones sin empaquetar.

Prueba de la extensión

Instale o registre el paquete y, a continuación, abra el Explorador de archivos y haga clic con el botón derecho en un elemento que coincida con uno de los tipos de elementos registrados. Si el comando no aparece después de instalar o actualizar un paquete, reinicie el Explorador de archivos o cierre la sesión y vuelva a iniciarla para que el shell vuelva a cargar el registro de la extensión.

Use Mostrar más opciones solo para inspeccionar las extensiones heredadas del menú contextual. Un comando registrado mediante windows.fileExplorerContextMenus e implementado con IExplorerCommand aparece en el menú contextual de Windows 11.

Asociaciones de tipo de archivo

Registre una asociación de tipo de archivo cuando la aplicación se abra o edite ese tipo de archivo. Puede hacer que la aplicación esté disponible a través de Open with y puede agregar un verbo de edición para los tipos de archivo asociados. Use el mecanismo de menú contextual de este artículo para los comandos que se aplican a archivos genéricos, carpetas o fondos, o para comandos que realizan operaciones sin abrir la experiencia normal de apertura de archivos de la aplicación.