I am clueless about a recent issue that I encountered while making an MSI installer for Windows XP 64 bit platform.
In the Launch condition of the installer I am trying to read from registry, but the installer is not fetching the correct value. I tried checking for a different Value name, to confirm that its not just one particular Value name, and found it's behaving in the same manner.
I tried to print the fetched registry value data in the error message and realized that in some cases it gets no value at all and in other cases, it fails to get any number that is a part of the complete value data.
For example if try reading the data for:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
Value Name : InstallRoot
Value Data: C:\Windows\Microsoft.NET\Framework64\
The data that installer fetched is: C:\Windows\Microsoft.NET\Framework\. And in some other instances it gets an empty string.
Registry searches use the 32-bit registry hive by default and the 64-bit hive only if msidbLocatorType64bit flag is set.
So the solution is to use 2 searches with the same property:
one for the 32-bit hive
one for the 64-bit hive (with msidbLocatorType64bit flag)
Please note that Visual Studio setup projects do not support this. Other setup authoring tools do.
Related
Can I set up a 64-bit registry key to refer to a 32-bit program files path using WiX?
I'm writing a plugin for another piece of software. I want my plugin dll to go in C:\Program Files (x86)\MyPlugin\MyPlugin.dll not in C:\Program Files\MyPlugin\MyPlugin.dll because the dll is 32-bit, not 64-bit.
However, I need the registry key to go in HKLM/Software/Company/Product/Etc.... not in HKLM/Wow6432Node/Software/Company/Product/Etc.... because the process that actually reads the registry key is 64-bit. That 64-bit process reads the registry and launches a 32-bit process to sandbox the dll.
Is there any way to do this? I've tried using different components with different Win64 attribute values, and even putting them in separate component groups. However, I keep getting these build errors (not warnings):
ICE80: This 64BitComponent RegistryComponent uses 32BitDirectory INSTALLFOLDER
A somewhat poor solution, but you could just a custom action to add registry entries, if you don't mind them sticking around after an uninstall.
If you write a custom action in C# you can just do something like this:
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
// do it
}
If you support 32-bit and 64-bit machines you need two separate MSI setups:
http://blogs.msdn.com/b/heaths/archive/2008/01/15/different-packages-are-required-for-different-processor-architectures.aspx
So your 32-bit install creates any COM entries for any 32-bit Clients and the 64-bit setup has 32-bit and 64-bit components that write to the registry.
http://msdn.microsoft.com/en-us/library/aa367451(v=vs.85).aspx
A rather easy solution to only have one installer version for 32 and 64 bit is to export a .reg file with the keys you want to add (from regedit) and then run a custom action during install, ie:
<CustomAction Id='Add_Registry_Keys' Execute='deferred' Directory='DriverDir' Impersonate='no' ExeCommand='regedit.exe /s "[DriverDir]default.reg' Return='ignore' />
You can suppress ICE errors also, not just warnings. This means you can use Win64 attributes in your x86 msi.
The setting to ignore ICE validations is found in the Project Properties under the Tool Settings tab.
It might not be recommended, but if it works its still better than the alternative of a custom action.
Forgive me if the title is not so accurate.
I have met some problem when I am doing something related to COM server and registry redirection and not quite sure is my understanding is correct or not. Hoping anyone could share some light on it. Thanks in advance.
Basically a COM server has been registered in the registry before anyone can use its service. On a 64bit Windows OS, there could be 2 possible views in the registry table, one is for default and the other for the WOW64 view. For example, first registry key is: COMPUTER\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID{GUID}\LocalServer32 and the other is: COMPUTER\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID{GUID}\LocalServer32.
And depends on the process bitness (64bit vs. 32bit) that either one can be read by default, and also we can use KEY_WOW64_64KEY or KEY_WOW64_32KEY (as: http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx) to access the other alternative registry key.
What I need is that, I want to get the LocalServer32 executable file by reading the registry key and this can work. The problem is that, for the executable file path I read back, do I need to do the file path translation (in order to get the correct value) depending on which view I get the value from? For example, if the file path is got from COMPUTER\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID{GUID}\LocalServer32 and the file path is: C:\Windows\System32\abc.exe, do I need to translate the path to: C:\Windows\SysWow64\abc.exe? Or do I need to translate C:\Program Files\abc.exe to C:\Program Files(x86).exe?
Another question is that, if, for some registry key for COM, the values set in the two Views are different (for example, one has C:\Program Files\abc.exe and the other has C:\Program Files(x86)\abc.exe), then when the COM server is started, how could svchost.exe know which one to start, C:\Program Files\abc.exe or C:\Program Files(x86)\abc.exe? Does anyone know the logic for svchost.exe to determine this? Use the first one if it exists otherwise use the second one?
Thanks a lot.
A 64-bit version of Windows already has all the features in place to make it unnecessary for you to take care of it yourself. You just need to keep the rules in mind when you troubleshoot problems.
First is the registry redirector, it ensures that a 32-bit client program cannot accidentally read keys that contain configuration information that's only appropriate for 64-bit programs. You already know it, most of the HKLM\Software registry accesses are redirected to HKLM\Software\Wow6432Node. This redirection is already in place when the COM server is registered, a 32-bit installer is automatically redirected to write the keys to Wow6432Node instead. The installer is completely unaware that Wow6432Node even exists. Everything falls together automatically, the installer is redirected and the COM server client is redirected as well. All that you care about is knowing where to look to verify that the install was done properly, you do have to look at HKLM\Software\Wow6432Node\Classes\CLSID with Regedit.exe to find the keys back.
File redirection works much the same way, any access to c:\windows\system32 is redirected to c:\windows\syswow64, from c:\program files to c:\program files (x86). And very similarly, a 32-bit installer doesn't have to know beans about this, it can simply use the legacy 32-bit path names. Same for any 32-bit client program, it will be redirected the same way. All that you care about is knowing where to look for a file to verify the installer.
This can only go wrong if bitness is mixed, a 64-bit program reading registry keys or files installed by a 32-bit program. Or the other way around. Like it does with your troubleshooting tools, like Explorer, Regedit and SysInternals' Process Monitor. In general something that should be strongly avoided in COM, most servers are in-process servers and running 32-bit code in a 64-bit process is not possible. The biggest reason that the registry and file redirectors exist in the first place.
I used RegCreateKeyEx from a win32 application(VisualStudio 2008) in 64 bit windows(Project built with target x64). It was able to create a registry entry. Now I have a dll file (Project built with target x64) which too wanna create registry entry but my dll is returning error code 5(Yeah! its a sign of access denied). My samDesired flag have KEY_ALL_Access + In linker->manifestfile->run as administrator chosen which still fails with error code 5. Whereas it works perfectly in 32bit windows(Project built with target x86). Am i missing something?
NOTE: I'm trying to create an entry at HKEY_LOCAL_MACHINE.
You can't create a registry key in HKEY_LOCAL_MACHINE because this isn't a hive. You need to put your key in HKEY_LOCAL_MACHINE\Software or (less probably) one of the other hives.
I don't know why this appeared to work when you were running 32-bit code in WOW64, perhaps this is a side-effect of the way the 32-bit view of the registry is presented.
Windows 7 is caching some of the COM class information. Older OSs didn't do this. After the OS looks up theHKCU\Software\Classes\CLSID\{GUID}\LocalServer32 value, it caches the value, and doesn't look it up again.
When we update our software, we place the new updates in a different directory, and then update the HKCU\Software\Classes\CLSID\{GUID}\LocalServer32 value to reflect the new path. The next time the software runs, it will use the latest files if running under older Windows OSs. However, on Windows 7, it will continue to use the older file, until the OS is rebooted.
I ran process monitor, and discovered that under Windows 7, it never reads the registry key again, after the first read. On older OSs, it reads that key every time.
My question is: Is there any way to force Windows 7 to re-read the LocalServer32 information from the HKCU hive each time a new out of proc COM object is created?
I have only been able to solve this problem by...
1: Stopping the Process
2: explicitly unregistering using regsvr32 the library ( or exename /unregserver)
3: Registering the new component
4: Starting the process back up.
I would suspect that it is the Un Reg part that is failing for you. If you are just changing the registry key directly then you should call RegSvr32 /u instead.
Also make sure the new directory location is the current directory when you call RegSvr32.
Note that I have always stopped the process and then unregistered, this is probably a significant detail.
As this is a top result in Google for this narrow-ish problem, I thought it would be valuable to add my troubleshooting outcome for this problem.
I found this response on SO: C# : How to change windows registry and take effect immediately
And linked solution from that answer: Registry Watcher C#
Both of which seem viable options for managing changed keys without forcing a reboot. For us (like the OP) this was when installing updates. For us (possibly unlike the OP) this is infrequent and we decided the effort to implement and test a fix as described was outweighed by the simple solution of requiring a reboot: a process Windows users have come to expect with installing software anyway.
My boss just got Windows 7 and he tried running one of our installers which runs perfectly fine under XP. On Windows 7, the installer runs without giving any errors. However, it does not create registry keys under HKEY_LOCAL_MACHINE\SOFTWARE{Company}{product}. These keys get created correctly under XP.
Has anyone encountered this issue? I suspect it is a rights/security issue but I'm not sure and I don't have Windows 7 to experiment with.
EDIT
The computer in question is a 64-bit machine running 64-bit Windows. It turns out Windows 7 redirects 32-bit applications to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node{Company}{product}. The problem is my application code tries to access the registry using a hardcoded value like this:
var t = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\..., "ValueName", DefaultValue);
So, my new question is how do I access the registry such that the Windows 9 registry redirection will just work?
If you're using .NET 4, you can specifically request that your 32-bit (or 64-bit) process access the 64-bit view of the registry using the RegistryKey.OpenBaseKey method.
Cf. http://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.openbasekey.aspx
Here's an example that reads a value from the 64-bit view of the registry, even if it runs as part of a 32-bit process:
var hklm64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var key = hklm.OpenSubKey(#"SOFTWARE\AcmeSoft\AnvilMaker 1.0");
var value = (string) key.GetValue("Blacksmith Name");
The RegistryKey.OpenBaseKey method also allows you to explicitly open a 32-bit view of the registry. This is useful if you're trying to go the other way around and access the 32-bit view of the registry from a 64-bit process and you don't want to explicitly add "Wow6432Node" to the registry path.
For example, today I needed to delete a sub-key tree in both the 32-bit and 64-bit views of the registry. Doing this in .NET 4 with a single registry path was easy:
foreach(var view in new[] {RegistryView.Registry32, RegistryView.Registry64})
{
var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
hklm.DeleteSubKeyTree(#"SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant", throwOnMissingSubKey: false);
}
On a 64-bit version of windows, the above code will remove the following sub-key trees from the registry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\AcmeSoft\SomeKeyWeNoLongerWant
-Adam
After more digging I came across this link which describes the registry access rules for .NET applications. My program had initially been targeted for "AnyCpu" which causes the app to target the 64-bit registry even though Windows installed it under the Wow6432Node. By setting the target to "x86" my program "magically" started accessing the registry under the Wow6432Node. Go figure!
In the C Windows API this is done by setting the samDesired parameter in the RegOpenKeyEx call to KEY_WOW64_64KEY. This means that the lookup of the registry value will map onto the regular 64-bit entry, rather than the WOW32Node one. I can't see how you would achieve this in .Net though as the Registry class doesn't appear to support these operations, but maybe it's provided through a newer class?
Registry Reflection
Code Sample