El estado actual de la integración con el shell de Windows — el menú contextual, la asociación de archivos y los cambios de Windows 11
· Actualizado el: · Go Komura · Windows, Extensiones de shell, Menú contextual, Asociación de archivos, COM, Windows 11, Explorador de archivos, MSIX, Desarrollo para Windows
En una consulta nos contaron: «Al cambiar a un PC con Windows 11, el menú contextual de la aplicación que ustedes nos hicieron hace tiempo dejó de aparecer». Al preguntar más a fondo, resultó que no había desaparecido. Al hacer clic derecho sobre un archivo y elegir «Mostrar más opciones», al final del menú, aparecía el menú de siempre tal cual. Es decir, el elemento del menú de su aplicación había quedado escondido un paso más adentro. Desde el propio negocio nos llegaron comentarios como «ahora hace falta un clic más» y «han aumentado las consultas de la gente que no encuentra la opción».
Esto no es una avería ni un error de configuración, sino un cambio de diseño de Windows 11. El menú contextual del Explorador pasó a tener una estructura dual, nueva y antigua, y las condiciones para que un elemento aparezca en el nuevo menú son completamente distintas de las de antes.
Por otro lado, el mecanismo subyacente de la asociación de archivos y las extensiones de shell sigue siendo, hoy en día, el mismo mundo de COM y del registro de Windows de siempre. La clave de extensión señala a un ProgID, el verb del ProgID tiene una línea de comandos, y las extensiones más elaboradas funcionan como servidores COM en proceso (DLL) que se cargan en el Explorador: esta estructura no ha cambiado en más de 20 años. Sin conocer a la vez la base que no ha cambiado y el menú que se duplicó en Windows 11, no es posible diagnosticar si «el menú no aparece», «se ha escondido» o «aparece duplicado».
Este artículo, dirigido a responsables de sistemas de pequeñas y medianas empresas y a desarrolladores de Windows que mantienen aplicaciones de negocio, conecta en un solo hilo la estructura de tres niveles de la asociación de archivos, los puntos de atención de las extensiones de shell tradicionales, cómo adaptarse al nuevo menú contextual de Windows 11, y el registro, la limpieza y la resolución de problemas desde el instalador.
1. Conclusión principal
- La base del menú contextual y de la asociación de archivos es la estructura de tres niveles del registro «clave de extensión → ProgID → verb». La clave de extensión es un puntero que señala al ProgID, el ProgID es la entidad, y el
shell\<verb>\commandque cuelga de él tiene la línea de comandos.1 - HKEY_CLASSES_ROOT (HKCR) no es una hive independiente, sino una vista combinada de HKLM\Software\Classes y HKCU\Software\Classes. El registro pensado para todos los usuarios se escribe en HKLM, el de un usuario concreto en HKCU, y HKCR se debe tratar como algo solo de lectura.2
- La aplicación predeterminada (la que se abre con doble clic) está diseñada para que la elija el usuario, y no se le puede arrebatar desde un programa. La elección del usuario está protegida por el sistema operativo, y lo único que puede hacer el instalador es registrarse como candidato.3
- Una extensión de shell tradicional es una DLL que actúa como servidor COM en proceso cargado en el Explorador. Un bloqueo o una lentitud de la extensión se propaga a todo el Explorador (y a cualquier otra aplicación que use el shell); en entornos de 64 bits se requiere una DLL de 64 bits, y la implementación en código administrado no tiene soporte.45
- En Windows 11 el menú contextual se duplicó. En el nuevo menú solo aparecen los comandos registrados con IExplorerCommand más identidad de paquete; las extensiones IContextMenu tradicionales quedan relegadas al menú antiguo que se abre con «Mostrar más opciones» (Shift+F10).67
- La ruta oficial para mostrar un comando propio en el nuevo menú es registrar una DLL nativa que implemente IExplorerCommand mediante el manifiesto de un paquete MSIX (desktop4:FileExplorerContextMenus). Las aplicaciones que no pueden convertirse a MSIX pueden obtener solo la identidad con un sparse package (MSIX con ubicación externa).78
- Si solo se quiere que «esta aplicación abra el archivo», la asociación y un verb estático siguen siendo suficientes hoy en día. No hace falta ninguna DLL de extensión de shell, y la propia Microsoft recomienda «elegir el método más simple que cumpla el requisito (un verb estático)».9
- Tras registrar o modificar una asociación hay que notificarlo con SHChangeNotify (SHCNE_ASSOCCHANGED), y la guía oficial indica que al desinstalar se elimine el ProgID pero no el valor predeterminado de la clave de extensión. Diseñar bien esa limpieza también forma parte de la integración con el shell.110
En resumen: el mundo de la asociación y de los verbs no ha cambiado, solo la forma de mostrar el menú se ha duplicado en Windows 11. A continuación lo revisamos desde la base.
2. Cómo funciona la asociación de archivos — la estructura de tres niveles clave de extensión→ProgID→verb
2.1. Leer la estructura de tres niveles con un ejemplo
Qué ocurre al hacer doble clic en un archivo de determinada extensión depende de tres niveles de claves del registro.1
HKEY_CLASSES_ROOT
.kmrpt ← (1) Clave de extensión
(Default) = KomuraSoft.Report.1 ← Puntero que solo señala al ProgID
OpenWithProgids
KomuraSoft.Report.1 ← Candidato para "Abrir con"
KomuraSoft.Report.1 ← (2) ProgID (la entidad de la asociación)
(Default) = Documento de informe KomuraSoft
DefaultIcon
(Default) = "C:\Program Files\KomuraSoft\Report.exe",0
shell ← (3) Lista de verbs (verbos)
open
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
- (1) La clave de extensión (
.kmrpt) se limita, con su valor predeterminado, a señalar el nombre del ProgID. Escribir un comando directamente aquí es un error. - (2) El ProgID (
KomuraSoft.Report.1) es la entidad de la asociación y tiene el nombre visible, el icono y la lista de verbs. - (3) El verb es un verbo como «abrir» o «imprimir», y el valor predeterminado de
shell\open\commandes la línea de comandos que realmente se ejecuta.
Gracias a esta separación se pueden apuntar varias extensiones (por ejemplo .kmrpt y .kmrpt-file) al mismo ProgID, o sustituir el ProgID al actualizar la versión de la aplicación.
flowchart TB
accTitle: Estructura de tres niveles de la asociación de archivos
accDescr: La clave de extensión es solo un puntero que señala al ProgID mediante su valor predeterminado, el ProgID es la entidad que tiene el nombre visible, el icono y la lista de verbs, y el valor predeterminado del command bajo el verb es la línea de comandos que realmente se ejecuta
ext["Clave de extensión .kmrpt"] -->|Señala al ProgID por su valor predeterminado| pid["ProgID KomuraSoft.Report.1"]
pid --> vb["Verb(open, bajo shell)"]
vb --> cmd["Valor predeterminado de command"]
cmd --> exe["Se ejecuta Report.exe"]
pid -.-> attr["También tiene nombre visible y DefaultIcon"]
Figura 1: la clave de extensión es un puntero, el ProgID es la entidad, y el command del verb es la línea de comandos que realmente se ejecuta.
2.2. HKCR es una «vista combinada» — el significado depende de dónde se escribe
El ejemplo anterior se mostró en HKEY_CLASSES_ROOT (HKCR), pero HKCR no es un lugar de almacenamiento físico, sino una vista combinada que superpone HKLM\Software\Classes y HKCU\Software\Classes. Si la misma clave existe en ambos, gana el lado de HKCU.2
flowchart TB
accTitle: HKCR es una vista combinada
accDescr: HKCR es la superposición de las claves Classes de HKLM y HKCU, si la misma clave existe en ambas gana el lado de HKCU, y la escritura del registro debe indicar explícitamente HKLM o HKCU dejando HKCR solo para lectura
hklm["HKLM\Software\Classes(todos los usuarios)"] --> hkcr["HKCR(vista combinada)"]
hkcu["HKCU\Software\Classes(por usuario)"] --> hkcr
hkcu -.-> win["Si la clave coincide, gana HKCU"]
hkcr -.-> ro["Se trata solo como lectura(verificación)"]
Figura 2: HKCR es la manera en que se ven combinadas las claves Classes de HKLM y HKCU; el destino de escritura debe indicarse siempre explícitamente.
| Destino de escritura | Significado | Permisos necesarios |
|---|---|---|
HKLM\Software\Classes |
Registro común para todos los usuarios | Permisos de administrador |
HKCU\Software\Classes |
Registro exclusivo de ese usuario | No se necesitan |
Escribir directamente en HKCR |
Se redirige según dónde exista ya la clave | Depende del caso |
En la práctica, lo más seguro es escribir siempre el registro indicando explícitamente HKLM o HKCU, y tratar HKCR solo como algo de lectura (verificación). Conviene además tener claro cómo se relaciona esto con la redirección del registro de WOW64. Los datos de asociación bajo HKLM\Software\Classes directamente, como las claves de extensión o los ProgID, se comparten entre las vistas de registro de 32 y 64 bits desde Windows 7 en adelante, así que aunque un instalador de 32 bits los escriba, no se desvían hacia Wow6432Node. En cambio, algunas subclaves del registro de COM, como Classes\CLSID, sí son objeto de redirección, y en el registro de extensiones de shell (COM en proceso) que veremos más adelante, la distinción entre 32 y 64 bits sí influye. Este tema se trata con detalle en «La redirección de 32/64 bits del registro y las trampas de la virtualización».
2.3. Registro del lado de la aplicación — App Paths, Applications y RegisteredApplications
Además del lado de los archivos (extensión y ProgID), también existen tres tipos de registro del lado de la aplicación.11
- App Paths (
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths): permite iniciar la aplicación desdeShellExecuteExsolo con el nombre del ejecutable. Como no ensucia la variable de entorno PATH, es lo que recomienda Microsoft. - Applications (
HKCR\Applications\<app.exe>): define la forma predeterminada de abrir un archivo arbitrario cuando se pasa a través de «Abrir con», y el nombre visible de la aplicación (FriendlyAppName). - RegisteredApplications + Capabilities: declara qué extensiones y tipos MIME puede manejar la aplicación, y es el registro necesario para figurar como candidato en la pantalla de configuración de aplicaciones predeterminadas de Windows.
La mayoría de las consultas del tipo «nuestra aplicación no aparece en la lista de aplicaciones predeterminadas» se deben a que se registró el ProgID pero se omitió este registro de Capabilities.
flowchart TB
accTitle: Los tres tipos de registro del lado de la aplicación
accDescr: El registro del lado de la aplicación tiene tres tipos, App Paths, Applications y RegisteredApplications, que cumplen respectivamente el papel de iniciar solo con el nombre del ejecutable, definir la forma predeterminada de abrir con Abrir con y aparecer en la pantalla de configuración de aplicaciones predeterminadas
app["Registro del lado de la aplicación"] --> ap["App Paths"]
app --> apps["Applications"]
app --> ra["RegisteredApplications"]
ap --> r1["Se inicia solo con el nombre del archivo"]
apps --> r2["Forma predeterminada de Abrir con"]
ra --> r3["Aparece en la pantalla de apps predeterminadas"]
r3 -.-> cap["Requiere declaración en Capabilities"]
Figura 3: hay tres tipos de registro del lado de la aplicación, y para aparecer como candidato en la pantalla de aplicaciones predeterminadas se necesita el registro de Capabilities.
2.4. La aplicación predeterminada pertenece al usuario — la protección de UserChoice
Escribir un ProgID en el valor predeterminado de la clave de extensión no basta por sí solo para convertirse en la aplicación predeterminada. El resultado que el usuario elige explícitamente, por ejemplo con «Abrir con», se guarda en HKCU\...\Explorer\FileExts\<extensión>\UserChoice, y ese es el que prevalece al resolver la asociación.
Y lo importante es que Windows no admite que la aplicación predeterminada se cambie mediante programación. El cambio de aplicación predeterminada está diseñado para hacerse a través de la interfaz de configuración del sistema, los datos de UserChoice están ofuscados, y un controlador de filtro (UCPD.sys) bloquea que las aplicaciones escriban en ellos. En entornos administrados, la directiva de grupo o la directiva MDM son el medio oficial.3
El hecho de que en el pasado se usaran herramientas como SetUserFTA, que «imitan el hash y lo reescriben», es el reflejo inverso de esta protección. Lo que un instalador de una aplicación propia debe incorporar no es arrebatar el valor predeterminado, sino tres cosas: (a) registrar correctamente el ProgID y el verb, (b) añadirse a OpenWithProgIds, y (c) dirigir al usuario, si hace falta, hacia la pantalla de configuración.
flowchart TB
accTitle: Resolución de la aplicación predeterminada y protección de UserChoice
accDescr: El resultado que el usuario elige explícitamente se guarda en UserChoice y tiene prioridad en la resolución de la asociación, la reescritura desde una aplicación es bloqueada por UCPD.sys, por lo que el instalador solo puede registrarse como candidato y dirigir al usuario a la pantalla de configuración
uc["UserChoice(elección del usuario)"] -->|Prioridad| res["Resolución de la asociación"]
ext["Valor predeterminado de la clave de extensión"] --> res
wr["Reescritura desde una aplicación"] -.->|Bloqueada por UCPD.sys| uc
res ~~~ inst["Tarea del instalador"]
inst --> a1["Registrar ProgID y verb"]
inst --> a2["Añadir a OpenWithProgIds"]
inst --> a3["Dirigir a la pantalla de configuración"]
Figura 4: en la resolución de la asociación tiene prioridad la elección del usuario (UserChoice), y el sistema operativo protege contra la reescritura desde una aplicación.
3. Verbs más allá de «abrir» — print, edit, runas y verbs personalizados
Un verb no es solo open. Entre los verbs estándar que el sistema operativo entiende están, además de open, edit, print, play, preview, y a los verbs estándar se les asigna automáticamente un nombre visible según el idioma del sistema operativo. El verb predeterminado que se usa al hacer doble clic se decide en este orden: el valor predeterminado de la clave shell, el primer verb del registro, open y por último openwith.12
flowchart TB
accTitle: Orden de determinación del verb predeterminado
accDescr: El verb predeterminado que se usa al hacer doble clic se decide por el primero que se encuentre en este orden: el valor predeterminado de la clave shell, el primer verb del registro, open y openwith
s1["Valor predeterminado de la clave shell"] -->|Si no existe| s2["Primer verb del registro"]
s2 -->|Si no existe| s3["open"]
s3 -->|Si no existe| s4["openwith"]
Figura 5: el verb predeterminado al hacer doble clic es el primero que se encuentre en este orden.
Para añadir un verbo propio se registra un verb personalizado.
KomuraSoft.Report.1
shell
open
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
print
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" /print "%1"
verify ← Verb personalizado
(Default) = Verificar informe (&V) ← Nombre mostrado en el menú
command
(Default) = "C:\Program Files\KomuraSoft\Report.exe" /verify "%1"
Van tres pequeños detalles útiles de saber.
- Registrar un verb llamado runas permite definir un inicio elevado equivalente a «Ejecutar como administrador», y también se usa cuando se especifica
runasdesde las API de la familiaShellExecute. - Si en la clave del verb se coloca un valor vacío llamado
Extended, se convierte en un verb extendido que solo se muestra al hacer clic derecho con la tecla Shift pulsada. Es útil para ocultar operaciones peligrosas que se usan rara vez.12 - En asociaciones de aplicaciones antiguas a veces persiste una configuración con DDE (la clave
ddeexec) que envía el documento a un proceso ya existente, pero iniciar un verb mediante DDE ya es un legado desaprobado (Deprecated). No hay motivo para escribirlo de nuevo.12
Otro origen frecuente de errores son las comillas en la línea de comandos. Si algún elemento de la cadena de comandos puede contener espacios, hay que encerrarlo entre comillas. Además de la ruta del EXE, del tipo C:\Program Files\..., %1 (la ruta del archivo seleccionado) siempre debe escribirse como "%1", porque no se puede garantizar que la ruta del archivo del usuario no contenga espacios. Un My Program.exe sin comillas se interpreta como «ejecutar My con el argumento Program.exe».13
flowchart TB
accTitle: El accidente de las comillas en la línea de comandos
accDescr: Un command sin comillas se divide por los espacios y se malinterpreta como el inicio de My con el argumento Program.exe, por lo que la ruta del EXE que puede contener espacios y %1, que representa la ruta del archivo seleccionado, deben ir siempre entre comillas
c1["command sin comillas"] -->|Se divide por espacios| bad["Se malinterpreta como otro EXE"]
c2["command con comillas"] --> good["Se ejecuta como se pretende"]
c2 -.-> q1["Encerrar la ruta del EXE entre comillas"]
q1 -.-> q2["Encerrar también %1 siempre entre comillas"]
Figura 6: un comando sin comillas se divide erróneamente por los espacios, así que la ruta del EXE y %1 deben ir siempre entre comillas.
Todo lo visto hasta aquí, basado únicamente en el registro (verb estático), se puede lograr sin escribir una sola DLL, y no conlleva el riesgo de desestabilizar el Explorador. La propia Microsoft repite que, antes de escribir una extensión de shell, hay que considerar si basta con el verb estático más simple que cumpla el requisito.9
4. Extensiones de shell tradicionales — DLL que se ejecutan dentro del Explorador
4.1. Tipos de extensiones de shell
Para requisitos que un verb estático no puede cubrir, como «cambiar el menú dinámicamente según lo seleccionado» o «sustituir el icono o la pantalla de propiedades», se usan controladores de extensión de shell. Los tipos representativos son los siguientes.4
| Controlador | Interfaces principales | Qué permite hacer |
|---|---|---|
| Controlador de menú contextual | IContextMenu + IShellExtInit | Añadir y controlar dinámicamente elementos del menú |
| Controlador de icono / superposición de icono | IExtractIcon / IShellIconOverlayIdentifier | Icono por archivo y superposiciones |
| Controlador de hoja de propiedades | IShellPropSheetExt | Añadir pestañas a la pantalla de propiedades |
| Miniatura / información emergente | IThumbnailProvider / IQueryInfo | Vista en miniatura y descripción al pasar el cursor |
| Controlador de arrastrar y soltar / de copia | IDropTarget / ICopyHook | Intervenir al soltar o al copiar/mover |
Todos ellos se implementan como clases COM y se registra su CLSID en el registro. Para el concepto de COM en sí, consulte «Qué es COM / ActiveX / OCX».
4.2. Qué implica ser un servidor COM en proceso
La esencia de una extensión de shell tradicional es que es un servidor COM en proceso (DLL) que se carga dentro del proceso del Explorador (o de cualquier aplicación que abra un cuadro de diálogo de archivos común). De aquí se derivan todos los puntos de atención.4
- Si la extensión se bloquea, el Explorador se bloquea con ella. Si se cuelga, el clic derecho se queda congelado varios segundos. Y el daño no se limita al Explorador: alcanza a cualquier aplicación que muestre un diálogo de abrir archivo.
- La construcción del menú se hace en el hilo de la interfaz de usuario, así que no deben realizarse operaciones lentas, como acceso a red o E/S de archivos, al mostrar el menú.
- La regla es registrar el modelo de subprocesamiento como
Apartment.
flowchart TB
accTitle: Estructura de arrastre de las extensiones en proceso
accDescr: La DLL de la extensión de shell se carga no solo en el Explorador sino también en el proceso de cualquier aplicación que abra un cuadro de diálogo de archivos, por lo que un bloqueo o cuelgue de la extensión se propaga a todo el proceso anfitrión
dll["DLL de la extensión de shell"] -->|Se carga en el proceso| exp["Explorador"]
dll -->|Se carga en el proceso| any["Cualquier app que abre un diálogo"]
exp --> dmg["Se propagan bloqueos o cuelgues"]
any --> dmg
dmg -.-> rule["No hacer procesos lentos al mostrar"]
Figura 7: la DLL de la extensión corre dentro del proceso anfitrión, por lo que un bloqueo o cuelgue se propaga a todo el anfitrión.
Al investigar consultas del tipo «el Explorador se congela al abrir cierta carpeta» o «el clic derecho tarda cinco segundos», no es raro descubrir que la causa no era una aplicación propia, sino una extensión de shell de terceros. El método de diagnóstico se trata en el capítulo 8.
4.3. Coincidencia de arquitectura — en un entorno de 64 bits se requiere una DLL de 64 bits
Una DLL en proceso debe coincidir en arquitectura con el proceso que la carga. Como el Explorador de un Windows de 64 bits es un proceso de 64 bits, una DLL de extensión de shell compilada solo para 32 bits sencillamente no se carga y no aparece en el menú en absoluto. Como no se produce ningún error, es una causa habitual de «lo registré pero no aparece». La combinación de un cuerpo de aplicación de 32 bits con una DLL de extensión de shell de 64 bits es una configuración válida, pero hay que tener en cuenta que el registro COM se divide según la arquitectura (Wow6432Node). El EXE que se inicia desde el command de un verb, por ser un proceso distinto, no está sujeto a esta restricción (puede seguir siendo de 32 bits sin problema).
flowchart TB
accTitle: Coincidencia de arquitectura de la DLL de extensión de shell
accDescr: El Explorador de 64 bits solo puede cargar una DLL de extensión de shell de 64 bits, una DLL de solo 32 bits no aparece en el menú sin ningún error, y el EXE que se inicia desde el command de un verb no tiene esta restricción porque corre en otro proceso
exp["Explorador de 64 bits"] -->|Puede cargar| d64["DLL de extensión de shell de 64 bits"]
exp -.->|No puede cargar| d32["DLL de solo 32 bits"]
d32 -.-> sym["No aparece en el menú, sin error"]
exe["EXE iniciado por un verb"] -->|Otro proceso| ok32["Puede seguir siendo de 32 bits"]
Figura 8: al Explorador de 64 bits solo puede cargarse una DLL de 64 bits, y el EXE iniciado por un verb no está sujeto a esta restricción.
4.4. Por qué no se debe escribir en código administrado
Es frecuente que nos pregunten «¿se puede escribir una extensión de shell en C#?», pero Microsoft afirma explícitamente que escribir extensiones de shell en proceso en código administrado (.NET) no es recomendable y no tiene soporte oficial.5
La razón está en que la extensión se carga en un proceso arbitrario. Existen factores estructurales que pueden desestabilizar la aplicación anfitriona: conflictos de versión del CLR (especialmente por debajo de .NET Framework 4), la reentrada del CLR en el bucle de mensajes durante una espera de bloqueo, y el choque entre el ciclo de vida no determinista de los objetos por la recolección de basura y el contrato de recuento de referencias de COM. Algunos de estos puntos se han aliviado desde .NET Framework 4 en adelante y con el .NET moderno, pero la postura oficial no ha cambiado.
La pauta práctica es sencilla. Las extensiones en proceso se escriben en C++ nativo. Si se quiere usar código administrado, hay que hacerlo como un EXE normal iniciado por el command de un verb, o como una extensión fuera de proceso que corre en otro proceso (como un controlador de vista previa).5
flowchart TB
accTitle: Criterio para decidir si usar código administrado
accDescr: La regla es escribir en C++ nativo las extensiones en proceso que se ejecutan dentro del proceso del Explorador, y si se quiere usar código administrado, conviene un EXE normal iniciado por el command de un verb o una extensión fuera de proceso que corre en otro proceso
q1{"¿Se ejecuta dentro del proceso?"} -->|Sí| cpp["Escribir en C++ nativo"]
q1 -->|No| mg["Código administrado también sirve"]
cpp -.-> why["Conflictos de CLR o reentrada inestabilizan el anfitrión"]
mg --> e1["EXE normal iniciado por un verb"]
mg --> e2["Extensión fuera de proceso(como una vista previa)"]
Figura 9: la regla es escribir las extensiones en proceso en C++ nativo, y el código administrado se limita a configuraciones que corren en otro proceso.
5. El nuevo menú contextual de Windows 11 — la duplicación del menú
5.1. Qué ha cambiado
Windows 11 renovó el menú contextual del Explorador. Cortar, copiar, etc. pasaron a ser una fila de iconos en la parte superior; «Abrir» y «Abrir con» se agrupan y se colocan también en la parte superior; y los comandos que añaden las aplicaciones se agrupan debajo de los comandos estándar del shell. Cuando una misma aplicación añade varios comandos, se agrupan en un flyout (submenú) con el nombre de la aplicación.6
Y aquí está el punto clave: las extensiones de shell tradicionales basadas en IContextMenu no se eliminaron, sino que quedaron relegadas al menú antiguo, el mismo de Windows 10, que se abre con «Mostrar más opciones» (Shift+F10).6 Esta duplicación es la verdadera identidad del «el menú se ha escondido» de la consulta inicial.
flowchart TB
accTitle: El menú contextual duplicado en Windows 11
accDescr: Al hacer clic con el botón derecho, primero se abre el nuevo menú, en el que solo aparecen los comandos registrados con IExplorerCommand e identidad de paquete, mientras que las extensiones IContextMenu tradicionales quedan relegadas al menú antiguo que se abre con Mostrar más opciones
rc["Clic derecho en un archivo"] --> newm["Nuevo menú(Windows 11)"]
newm --> newi["Comandos con IExplorerCommand+identidad"]
newm -->|Mostrar más opciones, Shift+F10| oldm["Menú antiguo(el menú de Windows 10)"]
oldm --> oldi["Extensión IContextMenu tradicional"]
newi -.-> fly["Varios comandos se agrupan en un flyout"]
Figura 10: en el nuevo menú solo aparecen los comandos con IExplorerCommand+identidad, y las extensiones tradicionales quedan relegadas al menú antiguo.
5.2. La ruta oficial para aparecer en el nuevo menú — IExplorerCommand+registro en el manifiesto
Solo hay una forma de sacar un comando propio en el nuevo menú: preparar una DLL nativa que implemente la interfaz IExplorerCommand, y declarar el servidor COM y la extensión de menú contextual en el manifiesto del paquete MSIX.7
<!-- Manifiesto del paquete (extracto) -->
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="Komura commands">
<com:Class Id="01234567-89AB-CDEF-0123-456789ABCDEF"
Path="KomuraCommand.dll" ThreadingModel="STA" />
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type=".kmrpt">
<desktop5:Verb Id="VerifyReport"
Clsid="01234567-89AB-CDEF-0123-456789ABCDEF" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
En Type de ItemType se puede indicar, además de una extensión concreta, * (todos los archivos), Directory (carpetas) o Directory\Background (el fondo de una carpeta). La DLL debe coincidir con la arquitectura del Explorador (64 bits/ARM64).7
IExplorerCommand es una interfaz que existe desde la época de Windows 7, e implementa el título (GetTitle), el icono (GetIcon), el estado habilitado/deshabilitado/oculto (GetState) y la ejecución (Invoke). Como los métodos se llaman desde el hilo de la interfaz de usuario, está prohibido acceder a recursos de red, y los métodos de construcción del menú deben devolver el control con rapidez. El procesamiento pesado se realiza después de Invoke.147
flowchart TB
accTitle: Estructura del manifiesto para registrar el nuevo menú
accDescr: La declaración del servidor COM en el manifiesto MSIX asocia el CLSID con la DLL, y la declaración de la extensión del menú contextual vincula el objetivo y la implementación mediante ItemType y Verb, de modo que el comando propio se muestra en el nuevo menú
man["Manifiesto MSIX"] --> com["Declaración del servidor COM"]
man --> ctx["Declaración de la extensión del menú"]
com -->|Asocia CLSID con la DLL| impl["DLL que implementa IExplorerCommand"]
ctx -->|Especifica ItemType y Verb| impl
impl --> shown["Comando visible en el nuevo menú"]
ctx -.-> tgt["El objetivo puede ser una extensión, todos los archivos, etc."]
Figura 11: las dos declaraciones del manifiesto vinculan la DLL de implementación con el objetivo, y así el comando aparece en el nuevo menú.
5.3. La opción para aplicaciones sin empaquetar — obtener solo la identidad con un sparse package
Para el caso de «nuestra aplicación solo se puede distribuir con un MSI, no es posible convertirla a MSIX», la vía de escape es el sparse package (MSIX con ubicación externa). Se firma y se crea un MSIX pequeño que solo contiene el manifiesto, sin el cuerpo de la aplicación, y se registra al final del instalador existente. Con esto la aplicación obtiene identidad de paquete, y pasa a ser posible el registro del manifiesto mencionado arriba (es decir, la aparición en el nuevo menú). Está disponible desde Windows 10 versión 2004 en adelante, y el paquete necesita estar firmado con un certificado de confianza en el equipo de destino.8
flowchart TB
accTitle: Flujo para obtener identidad con un sparse package
accDescr: Tras colocar el cuerpo de la aplicación con el instalador existente, registrar un sparse package que solo contiene el manifiesto con una ubicación externa hace que la aplicación obtenga identidad de paquete y así sea posible el registro del manifiesto en el nuevo menú
inst["Instalador existente"] --> files["Coloca el cuerpo de la app"]
sp["sparse package"] -.-> only["Solo manifiesto, sin cuerpo"]
files --> reg["Se registra con ubicación externa"]
sp --> reg
reg --> id["Obtiene identidad de paquete"]
id --> ok["Ya es posible registrarse en el nuevo menú"]
sp -.-> sign["Requiere una firma de confianza"]
Figura 12: al registrar con ubicación externa un sparse package que no incluye el cuerpo, la aplicación obtiene identidad de paquete.
La mayor ventaja es que no hace falta sustituir el instalador, lo que lo convierte en una solución realista para aplicaciones que ya cuentan con instaladores MSI/EXE existentes. Para comparar con una migración completa a MSIX, consulte también «Cómo elegir el método de distribución de aplicaciones de Windows».
5.4. Cómo se ven los verbs de asociación en el nuevo menú
Un punto fácil de malinterpretar es que la asociación (ProgID y verb) de los capítulos 2 y 3 sigue vigente incluso en el nuevo menú. El verb predeterminado del doble clic, «Abrir», y los candidatos de «Abrir con» se resuelven a partir de la asociación y se muestran en la parte superior del nuevo menú. Es decir, si solo se quiere «que esta aplicación pueda abrirlo», en Windows 11 tampoco hace falta ninguna adaptación adicional. Por otro lado, la asociación no es una extensión de menú de propósito general, así que si se quiere sacar un comando personalizado arbitrario en el primer nivel del nuevo menú, hace falta IExplorerCommand más identidad; ese es el reparto de funciones.7
flowchart TB
accTitle: Reparto de funciones entre la asociación y el nuevo menú
accDescr: La asociación de ProgID y verb también se usa en el nuevo menú para resolver el verb predeterminado del doble clic y Abrir y Abrir con, mostrándose en la parte superior, mientras que mostrar un comando personalizado arbitrario en el primer nivel del nuevo menú requiere IExplorerCommand e identidad
assoc["Asociación(ProgID y verb)"] --> sol["Resolución del verb predeterminado y Abrir"]
sol --> top["Se muestra en la parte superior del nuevo menú"]
assoc -.-> keep["No requiere trabajo adicional ni en Windows 11"]
cmd["Comando personalizado arbitrario"] --> need["IExplorerCommand+identidad"]
need --> first["Se muestra en el primer nivel del nuevo menú"]
Figura 13: la asociación sigue encargándose de la resolución de «Abrir» también en el nuevo menú, y solo un comando personalizado requiere IExplorerCommand+identidad.
6. Tabla de decisión práctica — cuál de las tres opciones elegir
Resumimos todo lo anterior en tres opciones prácticas.
| Lo que se quiere lograr | Método recomendado | Cómo se ve en Windows 11 | Trabajo y coste necesarios |
|---|---|---|---|
| (a) Iniciar la aplicación propia con doble clic o «Abrir» | Asociación + verb estático (solo registro en el registro de Windows) | Se integra en «Abrir»/«Abrir con» del nuevo menú | Solo el registro de claves desde el instalador. No hace falta DLL ni requisitos adicionales de firma |
| (b) Sacar un comando propio para archivos o carpetas seleccionados en el nuevo menú | Implementar IExplorerCommand + registro en el manifiesto MSIX. Las aplicaciones sin empaquetar obtienen identidad con un sparse package | Primer nivel del nuevo menú (varios comandos se agrupan en un flyout con el nombre de la aplicación) | DLL nativa en C++ + identidad de paquete + firma de código |
| (c) Seguir usando una extensión IContextMenu tradicional existente | Mantenerla tal cual por ahora (no elegirla para desarrollo nuevo) | Solo en el menú antiguo de «Mostrar más opciones» (Shift+F10) | Mantener la compilación de 64 bits y el registro COM. Planificar a futuro la migración a (b) |
Hay dos puntos clave para decidir. Primero, no recurrir a (b) o (c) para un requisito que (a) ya cubre: escribir una extensión de shell implica asumir, desde ese momento, una responsabilidad sobre la estabilidad del Explorador. Segundo, (c) solo significa que «no está roto», pero como experiencia de usuario sigue quedando en una posición inferior. Cuanto más se use un comando en el día a día, mayor será el retorno de la inversión en migrar a (b).
flowchart TB
accTitle: Cómo elegir entre las tres opciones
accDescr: Si solo se quiere iniciar con doble clic o Abrir, basta con la asociación y un verb estático, si se quiere sacar un comando propio en el nuevo menú se necesita IExplorerCommand y el registro en el manifiesto MSIX, si no se puede convertir a MSIX se otorga identidad con un sparse package, y una extensión IContextMenu tradicional existente se mantiene por ahora en el menú antiguo
q1{"¿Basta con abrir?"} -->|Sí| pa["Asociación+verb estático"]
q1 -->|No| q2{"¿Comando propio en el nuevo menú?"}
q2 -->|Sí| q3{"¿Se puede convertir a MSIX?"}
q3 -->|Sí| pb1["IExplorerCommand+MSIX"]
q3 -->|No| pb2["Identidad con sparse package"]
q2 -->|No| pc["Mantener lo tradicional por ahora"]
pc -.-> old["Solo se muestra en el menú antiguo"]
pa -.-> dllfree["Sin DLL, riesgo bajo"]
Figura 14: según el requisito, se elige entre el verb estático, IExplorerCommand+identidad, o mantener lo tradicional.
7. La práctica del despliegue y el registro — instalador, sparse package y limpieza
7.1. ¿HKLM o HKCU?
Hay que hacerlo coincidir con la forma del instalador. Si es para todos los usuarios (se coloca en Program Files, con permisos de administrador), corresponde a HKLM\Software\Classes; si es una instalación por usuario (sin elevación de permisos), corresponde a HKCU\Software\Classes. Mezclarlos genera consultas del tipo «a la usuaria A se le abre, pero al usuario B no». En las extensiones de shell que implican registro de CLSID, existe también la opción de Reg-Free COM, que evita por completo el registro en el registro de Windows y que es válida para el uso de COM dentro de la propia aplicación, pero no puede aplicarse a las extensiones de shell que carga el Explorador, por lo que ahí sí es necesario el registro convencional (véase «Qué es Reg-Free COM»).
7.2. Notificar tras cada cambio — SHChangeNotify
Cada vez que se registre, modifique o elimine una asociación, hay que notificarlo con el evento SHCNE_ASSOCCHANGED mediante SHChangeNotify. Omitir esto puede provocar que el cambio no lo reconozca el Explorador hasta el próximo reinicio.110
// Llamar una vez, por ejemplo desde una acción personalizada del instalador, después de cambiar la asociación
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
7.3. Registro y anulación del sparse package
Registrar y anular el sparse package es tarea del instalador. El registro se hace después de colocar los archivos, y la anulación antes de borrarlos.8
# Durante la instalación: tras colocar los archivos, registrar la carpeta de instalación como ubicación externa
Add-AppxPackage -Path "C:\Program Files\KomuraSoft\KomuraReport.identity.msix" `
-ExternalLocation "C:\Program Files\KomuraSoft"
# Durante la desinstalación: anular el registro del paquete antes de borrar los archivos
Remove-AppxPackage <nombre completo del paquete>
Un punto de atención: Add-AppxPackage se registra para el usuario que lo ejecuta. Si se invoca desde una acción personalizada de un MSI por máquina, ejecutarlo como LocalSystem no otorga la identidad al usuario que hizo la instalación, así que hay que ejecutarlo con suplantación (impersonate) del usuario. Aun así, la identidad registrada mediante la suplantación solo corresponde al usuario que realizó esa instalación. En un entorno donde varios usuarios comparten un mismo PC, los demás usuarios, o los que se crean después, no tienen identidad de paquete y no verán el comando en el nuevo menú. Para que funcione con todos los usuarios, hay que preparar un mecanismo que, en el primer inicio de la aplicación, compruebe si el registro del paquete del propio usuario existe y lo registre si falta (registro por usuario), e incluir también en la desinstalación la anulación del registro de cada usuario que lo tenga registrado. Además, la aplicación del registro del manifiesto puede requerir reiniciar el Explorador (o cerrar sesión).7
flowchart TB
accTitle: Orden de registro y anulación del sparse package
accDescr: Durante la instalación se registra el sparse package después de colocar los archivos, durante la desinstalación se anula el registro antes de borrar los archivos, pero hay que tener en cuenta que el registro solo es válido para el usuario que lo ejecutó
i1["Instalación"] --> i2["Coloca los archivos"]
i2 --> i3["Registra el sparse package"]
u1["Desinstalación"] --> u2["Anula el registro del paquete"]
u2 --> u3["Borra los archivos"]
i3 -.-> pu["El registro solo es válido para el usuario que lo ejecutó"]
Figura 15: el registro se hace después de colocar los archivos, la anulación antes de borrarlos, y hay que tener en cuenta que el registro es por usuario ejecutante.
7.4. Limpieza al desinstalar — qué eliminar y qué conservar
La guía oficial tiene un criterio claro sobre la limpieza al desinstalar.1
- Qué eliminar: el conjunto de claves ProgID propias, el registro de Capabilities/RegisteredApplications, el registro de CLSID de las extensiones de shell, y el sparse package (con Remove-AppxPackage).
- Qué conservar: el valor predeterminado de la clave de extensión (
.kmrpt). La recomendación oficial es no eliminarlo aunque siga apuntando al ProgID propio. Es difícil determinar, tras la instalación, si otra aplicación ha tomado el valor predeterminado, y como Windows simplemente ignora el ProgID predeterminado si no está registrado, dejarlo así no causa ningún daño real. - Al final de la limpieza también se llama a SHChangeNotify (SHCNE_ASSOCCHANGED).
Muchos de los problemas del tipo «desinstalé la aplicación pero queda un residuo en el menú» se deben a huecos en este diseño de la limpieza.
flowchart TB
accTitle: Diseño de la limpieza al desinstalar
accDescr: Al desinstalar se eliminan la clave ProgID propia, el registro de CLSID y el sparse package, se conserva el valor predeterminado de la clave de extensión porque un ProgID no registrado simplemente se ignora, y al final de la limpieza se notifica el cambio con SHChangeNotify
un["Desinstalación"] --> del["Qué eliminar"]
un --> keep["Qué conservar"]
del --> d1["Registro de ProgID o CLSID"]
del --> d2["sparse package"]
keep --> k1["Valor predeterminado de la clave de extensión"]
k1 -.-> why["Un ProgID no registrado se ignora"]
d1 --> fin["Notificar al final con SHChangeNotify"]
k1 --> fin
Figura 16: se elimina el registro propio, se conserva el valor predeterminado de la clave de extensión, y al final de la limpieza se notifica el cambio.
8. Solución de problemas — no aparece, aparece duplicado, va lento
8.1. El menú no aparece
Se diagnostica en este orden.
- Qué menú se está viendo: el registro del método antiguo solo aparece en el menú antiguo de Shift+F10. Primero hay que comprobar ambos.
- Arquitectura: una DLL de extensión de shell compilada solo para 32 bits no se carga en un Explorador de 64 bits (apartado 4.3).
- Destino de registro: confusión entre HKLM/HKCU o entre las vistas de Wow6432Node. Se comprueba la clave real con
reg query. - Registro del paquete: si es para el nuevo menú, se comprueba con
Get-AppxPackagesi el registro existe, si el certificado de firma es de confianza, y la ruta de-ExternalLocation, y se reinicia el Explorador.7 - Falta de notificación: si se olvidó SHChangeNotify, se puede confirmar viendo si se refleja al reiniciar el Explorador.
flowchart TB
accTitle: Orden de diagnóstico cuando el menú no aparece
accDescr: Se empieza confirmando si se está viendo el menú nuevo o el antiguo, y luego se sigue en orden con la arquitectura de la DLL, el destino del registro, el registro del paquete y la firma, y por último la falta de notificación de SHChangeNotify
c1["Confirmar si es el menú nuevo o el antiguo"] --> c2["Confirmar la arquitectura de la DLL"]
c2 --> c3["Confirmar el destino de registro en HKLM y HKCU"]
c3 --> c4["Confirmar el registro del paquete y la firma"]
c4 --> c5["Determinar la falta de notificación reiniciando"]
Figura 17: cuando «no aparece», se diagnostica en orden: qué menú se ve, la arquitectura, el destino de registro, el registro del paquete y la falta de notificación.
8.2. Aparece duplicado o no desaparece
Las causas típicas son la coexistencia del registro tradicional en el registro de Windows con el registro en el manifiesto, huecos en la limpieza al desinstalar (apartado 7.4), y restos de un ProgID de una versión anterior. Si la duplicación aparece solo en el menú antiguo, se sospecha del tipo de restos; si aparece en ambos menús, del tipo de coexistencia.
flowchart TB
accTitle: Diagnóstico de la aparición duplicada
accDescr: Si aparece duplicado solo en el menú antiguo se sospecha de restos por limpieza incompleta o de un ProgID antiguo, y si aparece duplicado en ambos menús se sospecha de la coexistencia del registro antiguo en el registro y del registro en el manifiesto
q{"¿Dónde aparece duplicado?"} -->|Solo en el menú antiguo| zan["Caso de restos"]
q -->|En ambos menús| hei["Caso de coexistencia"]
zan -.-> z1["Limpieza incompleta o restos de un ProgID antiguo"]
hei -.-> h1["Coexistencia del registro antiguo y el nuevo"]
Figura 18: si la duplicación aparece solo en el menú antiguo se sospecha del tipo de restos, y si aparece en ambos menús, del tipo de coexistencia.
8.3. El Explorador va lento o se bloquea
Cuando el clic derecho es lento o el Explorador se bloquea en cierta carpeta, lo primero es hacer inventario de las extensiones de shell instaladas. Con una herramienta como ShellExView de NirSoft se listan las extensiones que no son de Microsoft, y deshabilitando temporalmente las sospechosas con una búsqueda binaria se puede identificar la DLL causante. En caso de bloqueo, el «módulo con errores» del Visor de eventos también sirve de pista. Si la causa resulta ser una extensión propia, conviene sospechar de E/S síncrona o acceso de red en la ruta de construcción del menú (apartados 4.2 y 5.2).
flowchart TB
accTitle: Identificación de la DLL causante cuando va lento o se bloquea
accDescr: Se listan las extensiones de shell que no son de Microsoft con ShellExView, se identifica la DLL causante mediante búsqueda binaria deshabilitando temporalmente las sospechosas, y en caso de bloqueo el módulo con errores del Visor de eventos también sirve de pista
s1["Inventario de extensiones de shell"] --> s2["Listar las que no son de Microsoft"]
s2 --> s3["Búsqueda binaria deshabilitando temporalmente"]
s3 --> s4["Identificar la DLL causante"]
crash["En caso de bloqueo"] -.-> ev["Revisar el módulo con errores"]
ev -.-> s4
Figura 19: se deshabilitan temporalmente las extensiones que no son de Microsoft mediante búsqueda binaria, y en caso de bloqueo se usa también el Visor de eventos.
8.4. Windows Sandbox resulta útil para la verificación
Verificar la integración con el shell consiste, básicamente, en confirmar el ciclo «instalar en un entorno limpio → funcionamiento → desinstalar → cero residuos». Aquí resulta muy útil Windows Sandbox (Pro/Enterprise/Education), que arranca en pocos segundos un Windows desechable completamente limpio cada vez, lo que permite repetir cuantas veces haga falta las pruebas de registro y limpieza del instalador. Como al cerrarlo se elimina todo, también es útil para investigar residuos en el registro.15
9. Resumen
- La asociación de archivos tiene la estructura de tres niveles «clave de extensión → ProgID → verb», y HKCR es la vista combinada de las Classes de HKLM y HKCU. El destino de escritura debe indicarse explícitamente, y
%1siempre debe ir entre comillas. - La aplicación predeterminada está diseñada para que la elija el usuario, y no se puede cambiar desde un programa. La tarea del instalador llega hasta registrarse correctamente como candidato.
- Una extensión de shell tradicional es una DLL que actúa como servidor COM en proceso cargado en el Explorador. Un bloqueo o una lentitud se propaga a todo el conjunto, se requiere 64 bits, el código administrado no tiene soporte, y la regla es implementarla en C++ nativo.
- En Windows 11 el menú contextual se duplicó. Para sacar un comando propio en el nuevo menú hace falta IExplorerCommand+manifiesto MSIX, y las extensiones IContextMenu tradicionales quedan relegadas al lado de «Mostrar más opciones».
- Para las aplicaciones que no pueden convertirse a MSIX, obtener la identidad con un sparse package (MSIX con ubicación externa) es la solución realista.
- Si solo se quiere «que esta aplicación lo abra», la asociación y un verb estático siguen siendo suficientes hoy en día. Empezar por el medio más simple es también la pauta oficial.
- Después de registrar, modificar o eliminar hay que notificarlo con SHChangeNotify, y al desinstalar, aunque se elimine el ProgID, se conserva el valor predeterminado de la clave de extensión. Windows Sandbox resulta muy útil para la verificación.
Si al cambiar de PC a Windows 11 nota que «el menú se ha escondido», empiece por comprobar en la tabla de decisión del capítulo 6 a cuál de las opciones (a), (b) o (c) corresponde su caso. Con eso podrá estimar en el momento el alcance del trabajo necesario.
Artículos relacionados
- Qué es COM / ActiveX / OCX - diferencias y relaciones explicadas juntas
- Qué es Reg-Free COM - el mecanismo para usar COM sin registro
- La redirección de 32/64 bits del registro y las trampas de la virtualización — Wow6432Node y el problema de «el valor que escribí no está»
- Cómo elegir el método de distribución de aplicaciones de Windows - MSI/MSIX/ClickOnce/xcopy/actualizador propio
- Compatibilidad hacia atrás de interfaces DLL y COM — tabla de decisión sobre qué cambios rompen al llamador
- Cómo funciona la compatibilidad de aplicaciones de Windows — modo de compatibilidad, shims y Compatibility Administrator para prolongar la vida de aplicaciones antiguas
Áreas de consultoría relacionadas
KomuraSoft LLC se ocupa del diseño e implementación de la asociación de archivos, el menú contextual y las extensiones de shell de aplicaciones de negocio, de la adaptación al nuevo menú contextual de Windows 11 (migración a IExplorerCommand, introducción de sparse package), de la revisión del registro y la limpieza de instaladores existentes, y de la investigación de las causas cuando el Explorador va lento o se bloquea. Puede empezar simplemente decidiendo qué hacer con el menú que ha quedado escondido en «Mostrar más opciones».
- Desarrollo de aplicaciones para Windows
- Aprovechamiento y migración de activos existentes
- Consultoría técnica y revisión de diseño
- Contacto
Referencias
-
Microsoft Learn, File Types. Sobre la estructura en la que la clave de extensión señala al ProgID, OpenWithProgIds, el uso diferenciado del registro en HKLM/HKCU\Software\Classes, la necesidad de llamar a SHChangeNotify (SHCNE_ASSOCCHANGED) tras modificar una asociación, y que al desinstalar se debe eliminar el ProgID conservando el valor predeterminado de la clave de extensión. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, HKEY_CLASSES_ROOT Key. Sobre que HKEY_CLASSES_ROOT es una vista que combina HKLM\Software\Classes y HKCU\Software\Classes, que la definición del lado del usuario tiene prioridad sobre la de la máquina, y las reglas de reparto al escribir. ↩ ↩2
-
Microsoft Learn, Windows app defaults platform. Sobre que el cambio de aplicación predeterminada está diseñado para hacerse solo a través de la interfaz de configuración del sistema, que los datos de configuración del usuario están ofuscados y protegidos frente a escritura por un controlador de filtro (UCPD.sys), que el cambio basado en el registro no tiene soporte, y que en entornos administrados se usa la directiva de grupo o MDM. ↩ ↩2
-
Microsoft Learn, Working with Shell Extensions. Sobre los tipos de controladores de extensión de shell, que la extensión es una DLL que actúa como servidor COM en proceso cargado en el Explorador (y en los procesos que alojan el shell), que un bloqueo o cuelgue se propaga a todo el Explorador, el registro con ThreadingModel=Apartment, y que conviene considerar primero alternativas más simples que una extensión de shell. ↩ ↩2 ↩3
-
Microsoft Learn, Guidance for Implementing In-Process Extensions. Sobre que Microsoft no recomienda y no da soporte a la implementación de extensiones de shell en proceso en código administrado, las razones como los conflictos de versión del CLR, la reentrada y el ciclo de vida no determinista de los objetos, y que las extensiones fuera de proceso (controladores de vista previa o inicio desde shell\verb\command) sí admiten código administrado. ↩ ↩2 ↩3
-
Windows Developer Blog, Extending the Context Menu and Share Dialog in Windows 11. Sobre el diseño del nuevo menú contextual de Windows 11, la extensión mediante IExplorerCommand+identidad de aplicación, la ubicación superior de «Abrir» y «Abrir con», la agrupación de varios comandos en un flyout con el nombre de la aplicación, y que las extensiones IContextMenu tradicionales se cargan como el menú de Windows 10 mediante «Mostrar más opciones» (Shift+F10). ↩ ↩2 ↩3
-
Microsoft Learn, Add a File Explorer context menu command to a packaged desktop app. Sobre que el registro en el nuevo menú contextual de Windows 11 se realiza mediante la implementación de IExplorerCommand junto con la declaración en el manifiesto de windows.comServer y desktop4:FileExplorerContextMenus, que en ItemType se puede indicar *, Directory o Directory\Background, la coincidencia de arquitectura de la DLL, mantener rápidos los métodos de construcción del menú, la adaptación de aplicaciones sin empaquetar mediante sparse package, que aplicar el registro puede requerir reiniciar el Explorador, y que la asociación de archivos no es una extensión de menú de propósito general. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, Grant package identity by packaging with external location. Sobre que se puede obtener identidad de paquete registrando un paquete con ubicación externa (sparse package) sin modificar el instalador existente, que está disponible desde Windows 10 versión 2004 en adelante, y que pasan a poder usarse funciones de Windows que requieren identidad (registro en el menú contextual, notificaciones, etc.). ↩ ↩2 ↩3
-
Microsoft Learn, Choosing a Static or Dynamic Shortcut Menu Method. Sobre que se debe elegir el método de verb estático más simple que cumpla el requisito, que IContextMenu es el más potente pero también el más complejo y está clasificado del lado no recomendado, y que IExplorerCommand/IExplorerCommandState es el método recomendado. ↩ ↩2
-
Microsoft Learn, SHChangeNotify function. Sobre el método para emitir el evento SHCNE_ASSOCCHANGED que notifica al sistema los cambios en la asociación de archivos, y cómo usarlo para que el shell reconozca el cambio. ↩ ↩2
-
Microsoft Learn, Application Registration. Sobre que se recomienda registrar el ejecutable mediante la subclave App Paths, el papel de la subclave Applications, el registro de verbs mediante SystemFileAssociations, y el orden de prioridad del ProgID y la información relacionada al cambiar la aplicación predeterminada. ↩
-
Microsoft Learn, Verbs and File Associations. Sobre que el verb también se usa desde ShellExecuteEx, que los elementos de la cadena de comandos que puedan contener espacios deben ir entre comillas, que “%1” siempre debe escribirse entre comillas, y el registro del procedimiento predeterminado bajo HKCR\Applications. ↩
-
Microsoft Learn, IExplorerCommand interface. Sobre la composición de métodos como GetTitle, GetIcon, GetState, Invoke y EnumSubCommands, que los métodos se llaman desde el hilo de la interfaz de usuario y por tanto no deben comunicarse con recursos de red, y que está disponible desde Windows Vista en adelante. ↩
-
Microsoft Learn, Windows Sandbox. Sobre que permite iniciar en pocos segundos un entorno de Windows aislado y desechable, que al cerrarlo se descartan todos los cambios, que es adecuado para probar software y verificar instaladores, y que está disponible en Pro/Enterprise/Education. ↩
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Cómo funcionan el portapapeles y arrastrar y soltar — Gestionar correctamente la transferencia de datos OLE en aplicaciones empresariales
Una tabla de Excel se deforma al pegarla y deja de poder pegarse si cierra el origen: es el portapapeles colocando el mismo contenido en ...
Qué es el TPM en Windows — la "caja fuerte que no deja salir la llave" y el arranque medido, explicados con diagramas
Explicamos el TPM con diagramas: cómo evita que la clave salga del chip, el arranque medido con PCR, su uso en BitLocker y Windows Hello,...
Cómo invocar COM y .NET desde PowerShell en la práctica ── ampliar de un salto el alcance de sus scripts
Cómo invocar clases .NET desde PowerShell, integrar C# y la API Win32 con Add-Type, operar COM, gestionar los procesos residuales de Exce...
Cómo elegir la comunicación entre procesos en Windows — canalizaciones con nombre / TCP / gRPC / memoria compartida / COM: tabla de decisión
Cómo elegir la comunicación entre procesos en Windows: comparamos en una tabla de decisión las canalizaciones con nombre, el TCP local, g...
Externalización y desarrollo por encargo de una app Windows: qué aclarar antes de solicitarlo
Antes de encargar la externalización o el desarrollo por encargo de una app Windows, estos son los puntos a aclarar: revisión de software...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Migración de ActiveX
Decisiones para conservar, encapsular o sustituir componentes COM / ActiveX / OCX.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Desarrollo de aplicaciones para Windows
Aplicaciones empresariales, integración de dispositivos y herramientas de comunicación, de los requisitos al desarrollo.
Mantenimiento y modernización de software Windows
Ampliaciones, mantenimiento y modernización gradual de software Windows existente.
Preguntas frecuentes
Preguntas habituales en las consultas sobre el tema del artículo.
- ¿Por qué el menú contextual de mi aplicación en Windows 11 solo aparece dentro de «Mostrar más opciones»?
- Porque en Windows 11 el menú contextual del Explorador se dividió en dos niveles, uno nuevo y uno antiguo. Solo pueden aparecer en el nuevo menú los comandos que implementan la interfaz IExplorerCommand y que se registran en el manifiesto de un paquete MSIX (es decir, que tienen identidad de paquete); las extensiones de shell tradicionales basadas en IContextMenu quedaron relegadas al menú antiguo que se abre con «Mostrar más opciones» (Shift+F10). La extensión en sí no se ha roto, así que por ahora seguirá funcionando igual, pero si se quiere que aparezca en el nuevo menú es necesario migrar a IExplorerCommand y otorgarle identidad mediante MSIX o un sparse package.
- ¿Puedo hacer que mi instalador configure mi aplicación como la aplicación predeterminada para abrir un archivo con doble clic?
- No es posible. La elección de la aplicación predeterminada está diseñada para que la haga el usuario, y Windows no admite que se cambie la aplicación predeterminada desde ningún lugar que no sea la interfaz de configuración del sistema. La información de UserChoice que conserva la elección de cada usuario está ofuscada, y además un controlador de filtro (UCPD.sys) bloquea que las aplicaciones la escriban. Lo único que puede hacer el instalador es registrar el ProgID y el verb, añadirse a OpenWithProgIds para figurar como candidato en «Abrir con», y en todo caso dirigir al usuario hacia la pantalla de configuración de aplicaciones predeterminadas. La implementación correcta no es arrebatar el valor predeterminado, sino preparar la aplicación para ser elegida.
- ¿Puedo escribir una extensión de shell en código administrado, como C#?
- Microsoft afirma explícitamente que escribir en código administrado extensiones de shell que se cargan en proceso (como los controladores de menú contextual o los controladores de iconos) no es recomendable y no cuenta con soporte oficial. La razón es que la extensión se carga en el proceso de cualquier aplicación que abra el Explorador o un cuadro de diálogo de archivos común, y los conflictos de versión del CLR, la reentrada y la falta de determinismo en la vida útil de los objetos pueden desestabilizar la aplicación anfitriona. La regla es implementarlas en C++ nativo. En cambio, un EXE normal iniciado por el command de un verb, o una extensión fuera de proceso que corre en otro proceso, como un controlador de vista previa, sí puede escribirse en código administrado sin problema.
- ¿Qué es un sparse package (MSIX con ubicación externa)?
- Es un paquete MSIX pequeño que no incluye los archivos de la propia aplicación, sino solo el manifiesto (la información de identidad). Si a una aplicación instalada normalmente con un instalador existente (MSI, Inno Setup, etc.) se le registra un sparse package apuntando con -ExternalLocation de Add-AppxPackage a la carpeta de instalación, esa aplicación obtiene identidad de paquete y puede usar funciones que la requieren, como el registro en el nuevo menú contextual de Windows 11 o las notificaciones toast. Está disponible desde Windows 10 versión 2004 en adelante, y el paquete debe firmarse con un certificado de confianza en el equipo de destino. Es una opción realista para adaptarse al nuevo menú sin migrar por completo la distribución a MSIX.
- ¿Qué hago si un elemento del menú contextual aparece duplicado o no desaparece?
- Primero hay que aislar la causa comprobando si aparece en el nuevo menú, en el antiguo (Mostrar más opciones) o en ambos. La aparición duplicada suele deberse a que coexisten el registro tradicional del registro de Windows y el registro en el manifiesto MSIX, o a que, tras desinstalar, quedaron sin limpiar el ProgID o el registro de CLSID de la extensión. También conviene sospechar de una notificación perdida mediante SHChangeNotify (SHCNE_ASSOCCHANGED) después de cambiar una asociación, o de que falte reiniciar el Explorador justo después de registrar el paquete. Si aun así no se resuelve, deshabilitar temporalmente las extensiones que no son de Microsoft con ShellExView y aplicar una búsqueda binaria permite identificar la DLL causante.
Perfil del autor
Página de presentación del autor del artículo.
Go Komura
Representante de KomuraSoft LLC
Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.