没有Reg.exe的C#中的备份注册表项

时间:2013-02-01 15:21:27

标签: c# pinvoke

我需要在C#中备份一个注册表项。我一直在尝试P / Invoke RegSaveKey无济于事。由于无法关闭的组策略设置,我无法使用“Reg.exe”备份注册表。

以下是所有代码:

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);

2 个答案:

答案 0 :(得分:2)

您似乎没有检查RegOpenKeyEx或RegSaveKey的返回值是否有错误。我怀疑你得到的返回值为ERROR_PRIVILEGE_NOT_HELD。 Registry函数不使用SetLastError,它们直接返回它。与几乎每个Win32 API调用一样,必须检查返回值

无论您的ACL访问级别如何,RegSaveKey都需要启用SE_BACKUP_NAME权限。因此,您需要在调用RegSaveKey之前添加代码以启用此权限,然后在调用完成后将其禁用。

这是另一个question,其中包含更多信息,我确信还有其他信息。

答案 1 :(得分:1)

首先,我想评论一下,你的问题遗漏了一些非常重要的细节。也就是说,您实际上并未提供有关代码失败的任何信息。你所说的只是:

  

我一直试图P / Invoke RegSaveKey无济于事。

像这样的问题都与细节有关。我们需要查看精确而详细的错误诊断。请记住,我们无法看到您的屏幕。

您需要更加关注API调用的返回值。您正在检查RegOpenKeyEx的返回值是否为零,但这就是全部。您需要捕获并检查RegOpenKeyEx返回的值。这是一个错误代码。如果错误代码不等于零,您可以抛出Win32Exception

int err = RegOpenKeyEx(...);
if (err != 0)
    throw new Win32Exception(err);

将代码更改为抛出Win32Exception,并且在发生错误时至少会获得一些信息性文本。因此,如果RegOpenKeyEx失败,您至少会找出原因。

您根本没有检查其他API调用。给他们同样的待遇。

您拨打RegOpenKeyEx的失败模式非常少。我可以编写的唯一可信的解释是注册表项不存在。我希望你已经检查过了。但要注意registry redirector。如果您的进程是在64位操作系统上运行的32位进程,则重定向器将带您进入注册表的WOW6432Node部分,即32位视图。也许你所说的“无济于事”是将信息保存到文件中,但这是错误的信息。这与注册表重定向器让您感到困惑是一致的。

如果这是咬你的,那么在致电KEY_WOW64_64KEY时请加上RegOpenKeyEx标志。或者定位x64。

使用RegistryKey打开密钥要容易得多。我知道你不能轻易打电话给RegSaveKey所以你仍然需要调用它。但是RegistryKey会公开Handle属性,您可以传递给RegSaveKey。这有一个附带条件。如果您确实需要使用KEY_WOW64_64KEY标志,则需要.net 4和RegistryView

至于RegSaveKey,我会按照斯蒂芬在答案中提供的信息。