«La aplicación no puede leer al iniciar la clave de licencia que escribió el instalador. Al mirar con regedit, el valor sí está ahí» — recibí este informe mientras apoyaba la migración a 64 bits de un software de integración con equipos. Al investigar, resultó que el valor estaba bajo HKLM\Software\Wow6432Node\NombreDeLaEmpresa. La aplicación, recién recompilada en 64 bits, iba a leer HKLM\Software\NombreDeLaEmpresa, donde no había absolutamente nada: ese era el desenlace.
Este tipo de casos —«el valor que debería haberse escrito no está», «se ve en regedit pero la aplicación no lo ve»— sigue siendo un misterio por más que se inspeccione a simple vista si no se conocen dos mecanismos. El primero es que el registro de un Windows de 64 bits aparece en un lugar distinto según la bitness del proceso (es decir, según si ese proceso se ejecuta como de 32 o de 64 bits): es la redirección de registro de WOW64 (Windows 32-bit on Windows 64-bit, el subsistema que permite que un Windows de 64 bits ejecute aplicaciones de 32 bits). El segundo es que una escritura sin permisos suficientes se traslada silenciosamente a otro lugar: es la virtualización de registro de UAC. Y como ambos mecanismos «tienen éxito sin generar ningún error», el problema solo aparece en el instante en que el lugar donde se escribió y el lugar donde se lee dejan de coincidir, típicamente durante una migración a 64 bits o un cambio de instalador.
Este artículo se dirige a desarrolladores de aplicaciones empresariales para Windows y organiza, con el respaldo de la documentación oficial, el funcionamiento de la redirección de registro de WOW64 y la clasificación entre claves redirigidas y compartidas, las condiciones que activan la virtualización de registro de UAC, los daños reales que provoca en instaladores y en el registro de COM, y la forma correcta de especificar explícitamente la vista desde C#, C++ y reg.exe.
1. La conclusión primero
- El registro de un Windows de 64 bits tiene una vista de 64 bits y una de 32 bits, y el acceso de un proceso de 32 bits a
HKLM\Softwarees desviado de forma transparente por el redirector de registro hacia la ubicación físicaHKLM\Software\Wow6432Node. La aplicación no ve ni un error ni una advertencia. 1 - Wow6432Node es una ubicación física reservada por el sistema. No debe codificarse esa ruta a fuego ni accederse a ella directamente (en Windows 10 on ARM se usa otra ubicación distinta,
WowAA32Node, para las apps ARM de 32 bits). Para acceder a otra vista se deben usar los mecanismos oficiales (los indicadores o RegistryView descritos más adelante). 12 - Solo se redirige una parte de las claves; otras se comparten. Desde Windows 7 en adelante,
HKLM\SOFTWAREestá «redirigida»,HKLM\SOFTWARE\Classesestá «compartida», pero dentro de esta última,CLSIDeInterfacevuelven a estar «redirigidas»: es una estructura anidada. 3 - Para acceder a otra vista: en Win32 se indica
KEY_WOW64_64KEY/KEY_WOW64_32KEYen elsamDesiredde funciones comoRegOpenKeyEx; en .NET se pasaRegistryView.Registry64/Registry32aRegistryKey.OpenBaseKey; y en la línea de comandos se usa/reg:64//reg:32conreg.exe. 245 - Cuando un proceso interactivo de 32 bits sin privilegios de administrador escribe en
HKLM\Software, la virtualización de registro de UAC puede trasladar esa escritura aHKEY_USERS\<SID>_Classes\VirtualStore\Machine\Software. La trampa es que la escritura «tiene éxito» y, cuando el mismo proceso vuelve a leer el valor, lo ve a través de una vista combinada. 6 - Si el manifiesto declara
requestedExecutionLevel, la virtualización de archivos y de registro queda desactivada. Dicho de otro modo, la virtualización solo afecta a los ejecutables heredados que carecen de manifiesto. 7 - La virtualización de registro es una tecnología de compatibilidad provisional, y Microsoft ha declarado explícitamente su intención de eliminarla en futuras versiones de Windows. Una aplicación nueva no debe depender de ella; el diseño correcto es, sencillamente, «no escribir en HKLM». 6
- El registro CLSID de COM (
HKCR\CLSID=HKLM\Software\Classes\CLSID) se separa según la bitness. El registro de un servidor COM de 32 bits no es visible para un cliente de 64 bits, y esta es una causa clásica del error «clase no registrada (0x80040154)». 3
Panorama de los dos mecanismos
Los dos mecanismos que trata este artículo son distintos en quién actúa, sobre qué y hacia dónde traslada. La redirección es «un asunto de bitness» y afecta tanto a la lectura como a la escritura; la virtualización es «un asunto de permisos» y afecta solo a la escritura. Como es fácil confundirlos, conviene fijar el panorama general en una sola imagen antes de entrar en el detalle.
flowchart TD
S["El proceso opera sobre HKLM\Software"] --> B{"¿El proceso es de 32 bits?"}
B -- "32 bits" --> R["Redirección de registro de WOW64<br/>Asunto de bitness, afecta a lectura y escritura"]
B -- "64 bits" --> N["Sin redirección<br/>Lee y escribe directamente HKLM\Software"]
R --> RV["Lo que realmente se lee y escribe es<br/>Wow6432Node = la vista de 32 bits"]
RV --> W{"En una escritura, ¿falta el permiso<br/>de escritura sobre esa clave?"}
N --> W
W -- "Proceso interactivo de 32 bits sin manifiesto" --> V["Virtualización de registro de UAC<br/>Asunto de permisos, afecta solo a la escritura"]
V --> VS["Se traslada al VirtualStore de cada usuario<br/>La lectura da una vista combinada con la ubicación original"]
W -- "Proceso de 64 bits, servicio, o con manifiesto" --> E["Falla directamente por acceso denegado"]
La ramificación de la izquierda del diagrama (quién es de 32 bits) corresponde a los apartados 2 y 3, y la ramificación inferior derecha (permisos y manifiesto) corresponde al apartado 5.
2. Redirección de registro de WOW64 — qué ve realmente un proceso de 32 bits
Un Windows de 64 bits ejecuta las aplicaciones de 32 bits sobre un subsistema llamado WOW64. En ese momento, el redirector de registro presenta vistas lógicas distintas al proceso de 32 bits y al de 64 bits. El núcleo del mecanismo es que ambos usan la misma API y especifican el mismo nombre de clave (HKEY_LOCAL_MACHINE\Software\...), pero la ubicación física donde realmente se lee y se escribe es diferente. 1
La ubicación física de las claves redirigidas es Wow6432Node. Por ejemplo, HKEY_LOCAL_MACHINE\Software de un proceso de 32 bits se corresponde físicamente con HKEY_LOCAL_MACHINE\Software\Wow6432Node. Esta correspondencia es completamente transparente para la aplicación, de modo que una app de 32 bits puede operar el registro «como si estuviera ejecutándose en un Windows de 32 bits». 1
Si se resume en una tabla quién ve qué, queda así.
| Origen del acceso | Ruta indicada en el código | Ubicación física real de lectura/escritura |
|---|---|---|
| Proceso de 64 bits | HKLM\Software\MyApp |
HKLM\Software\MyApp |
| Proceso de 32 bits | HKLM\Software\MyApp |
HKLM\Software\Wow6432Node\MyApp |
Proceso de 32 bits + KEY_WOW64_64KEY (RegistryView.Registry64) |
HKLM\Software\MyApp |
HKLM\Software\MyApp |
Proceso de 64 bits + KEY_WOW64_32KEY (RegistryView.Registry32) |
HKLM\Software\MyApp |
HKLM\Software\Wow6432Node\MyApp |
| Proceso interactivo de 32 bits, permisos estándar, sin manifiesto (escritura) | HKLM\Software\MyApp |
HKCU\Software\Classes\VirtualStore\Machine\Software\Wow6432Node\MyApp (virtualizado tras la redirección de WOW64; véase el apartado 5) |
| regedit (proceso de 64 bits) | ─ |
Se muestra con la vista de 64 bits como referencia; Wow6432Node también se ve tal cual, como clave física |
La anécdota del principio es exactamente esta tabla. El valor que escribió el instalador de 32 bits se encuentra físicamente bajo Wow6432Node, mientras que la aplicación ya convertida a 64 bits lee el HKLM\Software puro. Como regedit ve ambas ubicaciones, el informe de campo «en regedit está» y el fenómeno «desde la aplicación no está» coexisten sin ninguna contradicción.
Aquí surge la tentación de escribir la ruta Wow6432Node directamente en el código para hacer cuadrar las cosas, pero es un antipatrón que la documentación oficial prohíbe de forma explícita. Se indica que la ubicación física de destino de la redirección es una reserva del sistema y puede cambiar. De hecho, en Windows 10 on ARM el destino de la redirección para las aplicaciones ARM de 32 bits es otra clave distinta, WowAA32Node. 12 Si necesita leer otra vista, utilice los mecanismos oficiales descritos en el apartado 4.
Como detalle adicional, WOW64 también corrige las cadenas REG_SZ/REG_EXPAND_SZ que una app de 32 bits escribe comenzando por %ProgramFiles%, reemplazándolas por %ProgramFiles(x86)% (solo cuando coincide también en mayúsculas y minúsculas). 1 Además, en la época de Vista/XP existía la «reflexión de registro» (registry reflection), que copiaba y sincronizaba claves entre las vistas de 32 y 64 bits, pero se eliminó en Windows 7 / Windows Server 2008 R2. Al leer artículos antiguos sobre el tema, tenga en cuenta esta diferencia de contexto. 1
3. Claves redirigidas y claves compartidas
No todas las claves se redirigen. Algunas comparten una única copia física entre ambas vistas. A continuación se extraen, de la lista oficial «Registry Keys Affected by WOW64», las claves más relevantes para el desarrollo de aplicaciones empresariales (columna de Windows 7 / Server 2008 R2 en adelante; por regla general, las subclaves heredan el comportamiento de su clave padre). 3
| Clave | Tratamiento desde Windows 7 |
|---|---|
HKLM\SOFTWARE |
Redirigida |
HKLM\SOFTWARE\Classes |
Compartida |
HKLM\SOFTWARE\Classes\CLSID |
Redirigida |
HKLM\SOFTWARE\Classes\Interface |
Redirigida |
HKLM\SOFTWARE\Classes\DirectShow / Media Type / MediaFoundation |
Redirigida |
HKLM\SOFTWARE\Clients |
Compartida |
HKLM\SOFTWARE\Microsoft\COM3 / EventSystem / OLE / RPC |
Compartida |
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths |
Compartida |
HKLM\SOFTWARE\Policies |
Compartida |
HKCU\SOFTWARE |
Compartida |
HKCU\SOFTWARE\Classes |
Compartida |
HKCU\SOFTWARE\Classes\CLSID / Interface |
Redirigida |
Lo llamativo es la estructura anidada. HKLM\SOFTWARE se redirige, pero Classes, justo debajo, vuelve a estar compartida, y más abajo todavía, CLSID e Interface vuelven a redirigirse. Un entendimiento superficial de «todo lo que está bajo Software va a Wow6432Node» no explica la diferencia de comportamiento entre la asociación de extensiones de archivo (justo bajo Classes, compartida) y el registro de clases COM (Classes\CLSID, redirigida). HKCU está básicamente compartida, así que, mientras la configuración por usuario se guarde en HKCU, prácticamente no aparecen problemas de bitness; esta es también una consecuencia práctica importante. 3
Además, indicadores como KEY_WOW64_64KEY no tienen ningún efecto sobre las claves compartidas, porque al existir una sola copia física, cambiar de vista carece de sentido. 2
4. Cómo leer explícitamente otra vista — la forma correcta con reg.exe, C# y C++
La forma más rápida de averiguar «en cuál de las dos vistas está el valor» son las opciones /reg:64 / /reg:32 de reg.exe, que acceden explícitamente a la vista de 64 bits y a la de 32 bits respectivamente. 5
:: Lee la vista de 64 bits (el HKLM\Software puro)
reg query "HKLM\SOFTWARE\KomuraSoft\DeviceLink" /v LicenseKey /reg:64
:: Lee la vista de 32 bits (físicamente bajo Wow6432Node)
reg query "HKLM\SOFTWARE\KomuraSoft\DeviceLink" /v LicenseKey /reg:32
Si al ejecutar estas dos líneas el valor solo aparece en una de ellas, queda confirmado que «la bitness del lado que escribió y la del lado que lee no coinciden». La clave está en cambiar únicamente la vista sobre la misma ruta lógica, en lugar de escribir a mano Wow6432Node en la ruta.
En C# (.NET) se pasa un RegistryView a RegistryKey.OpenBaseKey. Existen tres valores: Registry64 (256), Registry32 (512) y Default (0), y se pueden indicar en OpenBaseKey, OpenRemoteBaseKey o FromHandle. 4
using Microsoft.Win32;
// Lee la vista de 64 bits incluso desde un proceso de 32 bits
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
using (var key = baseKey.OpenSubKey(@"SOFTWARE\KomuraSoft\DeviceLink"))
{
var license = key?.GetValue("LicenseKey") as string;
}
// Lee la vista de 32 bits (lado Wow6432Node) desde un proceso de 64 bits
// ── útil, por ejemplo, para leer valores de un instalador de la época de 32 bits, como parte de una migración
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
using (var key = baseKey.OpenSubKey(@"SOFTWARE\KomuraSoft\DeviceLink"))
{
var legacy = key?.GetValue("LicenseKey") as string;
}
RegistryView.Default deja la vista a merced de la bitness del proceso. Como una aplicación .NET compilada como AnyCPU cambia entre 32 y 64 bits según el entorno de ejecución, si va a manejar datos comunes a nivel de máquina bajo HKLM, conviene indicar explícitamente en el código qué vista se va a leer; así se evita el incidente de que, al cambiar la configuración de compilación (activar o desactivar Prefer 32-bit, o migrar a 64 bits), la forma en que se ve el registro cambie de repente. Además, dado que solicitar Registry64 en un sistema operativo de 32 bits devuelve, según la especificación, la clave de la vista de 32 bits, el mismo código sigue funcionando de forma segura aunque todavía deba admitirse un sistema operativo de 32 bits. 4
En C++ (API de Win32), se indica KEY_WOW64_64KEY (0x0100) o KEY_WOW64_32KEY (0x0200) mediante OR en el samDesired de RegOpenKeyEx, RegCreateKeyEx o RegDeleteKeyEx. Especificar ambos a la vez provoca un fallo con ERROR_INVALID_PARAMETER. 2
HKEY hKey = nullptr;
// Abre la clave de la vista de 64 bits desde un proceso de 32 bits
LSTATUS st = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\KomuraSoft\\DeviceLink",
0,
KEY_READ | KEY_WOW64_64KEY, // Aquí se especifica la vista de forma explícita
&hKey);
if (st == ERROR_SUCCESS)
{
wchar_t buf[256]; DWORD cb = sizeof(buf); DWORD type = 0;
RegQueryValueExW(hKey, L"LicenseKey", nullptr, &type,
reinterpret_cast<LPBYTE>(buf), &cb);
RegCloseKey(hKey);
}
La documentación oficial señala dos advertencias. Una vez abierta otra vista con un indicador, hay que seguir especificando el mismo indicador en las operaciones sobre las subclaves (crear, eliminar, abrir). Mezclarlos produce un comportamiento inesperado. Además, si se quiere enumerar sin omisiones las claves de ambas vistas, es necesario enumerar en dos pasadas: una con el handle abierto con KEY_WOW64_64KEY y otra con el abierto con KEY_WOW64_32KEY. Tenga en cuenta también que RegDeleteKey (sin el sufijo Ex) no puede acceder a otra vista. 2
5. Virtualización de registro de UAC — cuando lo que se escribió en HKLM termina en VirtualStore
Otro mecanismo que suele confundirse con la redirección es la virtualización de registro de UAC. No es un asunto de bitness, sino de permisos: es una tecnología de compatibilidad introducida desde Vista para rescatar a las aplicaciones heredadas escritas dando por sentados privilegios de administrador. 6
Funciona así: cuando un proceso sin permiso de escritura intenta escribir un valor o crear una subclave bajo HKLM\Software, en lugar de fallar por acceso denegado, la escritura se traslada al almacén virtual de cada usuario, HKEY_USERS\<SID del usuario>_Classes\VirtualStore\Machine\Software (en regedit se ve bajo HKCU\Software\Classes\VirtualStore\Machine\Software). Además, en la lectura se devuelve una vista combinada entre el valor del almacén virtual y el del almacén global original, y cuando coinciden los nombres, prevalece el del almacén virtual. 6 Cabe señalar que, en un proceso de 32 bits sobre un sistema operativo de 64 bits, primero actúa la redirección de WOW64 del apartado 3, de modo que el destino real de una escritura en HKLM\Software\MyApp termina siendo VirtualStore\Machine\Software\Wow6432Node\MyApp. Al investigar el contenido de VirtualStore, verifique siempre tanto el lado Software puro como el lado Wow6432Node.
En otras palabras, desde el propio proceso que escribió, la lectura y la escritura parecen funcionar como si nada hubiera pasado. Este es el trasfondo real de fallos extraños que dependen del usuario, como «en la máquina de desarrollo (ejecutada como administrador) no hay problema, pero en el entorno de usuario estándar del cliente la configuración sale mal» o «funciona con la sesión de la persona A, pero con la de la persona B vuelve al valor inicial». El almacén virtual forma parte del perfil de usuario (NTUSER.DAT, entre otros archivos), por lo que su contenido varía de un usuario a otro (para la estructura del perfil, consulte «Introducción al perfil de usuario de Windows: AppData y NTUSER.DAT»).
Las condiciones bajo las que actúa la virtualización son limitadas y están documentadas explícitamente. 6
- Solo se aplica a operaciones de un proceso interactivo de 32 bits, bajo
HKLM\Software, sobre una clave que un administrador sí podría escribir - Quedan excluidos: los procesos de 64 bits, los procesos no interactivos como los servicios, las operaciones realizadas durante una suplantación (impersonation) de usuario, los controladores (drivers), y los procesos cuyo manifiesto declara
requestedExecutionLevel - Tampoco se aplica bajo
HKLM\Software\Classes,HKLM\Software\Microsoft\WindowsniHKLM\Software\Microsoft\Windows NT
En la práctica, lo que más importa es que «el comportamiento cambia según haya o no manifiesto». Como el enlazador de C++ de Visual Studio incrusta por defecto el fragmento de UAC asInvoker en el manifiesto 7, los ejecutables compilados con las herramientas actuales quedan excluidos de la virtualización desde el principio. Donde de verdad se encuentra la virtualización es en entornos que ejecutan sobre Windows de 64 bits ejecutables heredados sin manifiesto, hechos en VB6, en versiones antiguas de Delphi o en versiones antiguas de VC++. Y a la inversa, existe también una trampa típica de las migraciones: en cuanto a un ejecutable heredado se le «añade un manifiesto por si acaso» o se le «recompila a 64 bits», la virtualización deja de actuar, y entonces sí empieza a fallar de verdad por acceso denegado (o la escritura falla en silencio). Los tres valores de requestedExecutionLevel (asInvoker / highestAvailable / requireAdministrator) y los criterios de diseño de permisos se tratan en detalle en «Cuándo se necesitan realmente privilegios de administrador en Windows».
Cabe subrayar que la documentación oficial indica explícitamente que la virtualización es una tecnología de compatibilidad provisional (interim) y que existe la intención de eliminarla en una futura versión de Windows. Depender de este comportamiento en un desarrollo nuevo está totalmente fuera de lugar; el principio de diseño correcto es «la aplicación no escribe en zonas sensibles del sistema (HKLM); los datos van a un lugar por usuario o a un lugar común con las ACL adecuadas». 6 El criterio para decidir dónde guardar cada dato está organizado en «Cómo elegir dónde guardar los datos de una aplicación de Windows».
Existen también indicadores para controlar la virtualización clave por clave (REG_KEY_DONT_VIRTUALIZE / REG_KEY_DONT_SILENT_FAIL / REG_KEY_RECURSE_FLAG), que se pueden consultar y establecer con la opción flags de reg.exe. El ejemplo de consulta que aparece en la documentación oficial, junto con su salida, es el siguiente. 6
C:\>reg flags HKLM\Software\AppKey1 QUERY
HKEY_LOCAL_MACHINE\Software\AppKey1
REG_KEY_DONT_VIRTUALIZE: CLEAR
REG_KEY_DONT_SILENT_FAIL: CLEAR
REG_KEY_RECURSE_FLAG: CLEAR
The operation completed successfully.
Que las tres aparezcan como CLEAR significa «el indicador no está activado», es decir, que en esta clave la virtualización actúa según el comportamiento predeterminado. El efecto de activar (SET) cada indicador es el siguiente. 6
| Indicador | Efecto al activarlo |
|---|---|
REG_KEY_DONT_VIRTUALIZE |
Desactiva la virtualización de la escritura. La creación de claves o el establecimiento de valores sin permisos suficientes deja de trasladarse a VirtualStore y falla directamente |
REG_KEY_DONT_SILENT_FAIL |
Desactiva la virtualización de la apertura. Se deja de reintentar la apertura sin permisos suficientes con MAXIMUM_ALLOWED, y la operación falla |
REG_KEY_RECURSE_FLAG |
Propaga el indicador de virtualización de la clave padre a las hijas. Solo afecta a las subclaves creadas después del cambio; no se aplica a las subclaves ya existentes |
En otras palabras, si lo que se quiere es «detener la virtualización solo en esta clave y dejar a la vista la falta de permisos», la forma de usarlo es activar REG_KEY_DONT_VIRTUALIZE. Para activar el indicador se usa SET en lugar de QUERY, pero conviene verificar el orden exacto de las opciones con reg flags /?.
Para investigar un problema, las dos comprobaciones más rápidas son: en la pestaña «Detalles» del Administrador de tareas, hacer clic con el botón derecho sobre el encabezado de las columnas y añadir «Virtualización de UAC» desde «Seleccionar columnas» para ver el estado de virtualización por proceso, y revisar HKCU\Software\Classes\VirtualStore en busca de restos trasladados.
6. Daños reales en instaladores y registro de COM
Los dos ámbitos donde estos dos mecanismos se manifiestan con más frecuencia como daño real son los instaladores y el registro de COM.
El problema de bitness en los instaladores. La configuración que un instalador de 32 bits (un MSI de 32 bits o un ejecutable de instalación de 32 bits) escribe en HKLM\Software\NombreDeLaEmpresa acaba, físicamente, bajo Wow6432Node. Si se convierte a 64 bits el cuerpo de la aplicación pero se sigue reutilizando el instalador de 32 bits tal cual, se completa el cuadro de la anécdota inicial: «el instalador escribió, la aplicación no puede leer». El patrón inverso (instalador de 64 bits con aplicación de 32 bits) presenta el mismo problema. Como medida, conviene hacer que el instalador y el cuerpo de la aplicación coincidan en «qué vista se escribe y qué vista se lee», y, durante el período de transición de una migración a 64 bits, implementar con el RegistryView.Registry32 del apartado 4 una lectura de migración desde la ubicación anterior.
El problema de bitness en el registro de COM. Como muestra la tabla del apartado 3, HKLM\Software\Classes\CLSID (el lado HKLM de HKCR\CLSID) está sujeto a redirección. Es decir, el registro CLSID de un servidor COM de 32 bits queda en la vista de 32 bits, y el de 64 bits en la vista de 64 bits, y no se ven mutuamente. 3 Dado que un proceso de 64 bits no puede cargar de entrada un servidor COM in-process alojado en una DLL de 32 bits, esta separación es en sí misma razonable, pero en la práctica se manifiesta en la forma de «se registró con regsvr32, pero desde el cliente aparece 0x80040154 (clase no registrada)». El propio regsvr32 tiene una versión de 32 bits (en SysWOW64) y otra de 64 bits (en System32), y cuál de las dos se use determina en qué vista se escribe el registro. El panorama completo de las trampas que surgen de combinar el registro de COM con la bitness está reunido en «Trampas del registro y la bitness al desarrollar componentes COM/OCX/ActiveX», y la alternativa que evita por completo el registro en el registro de Windows se explica en «Qué es Reg-Free COM».
En el mundo de COM hay otro antecedente histórico. En la época de Vista/XP, CLSID y otras claves se trataban con «redirección + reflexión (sincronización entre ambas vistas)», pero en Windows 7 se eliminó la reflexión, y ahora la separación es puramente por vista. 3 Además, hay definidos varios enlaces simbólicos de compatibilidad, como HKLM\SOFTWARE\Wow6432Node\Classes → HKLM\SOFTWARE\Classes\Wow6432Node, pero son para rescatar aplicaciones existentes que ya codificaron Wow6432Node a fuego, y no algo que una aplicación nueva deba usar. 3
Cabe señalar que, incluso después de resolver la separación del registro, la propia carga de la DLL está sujeta a otras reglas de resolución de nombres. Para investigaciones del tipo «no se encuentra», consulte también «Cómo funciona la resolución de nombres de DLL en Windows: orden de búsqueda y SxS».
7. Solución de problemas — ver con Procmon qué se leyó realmente
Aunque se conozca el mecanismo, para determinar, ante un fallo concreto, «qué clave física llegó a leer realmente este proceso», hace falta observar. Aquí la herramienta más eficaz es Process Monitor (Procmon), de Sysinternals.
El procedimiento es sencillo.
- Inicie Procmon y añada el filtro
Process Name is <app_objetivo>.exe - Restrinja la vista solo a operaciones de registro desde la barra de herramientas (también sirve el filtro
Operation begins with Reg) - Reproduzca la operación problemática de la aplicación y observe las filas de
RegOpenKey/RegQueryValue/RegSetValue
El punto clave es que la columna Path de Procmon muestra la ruta física ya resuelta tras la redirección. Aunque una app de 32 bits crea estar abriendo HKLM\Software\MyApp, en Procmon aparece como HKLM\SOFTWARE\WOW6432Node\MyApp. Si ahí se alinean varios NAME NOT FOUND, salta a la vista «qué clave falta en qué vista»; y si la escritura fluye hacia HKCU\Software\Classes\VirtualStore\..., también se puede observar la activación de la virtualización. Para investigar un 0x80040154 de COM, se puede llegar a averiguar en qué vista falló exactamente la apertura de CLSID\{...}. Para el diseño de filtros de Procmon y los detalles de cómo interpretarlo, consulte «Guía práctica de Process Monitor (ProcMon)».
8. Reglas prácticas (tabla de decisión)
| Situación | Qué hacer | Motivo / observación |
|---|---|---|
| «Se ve en regedit pero no desde la aplicación» | Comparar ambas vistas con reg query ... /reg:64 y /reg:32 |
Determinar primero en qué vista está el valor5 |
| Dos procesos propios, uno de 32 y otro de 64 bits, leen la misma configuración de HKLM | Fijar la vista en el lado que escribe (por ejemplo, la de 64 bits) y hacer que todos los lectores especifiquen la misma vista | Unificar con RegistryView.Registry64 / KEY_WOW64_64KEY42 |
Tentación de escribir Wow6432Node directamente en el código |
No hacerlo. Sustituirlo por la API de especificación de vista | La ubicación física es reservada por el sistema; en ARM es WowAA32Node12 |
| Dónde guardar la configuración por usuario | En HKCU (o en AppData) | HKCU es una clave compartida, sin problemas de bitness ni de permisos3 |
| La configuración de una app heredada de 32 bits «varía según el usuario» | Revisar HKCU\Software\Classes\VirtualStore |
Patrón típico: valores trasladados por virtualización acumulados por usuario6 |
| Añadir manifiesto o migrar a 64 bits un ejecutable heredado | Hacerlo solo después de identificar todos los puntos de escritura en HKLM | La virtualización se desactiva y las escrituras que hasta entonces «funcionaban» empiezan a fallar67 |
| 0x80040154 en COM | Verificar la bitness del cliente y del servidor, y confirmar el registro con el regsvr32 o la vista correspondiente | El registro CLSID está separado por vista3 |
| No se puede determinar qué se leyó | Observar con Procmon la ruta física y el resultado (NAME NOT FOUND, etc.) | Dejar de suponer y mirar los hechos es lo más rápido |
9. Resumen
- El registro de un Windows de 64 bits tiene dos vistas, y
HKLM\Softwarede un proceso de 32 bits se redirige de forma transparente a Wow6432Node. Es el primer sospechoso de «el valor que debería estar y no está». - La redirección no afecta a todas las claves. Tenga presente la estructura anidada:
Classesestá compartida,CLSID/Interfacepor debajo vuelven a estar redirigidas, y HKCU está casi por completo compartida. - Está prohibido escribir Wow6432Node a fuego. Indique la vista explícitamente con
/reg:64/reg:32de reg.exe,RegistryViewde .NET, oKEY_WOW64_64KEY/KEY_WOW64_32KEYde Win32. - La virtualización de registro de UAC traslada silenciosamente a VirtualStore las escrituras en HKLM sin permisos suficientes de un proceso interactivo de 32 bits sin manifiesto. Es una tecnología provisional de rescate para aplicaciones heredadas, y una app nueva no debe depender de ella.
- El instalador y la aplicación, y el servidor COM y el cliente, deben coincidir en «qué vista usan». En una migración a 64 bits, incluya en el diseño una lectura de migración desde la vista anterior.
- Ante la duda, observe la ruta física con Procmon. Observar es más rápido y fiable que suponer.
Artículos relacionados
- Trampas del registro y la bitness al desarrollar componentes COM/OCX/ActiveX
- Qué es Reg-Free COM
- Cuándo se necesitan realmente privilegios de administrador en Windows
- Introducción al perfil de usuario de Windows: AppData y NTUSER.DAT
- Cómo elegir dónde guardar los datos de una aplicación de Windows
- Guía práctica de Process Monitor (ProcMon)
- Cómo funciona la resolución de nombres de DLL en Windows: orden de búsqueda y SxS
Áreas de consultoría relacionadas
KomuraSoft LLC se ocupa de investigar incidencias como «no se puede leer un valor que debería haberse escrito en el registro» o «no se encuentra el registro de COM», del diseño de la migración a 64 bits de aplicaciones de 32 bits y de activos de componentes COM, y del desarrollo por encargo de aplicaciones empresariales para Windows, incluido software de integración con equipos.
- Investigación de incidencias y análisis de causa raíz
- Migración y aprovechamiento de activos existentes
- Desarrollo de componentes COM
- Contacto
Referencias
-
Microsoft Learn, Registry Redirector. Sobre cómo el redirector de registro ofrece vistas lógicas distintas a las aplicaciones de 32 y 64 bits de forma transparente para la aplicación, cómo HKEY_LOCAL_MACHINE\Software se redirige a HKEY_LOCAL_MACHINE\Software\Wow6432Node, que la ubicación física es una reserva del sistema y las aplicaciones no deben acceder a ella directamente, que en Windows 10 on ARM las claves ARM de 32 bits se asignan a WowAA32Node, la sustitución de la cadena %ProgramFiles%, y la eliminación de la reflexión en Windows 7 / Windows Server 2008 R2. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, Accessing an Alternate Registry View. Sobre el significado de KEY_WOW64_64KEY (0x0100) y KEY_WOW64_32KEY (0x0200), que se indican en el samDesired de RegCreateKeyEx, RegDeleteKeyEx y RegOpenKeyEx, que especificar ambos indicadores a la vez produce ERROR_INVALID_PARAMETER, que no tienen efecto sobre las claves compartidas, que debe seguir usándose el mismo indicador en las operaciones sobre subclaves, que la enumeración completa de claves debe hacerse en dos pasadas, y que Wow6432Node/WowAA32Node son claves reservadas. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, Registry Keys Affected by WOW64. Sobre la lista de claves redirigidas y compartidas (desde Windows 7, HKLM\SOFTWARE está redirigida, HKLM\SOFTWARE\Classes está compartida, Classes\CLSID, Interface, DirectShow, etc. están redirigidas, y Clients, COM3, OLE, RPC, App Paths, Policies, HKCU\SOFTWARE, etc. están compartidas), que las subclaves heredan el comportamiento de la clave padre, que HKCR es una vista combinada de Classes de HKLM y de HKCU, y que los enlaces simbólicos de compatibilidad que incluyen Wow6432Node son para rescatar aplicaciones existentes y no deben usarse en aplicaciones nuevas. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, RegistryView Enum (Microsoft.Win32). Sobre los valores Default (0), Registry64 (256) y Registry32 (512) de la enumeración RegistryView, que la vista se puede indicar en OpenBaseKey, OpenRemoteBaseKey y FromHandle, y que al solicitar la vista de 64 bits en un sistema operativo de 32 bits se devuelve la clave de la vista de 32 bits. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, reg query. Sobre las opciones /reg:32 y /reg:64 del comando reg query, que acceden a la clave usando la vista de registro de 32 y de 64 bits respectivamente. ↩ ↩2 ↩3
-
Microsoft Learn, Registry Virtualization. Sobre cómo la escritura en HKLM\Software se redirige a HKEY_USERS<User SID>_Classes\VirtualStore\Machine\Software, que en la lectura se devuelve una vista combinada con prioridad para el almacén virtual, que la virtualización se limita a procesos interactivos de 32 bits, bajo HKLM\Software, sobre claves que un administrador podría escribir, que queda desactivada en procesos de 64 bits, servicios, operaciones de suplantación, procesos con requestedExecutionLevel declarado y subclaves como Classes, que es una tecnología de compatibilidad provisional con intención de eliminarse en el futuro y que una aplicación no debe depender de ella, y sobre el control mediante REG_KEY_DONT_VIRTUALIZE y similares con reg flags. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, Application manifests. Sobre el significado de los valores asInvoker, requireAdministrator y highestAvailable del elemento requestedExecutionLevel, que declarar el nodo requestedExecutionLevel desactiva la virtualización de archivos y de registro, que ese nodo debe omitirse si se desea aprovechar la virtualización por compatibilidad con versiones anteriores, y que el enlazador de Visual C++ incrusta por defecto el fragmento de UAC asInvoker en el manifiesto. ↩ ↩2 ↩3
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Cómo elegir el destino de almacenamiento de datos en una app de Windows ── Tabla de decisión: SQLite / JSON / Registro / Access
Dónde y con qué guardar los datos de una app de escritorio Windows: uso de AppData/ProgramData, ventajas y trampas de SQLite, JSON, Regis...
Buenas prácticas de multithreading en la práctica — Edición .NET: qué decidir antes de aumentar los hilos
Reglas de diseño en .NET/C# para evitar fallos y bloqueos intermitentes con hilos: usar Task en lugar de hilos propios, reducir el estado...
Usar WMI/CIM desde C# y PowerShell ── Guía práctica de obtención de información de hardware, monitorización de procesos y consultas remotas
WMI/CIM es la solución estándar para leer el número de serie, monitorizar el disco y detectar procesos. Cmdlets CIM, migración desde Get-...
¿Hasta cuándo se puede usar MSMQ? — La decisión de migración de una cola legacy que «ni siquiera está en desuso»
MSMQ no figura en la lista oficial de funciones en desuso, pero System.Messaging solo existe en .NET Framework y bloquea la migración a ....
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,...
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.
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.
Preguntas frecuentes
Preguntas habituales en las consultas sobre el tema del artículo.
- ¿Por qué un valor visible en regedit no existe cuando la aplicación intenta leerlo?
- La causa típica es que la aplicación y regedit están consultando vistas de registro distintas. En Windows de 64 bits, regedit se ejecuta como proceso de 64 bits y, tomando como referencia la vista de 64 bits, muestra también Wow6432Node (la ubicación física de la vista de 32 bits). En cambio, cuando una aplicación de 32 bits abre HKLM\Software, el redirector de registro de WOW64 la desvía hacia Wow6432Node, de modo que un valor que solo existe en el lado de la vista de 64 bits aparece como «inexistente». Lo primero que conviene comprobar es si la ruta del valor que se ve en regedit incluye Wow6432Node, y comparar ambas vistas con reg query usando /reg:64 y /reg:32 permite aislar el problema con rapidez.
- ¿Está bien acceder directamente desde el código a la ruta de Wow6432Node?
- Debe evitarse. La documentación oficial de Microsoft indica explícitamente que la ubicación física de destino de la redirección es una zona reservada del sistema, susceptible de cambiar en el futuro, por lo que las aplicaciones no deberían acceder a ella directamente. De hecho, en Windows 10 on ARM las aplicaciones ARM de 32 bits usan una ubicación física distinta llamada WowAA32Node, así que dar por sentado Wow6432Node se rompe en entornos ARM. Si necesita acceder a otra vista, utilice los mecanismos oficiales: los indicadores KEY_WOW64_64KEY/KEY_WOW64_32KEY o, en .NET, RegistryView.
- ¿Por qué un valor que debería haberse escrito en HKLM aparece en el VirtualStore de HKCU?
- Es el resultado de la virtualización de registro de UAC. Cuando un proceso interactivo de 32 bits sin permisos de escritura, y cuyo manifiesto no declara requestedExecutionLevel, intenta escribir bajo HKLM\Software, en lugar de fallar la escritura se traslada al almacén virtual de cada usuario (HKEY_USERS\<SID>_Classes\VirtualStore\Machine\Software, visible en regedit bajo HKCU\Software\Classes\VirtualStore). Cuando ese mismo proceso vuelve a leer el valor, ve una vista combinada del almacén virtual y de la ubicación original, por lo que aparentemente todo funciona, pero un proceso de 64 bits o un servicio no ven ese valor, lo que produce el extraño fallo de «la configuración cambia según el usuario». La virtualización es una tecnología de rescate provisional para aplicaciones heredadas, así que una aplicación nueva no debe depender de ella.
- ¿Cómo se especifica en C# la bitness (vista de 32 o 64 bits) del registro?
- Se pasa un valor de RegistryView a RegistryKey.OpenBaseKey. Con RegistryView.Registry64 se puede leer y escribir la vista de 64 bits incluso desde un proceso de 32 bits, y con RegistryView.Registry32 se puede leer y escribir la vista de 32 bits (el lado de Wow6432Node) incluso desde un proceso de 64 bits. RegistryView.Default deja la vista a merced de la bitness del proceso, así que en configuraciones donde la bitness cambia según el entorno de ejecución, como una compilación AnyCPU, es más seguro indicar explícitamente qué vista se va a leer. Además, si se solicita Registry64 en un sistema operativo de 32 bits, la especificación indica que se devuelve la vista de 32 bits, de modo que el mismo código sigue funcionando aunque todavía deba admitir sistemas operativos de 32 bits.
- ¿Cómo se desactiva la virtualización de registro, o cómo se comprueba si está actuando?
- Del lado de la aplicación, basta con declarar requestedExecutionLevel en el manifiesto (incluso con el valor asInvoker) para que la virtualización de archivos y de registro de ese proceso quede desactivada. Del lado del administrador, el comando reg flags permite consultar y establecer, por clave, el indicador REG_KEY_DONT_VIRTUALIZE. Para investigar una aplicación que ya está en ejecución, el camino más rápido es consultar la columna «Virtualización de UAC» del Administrador de tareas para ver el estado de virtualización por proceso, y revisar si se han acumulado valores trasladados bajo HKCU\Software\Classes\VirtualStore. Como solución permanente, se recomienda rediseñar la aplicación para que directamente no escriba en HKLM (la configuración por usuario debe ir a HKCU o a AppData).
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.