Reputation: 1104
I need to backup a registry key in C#. I've been trying to P/Invoke RegSaveKey to no avail. I can't use "Reg.exe" to backup the registry due to Group Policy settings which can't be turned off.
Here's all of the code:
private static UIntPtr GetKey(string registryPath)
{
UIntPtr hKey = UIntPtr.Zero;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryPath, 0, KEY_READ, out hKey) != 0)
{
throw new Exception("Error getting key!");
}
return hKey;
}
private static void ExportRegistry(string registryPath)
{
UIntPtr key = UIntPtr.Zero;
try
{
key = GetKey(registryPath);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
if (key == UIntPtr.Zero)
{
Console.WriteLine("Not key to export!");
return;
}
try
{
RegSaveKey(key, "c:\\temp\\test.reg", IntPtr.Zero);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (key != UIntPtr.Zero)
{
RegCloseKey(key);
}
}
private static int KEY_READ = 131097;
private static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegCloseKey(UIntPtr hKey);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint RegSaveKey(UIntPtr hKey, string lpFile, IntPtr lpSecurityAttributes);
Upvotes: 0
Views: 3538
Reputation: 613451
First of all I would like to comment that your question misses some very important details. Namely that you do not actually give any information as to how your code is failing. All you say is:
I've been trying to P/Invoke RegSaveKey to no avail.
Questions like this one are all about the details. We need to see precise and detailed error diagnostics. Remember that we cannot see your screen.
You need to pay more attention to the return values from API calls. You are checking the return value of RegOpenKeyEx
against zero, but that's all. You need to capture and inspect the value returned by RegOpenKeyEx
. That's an error code. You can throw a Win32Exception
if the error code is not equal to zero.
int err = RegOpenKeyEx(...);
if (err != 0)
throw new Win32Exception(err);
Change the code to throw Win32Exception
and you will at least get some informative text when the error occurs. So, if RegOpenKeyEx
is failing, you will at least find out why.
And you aren't checking the other API calls at all. Give them the same treatment.
There are really very few failure modes for your call to RegOpenKeyEx
. The only plausible explanation that I can concoct is that the registry key does not exist. I expect that you already checked that. But watch out for the registry redirector. If your process is a 32 bit process running on 64 bit OS, then the redirector will take you to the WOW6432Node
section of the registry, the 32 bit view. Perhaps what you mean by "to no avail" is that information is saved to the file, but it's the wrong information. That would be consistent with the registry redirector confusing you.
If that's what is biting you then include the KEY_WOW64_64KEY
flag when calling RegOpenKeyEx
. Or target x64.
It would be a lot easier to use RegistryKey
to open the key. I understand that you can't readily call RegSaveKey
so you still need to p/invoke that. But RegistryKey
exposes a Handle
property that you can pass to RegSaveKey
. There's one proviso to this. If you do need to use the KEY_WOW64_64KEY
flag then that requires the .net 4 and RegistryView
.
As for RegSaveKey
, I defer to the information given by Stephen in his answer.
Upvotes: 1
Reputation: 9645
You don't appear to be checking the return value of either RegOpenKeyEx or RegSaveKey for errors. I suspect that you are getting a return value of ERROR_PRIVILEGE_NOT_HELD. The Registry functions do not use SetLastError they return it directly. And as with virtually every Win32 API call the return value must be checked.
RegSaveKey requires the SE_BACKUP_NAME privilege to be enabled regardless of your ACL access level. So you'll need to add code to enable this privilege before the call to RegSaveKey and then disable it after the call is complete.
Here's another question with more info and I'm sure there are others.
Upvotes: 2