I have been working on x64 hardware for quite some time, except I was running a 32-bit OS because I did not want to deal with compatibility issues. Now that x64 has come into mainstream adoption, I am exposed to more instances of x64 editions of Windows on real and fake hardware. But 32-bit applications are still around and will be for the foreseeable future. One of the things I have encountered when working with x64 systems is accurately reading the registry, due to the need for 32-bit compatibility mode (a.k.a. WoW64).
A 32-bit application is provided a special view on the registry for compatibility reasons. The following table illustrates the logical 32-bit mapping to the physical 64-bit registry nodes.
| 32-bit logical registry node | 64-but physical registry node |
| HKEY_CLASSES_ROOT | HKEY_CLASSES_ROOT\Wow6432Node |
| HKEY_CURRENT_USER\Software\Classes | HKEY_CURRENT_USER\Software\Classes\Wow6432Node |
| HKEY_LOCAL_MACHINE\SOFTWARE | HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node |
When enumerating the registry from a 64-bit application and you care if a 32-bit application has similar values of interested, you must query both the 64-bit and 32-bit registry locations. An example of this is the script I wrote to write out all the applications installed on a machine:
# (c) 2008-2009 D. P. Bullington <dpbullington@hotmail.com>
# appwiz.ps1: gets a list of installed application from the registry similar to appwiz.cpl.
# USAGE: powershell -command ".\appwiz.ps1"
# Supports x86 and Wow64 and user private installs.
$paths =
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
"HKCU:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
$ht = @()
foreach ($path in $paths)
{
if(!(test-path -path $path -PathType Container)) { continue }
$reg = Get-ItemProperty ($path + "\*")
foreach ($subreg in $reg)
{
$dispname = $subreg.DisplayName
$dispver = $subreg.DisplayVersion
$value = ""
if ($dispname -eq $null)
{$value = "[" + $subreg.PSChildName + "]"}
else
{$value = $dispname + " (" + $dispver + ")"}
$ht += @($value)
}
}
[System.Array]::Sort($ht)
$vz = ""
foreach ($v in $ht)
{$vz = $vz + $v + "`r`n"}
[System.IO.File]::WriteAllText([System.Environment]::machineName + ".appwiz.output.txt", $vz)
As you can see, I must query both 32-bit and 64-bit application specific registry nodes in order to compile the correct list of installed applications. Note, that I do query for a 32-bit current user although this is not currently segregated like the 32-bit local machine node.
All the magic of WoW64 takes place via a registry redirector that "isolates 32-bit and 64-bit applications by providing separate logical views of key portions of the registry on WOW64. The registry redirector intercepts 32-bit registry calls to each logical registry view and maps them to the corresponding physical registry location. The redirection process is transparent to the application." [MSDN]
Moral of the story: we aware of subtleties on x64 when using 32-bit applications.
0 comments:
Post a Comment